summaryrefslogtreecommitdiffstats
path: root/contrib/tar
diff options
context:
space:
mode:
authorsobomax <sobomax@FreeBSD.org>2002-06-04 10:37:47 +0000
committersobomax <sobomax@FreeBSD.org>2002-06-04 10:37:47 +0000
commit0f70d6636c8f836f50cc56b9ea9b8dc51cd12dbe (patch)
tree8e3e6da9ce2dfb3d403e8ed0fab9168ce589ca80 /contrib/tar
downloadFreeBSD-src-0f70d6636c8f836f50cc56b9ea9b8dc51cd12dbe.zip
FreeBSD-src-0f70d6636c8f836f50cc56b9ea9b8dc51cd12dbe.tar.gz
Virgin import (trimmed) of GNU Tar version 1.13.25.
Diffstat (limited to 'contrib/tar')
-rw-r--r--contrib/tar/ABOUT-NLS324
-rw-r--r--contrib/tar/AUTHORS31
-rw-r--r--contrib/tar/COPYING340
-rw-r--r--contrib/tar/ChangeLog3571
-rw-r--r--contrib/tar/ChangeLog.15887
-rw-r--r--contrib/tar/INSTALL226
-rw-r--r--contrib/tar/NEWS512
-rw-r--r--contrib/tar/PORTS157
-rw-r--r--contrib/tar/README196
-rw-r--r--contrib/tar/README-alpha242
-rw-r--r--contrib/tar/THANKS493
-rw-r--r--contrib/tar/TODO5
-rw-r--r--contrib/tar/doc/fdl.texi403
-rw-r--r--contrib/tar/doc/freemanuals.texi89
-rw-r--r--contrib/tar/doc/getdate.texi432
-rw-r--r--contrib/tar/doc/header.texi235
-rw-r--r--contrib/tar/doc/tar.texi8465
-rw-r--r--contrib/tar/doc/version.texi4
-rw-r--r--contrib/tar/lib/addext.c114
-rw-r--r--contrib/tar/lib/alloca.c504
-rw-r--r--contrib/tar/lib/argmatch.c308
-rw-r--r--contrib/tar/lib/argmatch.h129
-rw-r--r--contrib/tar/lib/backupfile.c278
-rw-r--r--contrib/tar/lib/backupfile.h60
-rw-r--r--contrib/tar/lib/basename.c79
-rw-r--r--contrib/tar/lib/dirname.c105
-rw-r--r--contrib/tar/lib/dirname.h47
-rw-r--r--contrib/tar/lib/error.c396
-rw-r--r--contrib/tar/lib/error.h78
-rw-r--r--contrib/tar/lib/exclude.c267
-rw-r--r--contrib/tar/lib/exclude.h49
-rw-r--r--contrib/tar/lib/fileblocks.c77
-rw-r--r--contrib/tar/lib/fnmatch.c230
-rw-r--r--contrib/tar/lib/fnmatch.hin69
-rw-r--r--contrib/tar/lib/ftruncate.c95
-rw-r--r--contrib/tar/lib/full-write.c67
-rw-r--r--contrib/tar/lib/full-write.h9
-rw-r--r--contrib/tar/lib/getdate.c2210
-rw-r--r--contrib/tar/lib/getdate.h46
-rw-r--r--contrib/tar/lib/getline.c57
-rw-r--r--contrib/tar/lib/getline.h38
-rw-r--r--contrib/tar/lib/getopt.c1067
-rw-r--r--contrib/tar/lib/getopt.h179
-rw-r--r--contrib/tar/lib/getopt1.c187
-rw-r--r--contrib/tar/lib/getstr.c114
-rw-r--r--contrib/tar/lib/getstr.h19
-rw-r--r--contrib/tar/lib/hash.c1009
-rw-r--r--contrib/tar/lib/hash.h120
-rw-r--r--contrib/tar/lib/human.c342
-rw-r--r--contrib/tar/lib/human.h39
-rw-r--r--contrib/tar/lib/lchown.c56
-rw-r--r--contrib/tar/lib/lchown.h9
-rw-r--r--contrib/tar/lib/malloc.c38
-rw-r--r--contrib/tar/lib/memset.c26
-rw-r--r--contrib/tar/lib/mktime.c527
-rw-r--r--contrib/tar/lib/modechange.c481
-rw-r--r--contrib/tar/lib/modechange.h71
-rw-r--r--contrib/tar/lib/msleep.c131
-rw-r--r--contrib/tar/lib/prepargs.c95
-rw-r--r--contrib/tar/lib/prepargs.h3
-rw-r--r--contrib/tar/lib/print-copyr.c52
-rw-r--r--contrib/tar/lib/print-copyr.h9
-rw-r--r--contrib/tar/lib/quote.c28
-rw-r--r--contrib/tar/lib/quote.h12
-rw-r--r--contrib/tar/lib/quotearg.c622
-rw-r--r--contrib/tar/lib/quotearg.h110
-rw-r--r--contrib/tar/lib/readutmp.c133
-rw-r--r--contrib/tar/lib/realloc.c44
-rw-r--r--contrib/tar/lib/rename.c67
-rw-r--r--contrib/tar/lib/rmdir.c87
-rw-r--r--contrib/tar/lib/safe-read.c59
-rw-r--r--contrib/tar/lib/safe-read.h10
-rw-r--r--contrib/tar/lib/save-cwd.c153
-rw-r--r--contrib/tar/lib/save-cwd.h23
-rw-r--r--contrib/tar/lib/savedir.c129
-rw-r--r--contrib/tar/lib/savedir.h14
-rw-r--r--contrib/tar/lib/stpcpy.c50
-rw-r--r--contrib/tar/lib/strcasecmp.c66
-rw-r--r--contrib/tar/lib/strncasecmp.c2
-rw-r--r--contrib/tar/lib/strstr.c122
-rw-r--r--contrib/tar/lib/strtoimax.c100
-rw-r--r--contrib/tar/lib/strtol.c472
-rw-r--r--contrib/tar/lib/strtoll.c33
-rw-r--r--contrib/tar/lib/strtoul.c22
-rw-r--r--contrib/tar/lib/strtoull.c27
-rw-r--r--contrib/tar/lib/strtoumax.c2
-rw-r--r--contrib/tar/lib/unicodeio.c259
-rw-r--r--contrib/tar/lib/unicodeio.h57
-rw-r--r--contrib/tar/lib/utime.c82
-rw-r--r--contrib/tar/lib/waitpid.c72
-rw-r--r--contrib/tar/lib/xalloc.h87
-rw-r--r--contrib/tar/lib/xgetcwd.c87
-rw-r--r--contrib/tar/lib/xmalloc.c116
-rw-r--r--contrib/tar/lib/xstrdup.c46
-rw-r--r--contrib/tar/lib/xstrtoimax.c31
-rw-r--r--contrib/tar/lib/xstrtol.c288
-rw-r--r--contrib/tar/lib/xstrtol.h82
-rw-r--r--contrib/tar/lib/xstrtoul.c4
-rw-r--r--contrib/tar/lib/xstrtoumax.c31
-rw-r--r--contrib/tar/src/arith.h27
-rw-r--r--contrib/tar/src/buffer.c1600
-rw-r--r--contrib/tar/src/common.h578
-rw-r--r--contrib/tar/src/compare.c817
-rw-r--r--contrib/tar/src/create.c1550
-rw-r--r--contrib/tar/src/delete.c364
-rw-r--r--contrib/tar/src/extract.c1313
-rw-r--r--contrib/tar/src/incremen.c584
-rw-r--r--contrib/tar/src/list.c1191
-rw-r--r--contrib/tar/src/mangle.c121
-rw-r--r--contrib/tar/src/misc.c847
-rw-r--r--contrib/tar/src/names.c941
-rw-r--r--contrib/tar/src/rmt.c576
-rw-r--r--contrib/tar/src/rmt.h93
-rw-r--r--contrib/tar/src/rtapelib.c718
-rw-r--r--contrib/tar/src/system.h587
-rw-r--r--contrib/tar/src/tar.c1354
-rw-r--r--contrib/tar/src/tar.h235
-rw-r--r--contrib/tar/src/update.c195
118 files changed, 48818 insertions, 0 deletions
diff --git a/contrib/tar/ABOUT-NLS b/contrib/tar/ABOUT-NLS
new file mode 100644
index 0000000..5fde45a
--- /dev/null
+++ b/contrib/tar/ABOUT-NLS
@@ -0,0 +1,324 @@
+Notes on the Free Translation Project
+*************************************
+
+ Free software is going international! The Free Translation Project
+is a way to get maintainers of free software, translators, and users all
+together, so that will gradually become able to speak many languages.
+A few packages already provide translations for their messages.
+
+ If you found this `ABOUT-NLS' file inside a distribution, you may
+assume that the distributed package does use GNU `gettext' internally,
+itself available at your nearest GNU archive site. But you do _not_
+need to install GNU `gettext' prior to configuring, installing or using
+this package with messages translated.
+
+ Installers will find here some useful hints. These notes also
+explain how users should proceed for getting the programs to use the
+available translations. They tell how people wanting to contribute and
+work at translations should contact the appropriate team.
+
+ When reporting bugs in the `intl/' directory or bugs which may be
+related to internationalization, you should tell about the version of
+`gettext' which is used. The information can be found in the
+`intl/VERSION' file, in internationalized packages.
+
+Quick configuration advice
+==========================
+
+ If you want to exploit the full power of internationalization, you
+should configure it using
+
+ ./configure --with-included-gettext
+
+to force usage of internationalizing routines provided within this
+package, despite the existence of internationalizing capabilities in the
+operating system where this package is being installed. So far, only
+the `gettext' implementation in the GNU C library version 2 provides as
+many features (such as locale alias, message inheritance, automatic
+charset conversion or plural form handling) as the implementation here.
+It is also not possible to offer this additional functionality on top
+of a `catgets' implementation. Future versions of GNU `gettext' will
+very likely convey even more functionality. So it might be a good idea
+to change to GNU `gettext' as soon as possible.
+
+ So you need _not_ provide this option if you are using GNU libc 2 or
+you have installed a recent copy of the GNU gettext package with the
+included `libintl'.
+
+INSTALL Matters
+===============
+
+ Some packages are "localizable" when properly installed; the
+programs they contain can be made to speak your own native language.
+Most such packages use GNU `gettext'. Other packages have their own
+ways to internationalization, predating GNU `gettext'.
+
+ By default, this package will be installed to allow translation of
+messages. It will automatically detect whether the system already
+provides the GNU `gettext' functions. If not, the GNU `gettext' own
+library will be used. This library is wholly contained within this
+package, usually in the `intl/' subdirectory, so prior installation of
+the GNU `gettext' package is _not_ required. Installers may use
+special options at configuration time for changing the default
+behaviour. The commands:
+
+ ./configure --with-included-gettext
+ ./configure --disable-nls
+
+will respectively bypass any pre-existing `gettext' to use the
+internationalizing routines provided within this package, or else,
+_totally_ disable translation of messages.
+
+ When you already have GNU `gettext' installed on your system and run
+configure without an option for your new package, `configure' will
+probably detect the previously built and installed `libintl.a' file and
+will decide to use this. This might be not what is desirable. You
+should use the more recent version of the GNU `gettext' library. I.e.
+if the file `intl/VERSION' shows that the library which comes with this
+package is more recent, you should use
+
+ ./configure --with-included-gettext
+
+to prevent auto-detection.
+
+ The configuration process will not test for the `catgets' function
+and therefore it will not be used. The reason is that even an
+emulation of `gettext' on top of `catgets' could not provide all the
+extensions of the GNU `gettext' library.
+
+ Internationalized packages have usually many `po/LL.po' files, where
+LL gives an ISO 639 two-letter code identifying the language. Unless
+translations have been forbidden at `configure' time by using the
+`--disable-nls' switch, all available translations are installed
+together with the package. However, the environment variable `LINGUAS'
+may be set, prior to configuration, to limit the installed set.
+`LINGUAS' should then contain a space separated list of two-letter
+codes, stating which languages are allowed.
+
+Using This Package
+==================
+
+ As a user, if your language has been installed for this package, you
+only have to set the `LANG' environment variable to the appropriate
+`LL_CC' combination. Here `LL' is an ISO 639 two-letter language code,
+and `CC' is an ISO 3166 two-letter country code. For example, let's
+suppose that you speak German and live in Germany. At the shell
+prompt, merely execute `setenv LANG de_DE' (in `csh'),
+`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash').
+This can be done from your `.login' or `.profile' file, once and for
+all.
+
+ You might think that the country code specification is redundant.
+But in fact, some languages have dialects in different countries. For
+example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The
+country code serves to distinguish the dialects.
+
+ Not all programs have translations for all languages. By default, an
+English message is shown in place of a nonexistent translation. If you
+understand other languages, you can set up a priority list of languages.
+This is done through a different environment variable, called
+`LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG'
+for the purpose of message handling, but you still need to have `LANG'
+set to the primary language; this is required by other parts of the
+system libraries. For example, some Swedish users who would rather
+read translations in German than English for when Swedish is not
+available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'.
+
+ In the `LANGUAGE' environment variable, but not in the `LANG'
+environment variable, `LL_CC' combinations can be abbreviated as `LL'
+to denote the language's main dialect. For example, `de' is equivalent
+to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT'
+(Portuguese as spoken in Portugal) in this context.
+
+Translating Teams
+=================
+
+ For the Free Translation Project to be a success, we need interested
+people who like their own language and write it well, and who are also
+able to synergize with other translators speaking the same language.
+Each translation team has its own mailing list. The up-to-date list of
+teams can be found at the Free Translation Project's homepage,
+`http://www.iro.umontreal.ca/contrib/po/HTML/', in the "National teams"
+area.
+
+ If you'd like to volunteer to _work_ at translating messages, you
+should become a member of the translating team for your own language.
+The subscribing address is _not_ the same as the list itself, it has
+`-request' appended. For example, speakers of Swedish can send a
+message to `sv-request@li.org', having this message body:
+
+ subscribe
+
+ Keep in mind that team members are expected to participate
+_actively_ in translations, or at solving translational difficulties,
+rather than merely lurking around. If your team does not exist yet and
+you want to start one, or if you are unsure about what to do or how to
+get started, please write to `translation@iro.umontreal.ca' to reach the
+coordinator for all translator teams.
+
+ The English team is special. It works at improving and uniformizing
+the terminology in use. Proven linguistic skill are praised more than
+programming skill, here.
+
+Available Packages
+==================
+
+ Languages are not equally supported in all packages. The following
+matrix shows the current state of internationalization, as of September
+2001. The matrix shows, in regard of each package, for which languages
+PO files have been submitted to translation coordination, with a
+translation percentage of at least 50%.
+
+ Ready PO files bg cs da de el en eo es et fi fr gl he hr id it ja
+ +----------------------------------------------------+
+ a2ps | [] [] [] |
+ bash | [] [] [] [] |
+ bfd | |
+ binutils | [] |
+ bison | [] [] [] [] [] |
+ clisp | [] [] [] [] |
+ cpio | [] [] [] [] [] |
+ diffutils | [] [] [] [] [] [] [] |
+ enscript | [] [] |
+ error | [] [] |
+ fetchmail | |
+ fileutils | [] [] [] [] [] [] [] [] |
+ findutils | [] [] [] [] [] [] [] [] |
+ flex | [] [] [] |
+ freetype | |
+ gas | |
+ gawk | [] [] |
+ gcal | |
+ gcc | |
+ gettext | [] [] [] [] [] [] [] [] [] [] |
+ gnupg | [] [] [] [] [] [] [] |
+ gprof | |
+ grep | [] [] [] [] [] [] [] [] |
+ hello | [] [] [] [] [] [] [] [] [] [] [] |
+ id-utils | [] [] [] |
+ indent | [] [] [] [] [] |
+ jpilot | [] |
+ kbd | |
+ ld | [] |
+ libc | [] [] [] [] [] [] [] [] |
+ lilypond | [] |
+ lynx | [] [] [] [] |
+ m4 | [] [] [] [] [] [] [] [] |
+ make | [] [] [] [] [] [] |
+ mysecretdiary | [] |
+ nano | [] [] [] |
+ opcodes | |
+ parted | [] [] [] |
+ ptx | [] [] [] [] [] [] [] |
+ python | |
+ recode | [] [] [] [] [] [] [] [] [] |
+ sed | [] [] [] [] [] [] [] [] [] [] [] [] |
+ sh-utils | [] [] [] [] [] [] [] [] [] [] |
+ sharutils | [] [] [] [] [] [] [] [] |
+ sketch | |
+ soundtracker | [] [] [] |
+ sp | |
+ tar | [] [] [] [] [] [] [] [] |
+ texinfo | [] [] [] [] [] [] |
+ textutils | [] [] [] [] [] [] [] [] |
+ util-linux | [] [] |
+ wdiff | [] [] [] |
+ wget | [] [] [] [] [] [] [] [] [] [] |
+ +----------------------------------------------------+
+ bg cs da de el en eo es et fi fr gl he hr id it ja
+ 0 14 24 32 11 1 8 23 13 1 33 22 4 0 7 9 18
+
+ ko lv nb nl nn no pl pt pt_BR ru sk sl sv tr uk zh
+ +----------------------------------------------------+
+ a2ps | [] [] [] | 6
+ bash | | 4
+ bfd | | 0
+ binutils | | 1
+ bison | [] | 6
+ clisp | [] | 5
+ cpio | [] [] [] [] [] | 10
+ diffutils | [] [] [] [] | 11
+ enscript | [] [] [] | 5
+ error | [] [] | 4
+ fetchmail | | 0
+ fileutils | [] [] [] [] [] [] [] [] [] | 17
+ findutils | [] [] [] [] [] [] [] [] | 16
+ flex | [] [] [] | 6
+ freetype | | 0
+ gas | | 0
+ gawk | [] | 3
+ gcal | | 0
+ gcc | | 0
+ gettext | [] [] [] [] [] [] [] [] | 18
+ gnupg | [] [] [] | 10
+ gprof | | 0
+ grep | [] [] [] [] | 12
+ hello | [] [] [] [] [] [] [] [] [] [] [] | 22
+ id-utils | [] [] [] | 6
+ indent | [] [] [] [] [] [] [] | 12
+ jpilot | | 1
+ kbd | [] | 1
+ ld | | 1
+ libc | [] [] [] [] [] [] [] [] | 16
+ lilypond | [] [] | 3
+ lynx | [] [] [] [] | 8
+ m4 | [] [] [] [] | 12
+ make | [] [] [] [] [] [] | 12
+ mysecretdiary | | 1
+ nano | [] | 4
+ opcodes | [] | 1
+ parted | [] [] | 5
+ ptx | [] [] [] [] [] [] [] [] | 15
+ python | | 0
+ recode | [] [] [] [] | 13
+ sed | [] [] [] [] [] [] [] | 19
+ sh-utils | [] [] [] [] [] [] [] [] [] [] [] | 21
+ sharutils | [] [] [] | 11
+ sketch | | 0
+ soundtracker | | 3
+ sp | | 0
+ tar | [] [] [] [] [] [] [] | 15
+ texinfo | [] | 7
+ textutils | [] [] [] [] [] [] [] [] | 16
+ util-linux | [] [] | 4
+ wdiff | [] [] [] [] | 7
+ wget | [] [] [] [] [] [] [] | 17
+ +----------------------------------------------------+
+ 33 teams ko lv nb nl nn no pl pt pt_BR ru sk sl sv tr uk zh
+ 53 domains 9 1 6 20 0 6 17 1 13 25 10 11 23 21 2 2 387
+
+ Some counters in the preceding matrix are higher than the number of
+visible blocks let us expect. This is because a few extra PO files are
+used for implementing regional variants of languages, or language
+dialects.
+
+ For a PO file in the matrix above to be effective, the package to
+which it applies should also have been internationalized and
+distributed as such by its maintainer. There might be an observable
+lag between the mere existence a PO file and its wide availability in a
+distribution.
+
+ If September 2001 seems to be old, you may fetch a more recent copy
+of this `ABOUT-NLS' file on most GNU archive sites. The most
+up-to-date matrix with full percentage details can be found at
+`http://www.iro.umontreal.ca/contrib/po/HTML/matrix.html'.
+
+Using `gettext' in new packages
+===============================
+
+ If you are writing a freely available program and want to
+internationalize it you are welcome to use GNU `gettext' in your
+package. Of course you have to respect the GNU Library General Public
+License which covers the use of the GNU `gettext' library. This means
+in particular that even non-free programs can use `libintl' as a shared
+library, whereas only free software can use `libintl' as a static
+library or use modified versions of `libintl'.
+
+ Once the sources are changed appropriately and the setup can handle
+to use of `gettext' the only thing missing are the translations. The
+Free Translation Project is also available for packages which are not
+developed inside the GNU project. Therefore the information given above
+applies also for every other Free Software Project. Contact
+`translation@iro.umontreal.ca' to make the `.pot' files available to
+the translation teams.
+
diff --git a/contrib/tar/AUTHORS b/contrib/tar/AUTHORS
new file mode 100644
index 0000000..5954e5a
--- /dev/null
+++ b/contrib/tar/AUTHORS
@@ -0,0 +1,31 @@
+Authors of GNU tar.
+
+The following contributions warranted legal paper exchanges with the
+Free Software Foundation. Also see files ChangeLog and THANKS.
+
+TAR Paul Eggert 2000-10
+Assigns his past and future changes.
+
+TAR Jay Fenlason
+Assigns his changes.
+
+TAR Richard E Salz 1993-03-11
+Disclaims changes to getdate.y.
+
+TAR MANUAL (?) Amy Gorin (US 1963) 1995-01-10
+Assigns the Tar Manual.
+
+TAR Francois Pinard Canada 1949 1996-02-01
+Assigns past and future changes.
+
+TAR Melissa Weisshaus US 1966 1997-04-09
+Assigns changes to the manual and future changes.
+melissa@gnu.ai.mit.edu
+
+TAR Thomas Michael Innis Bushnell US 1967 1997-04-09
+Assigns changes.
+thomas@gnu.ai.mit.edu
+
+TAR Thomas Michael Innis Bushnell US 1967 1997-04-09
+Assigns changes to manual.
+thomas@gnu.ai.mit.edu
diff --git a/contrib/tar/COPYING b/contrib/tar/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/contrib/tar/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/contrib/tar/ChangeLog b/contrib/tar/ChangeLog
new file mode 100644
index 0000000..0590681
--- /dev/null
+++ b/contrib/tar/ChangeLog
@@ -0,0 +1,3571 @@
+2001-09-26 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.ac (AM_INIT_AUTOMAKE): Version 1.13.25.
+
+ * src/buffer.c (flush_read): Don't diagnose partial blocks before
+ end of file; just ignore them silently.
+
+ * src/list.c (read_header): Don't keep around extended name
+ and link info indefinitely; keep it only for the next file.
+ This fixes a bug introduced in 1.13.24, and removes the need
+ for some static variables. Set recent_long_name and
+ recent_long_link to zero if there were no long links; this
+ avoids a violation of ANSI C rules for pointers in delete.c.
+ * THANKS: Add Christian Laubscher.
+
+2001-09-26 Jim Meyering <meyering@lucent.com>
+
+ * doc/tar.texi (Remote Tape Server): is know -> is known
+
+2001-09-25 Paul Eggert <eggert@twinsun.com>
+
+ * lib/unicodeio.c (EILSEQ): Include <iconv.h> first, since
+ <iconv.h> may define EILSEQ (e.g. libiconv). Define a
+ replacement EILSEQ to be ENOENT, not EINVAL, since callers may
+ want to distinguish EINVAL and EILSEQ.
+
+2001-09-24 Christophe Kalt <Christophe.Kalt@kbcfp.com>
+
+ * src/extract.c (maybe_recoverable):
+ Treat OVERWRITE_OLD_DIRS like DEFAULT_OLD_FILES.
+
+2001-09-22 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.ac (AM_INIT_AUTOMAKE): Version 1.13.24.
+
+ * ABOUT-NLS, intl/*: Update to gettext-0.10.40, replacing LGPL
+ with GPL.
+
+ * INSTALL, mkinstalldirs: Update to autoconf 2.52 version.
+ * PORTS: Add copyright notice, 'star' reference.
+ * README-alpha: Add copyright notice, autoconf 2.52 patch.
+ * THANKS: Add Christophe Kalt.
+ * config.sub: Upgrade to 2001-09-14 version.
+
+ * configure.ac (ALL_LINGUAS): Add ko.
+ * po/ko.po: Resurrected file.
+
+ * doc/convtexi.pl: Add coding advice for Emacs.
+
+ * doc/getdate.texi: Add copyright notice.
+
+ * doc/mdate-sh: Upgrade to automake 1.5 version.
+
+ * doc/tar.texi (extracting files): Mention --to-stdout.
+ (Option Summary, Dealing with Old Files): New option --overwrite-dir.
+ (Overwrite Old Files): Likewise.
+
+ * lib/Makefile.am (noinst_HEADERS):
+ Remove copysym.h. Add print-copyr.h, unicodeio.h.
+ (libtar_a_SOURCES): Remove copysym.c, Add print-copyr.c, unicodeio.c.
+
+ * lib/copysym.c, lib/copysym.h: Remove.
+ * lib/print-copyr.c, lib/print-copyr.h, lib/unicodeio.c,
+ lib/unicodeio.h: New files.
+
+ * lib/error.c, lib/getopt.c, lib/getopt.h, lib/getopt1.c,
+ lib/mktime.c, lib/strtoll.c: Switch from LGPL to GPL.
+
+ * lib/quotearg.c (HAVE_MBSINIT): Undef if !HAVE_MBRTOWC.
+ (mbsinit): Define to 1 if !defined mbsinit && !HAVE_MBSINIT.
+
+ * m4/Makefile.am (EXTRA_DIST): Remove isc-posix.m4.
+ * m4/isc-posix.m4: Remove.
+
+ * m4/prereq.m4 (jm_PREREQ_QUOTEARG): Check for mbsinit.
+
+ * po/POTFILES.in: Add copyright notice.
+
+ * src/Makefile.am (LDADD): Like libtar.a before @INTLLIBS@ as
+ well as after.
+ * tests/Makefile.am (LDADD): Likewise.
+
+ * src/buffer.c (write_archive_buffer, close_archive):
+ If an archive is a socket, treat it like a FIFO.
+ (records_read, records_written): New vars.
+ (write_archive_to_stdout): Now bool, not int.
+ (open_archive, flush_write, flush_read): Keep records_read and
+ records_written up to date.
+
+ * src/common.h (enum old_files): New value OVERWRITE_OLD_DIRS.
+ (write_archive_to_stdout): Now bool, not int.
+ (enum read_header): New value HEADER_SUCCESS_EXTENDED.
+ (read_header): Now takes bool arg. Existing callers modified
+ to pass 0, unless otherwise specified.
+
+ * src/delete.c (records_read): Remove; now a global.
+ (acting_as_filter): Now bool, not int.
+ (recent_long_name, recent_long_link, recent_long_name_blocks,
+ recent_long_link_blocks, records_read, records_written): New decls.
+ (records_skipped): New var.
+ (move_archive): Don't divide by zero if arg is 0.
+ Use the above vars to compute how far to move.
+ (write_recent_blocks): New function.
+ (delete_archive_member): Pass 1 to read_header, so that it doesn't
+ read more than 1 block. Handle resulting HEADER_SUCCESS_EXTENDED code.
+ Keep track of how many records have been skipped.
+ Let the buffer code count records.
+ When copying a header, copy any extended headers that came before it.
+
+ * src/extract.c (extract_archive): When marking a directory to be
+ updated after symlinks, stat all directories after it in the
+ delayed-set-stat list too, since they will be checked after
+ symlinks. Add support for --overwrite-dir.
+
+ * src/list.c (recent_long_name, recent_long_link,
+ recent_long_name_blocks, recent_long_link_blocks): New vars.
+ (read_and): Pass 0 to read_header.
+ (read_header): New arg RAW_EXTENDED_HEADERS. Store away extended
+ headers into new vars. Null-terminate incoming symbolic links.
+
+ * src/rmt.c: Include print-copyr.h, not copysym.h.
+ (main): Use print_copyright, not copyright_symbol.
+ * src/tar.c (decode_options): Likewise.
+ (OVERWRITE_DIR_OPTION): New constant.
+ (long_options, usage, decode_options): Add --overwrite-dir.
+
+ * src/tar.h: Put copyright notice into documentation.
+
+ * tests/Makefile.am (TESTS): Add delete03.sh.
+ * tests/delete03.sh: New file.
+
+ * tests/genfile.c: Include print-copyr.h, not copysym.h.
+ (main): Use print_copyright, not copyright_symbol.
+ Include <argmatch.h>.
+ (pattern_strings): Remove.
+ (pattern_args, pattern_types): New constants.
+ (main): Use XARGMATCH, not argmatch.
+
+2001-09-20 Jim Meyering <meyering@lucent.com>
+
+ * lib/xstrtol.c (strtoimax): Guard declaration with
+ `#if !HAVE_DECL_STRTOIMAX', rather than just `#ifndef strtoimax'.
+ The latter fails because some systems (at least rs6000-ibm-aix4.3.3.0)
+ have their own, conflicting declaration of strtoimax in sys/inttypes.h.
+ (strtoumax): Likewise, for completeness (it wasn't necessary).
+ * m4/xstrtoimax.m4 (jm_AC_PREREQ_XSTRTOIMAX):
+ Check for declaration of strtoimax.
+ * m4/xstrtoumax.m4 (jm_AC_PREREQ_XSTRTOUMAX):
+ Check for declaration of strtoumax.
+
+2001-09-16 Paul Eggert <eggert@twinsun.com>
+
+ * fnmatch.m4 (jm_FUNC_FNMATCH): Fix typo in previous patch: yes -> no.
+
+2001-09-14 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.ac (AC_INIT_AUTOMAKE): Version 1.13.23.
+
+ * README-alpha: Describe automake patch.
+
+ * configure.ac (LIBOBJS):
+ Remove automake 1.4 workaround, as we're using 1.5 now.
+ (USE_INCLUDED_LIBINTL): New AC_DEFINE.
+
+ * lib/copysym.c: Include stddef.h, for size_t.
+ Include langinfo.h if needed.
+ Use locale_charset only if USE_INCLUDED_LIBINTL;
+ if not, use nl_langinfo (CODESET) if available.
+
+2001-09-13 Paul Eggert <eggert@twinsun.com>
+
+ * config.guess, config.sub: Sync with canonical versions.
+
+ * configure.ac (jm_PREREQ_XGETCWD): Add.
+
+ * lib/Makefile.am (noinst_HEADERS): Add copysym.h.
+ (libtar_a_SOURCES): Add copysym.c.
+ * copysym.c, copysym.h: New files.
+
+ * lib/error.c: Sync with fileutils version.
+
+ * m4/Makefile.am (EXTRA_DIST): Add getcwd.m4; remove uintmax_t.m4.
+ * m4/getcwd.m4: New file.
+ * m4/uintmax_t.m4: Remove.
+
+ * m4/gettext.m4 (AM_WITH_NLS):
+ Fix bug with calculating version of Bison 1.29.
+ Reported by Karl Berry.
+
+ * src/Makefile.am (datadir): Remove.
+
+ * src/rmt.c: Include copysym.h.
+ (main): Use copyright_symbol to translate copyright notice,
+ instead of gettext.
+ * src/tar.c: Likewise.
+ * tests/genfile.c: Likewise.
+
+ * src/system.h (MB_LEN_MAX): New symbol.
+
+2001-09-11 Paul Eggert <eggert@twinsun.com>
+
+ * src/extract.c (struct delayed_set_stat): New member
+ 'after_symlinks'.
+ (delay_set_stat): Initialize it to 0.
+ (set_mode): New arg current_stat_info. Use it (if nonnull) to avoid
+ taking an extra stat ourselves. All callers changed.
+ (set_stat): Likewise.
+ (apply_nonancestor_delayed_set_stat): New arg 'after_symlinks'.
+ If false, stop when encountering a struct whose 'after_symlinks'
+ member is true. Otherwise, go through all structures but check
+ them more carefully. All callers changed.
+ (extract_archive): When extracting a deferred symlink, if its parent
+ directory's status needs fixing, then mark the directory as needing
+ to be fixed after symlinks.
+ (extract_finish): Fix status of ordinary directories, then apply
+ delayed symlinks, then fix the status of directories that are
+ ancestors of delayed symlinks.
+
+ * src/rtapelib.c (rexec):
+ Remove declaration; it ran afoul of prototypes on Crays.
+ Reported by Wendy Palm of Cray.
+
+2001-09-06 Paul Eggert <eggert@twinsun.com>
+
+ * lib/strtoimax.c (HAVE_LONG_LONG):
+ Redefine to HAVE_UNSIGNED_LONG_LONG if unsigned.
+ (strtoimax): Use sizeof (long), not
+ sizeof strtol (ptr, endptr, base),
+ to work around bug in IBM C compiler.
+
+2001-09-04 Paul Eggert <eggert@twinsun.com>
+
+ * lib/xgetcwd.c: Include "xalloc.h".
+ (xgetcwd): Do not return NULL when memory is exhausted; instead,
+ report an error and exit.
+
+ * m4/prereq.m4 (jm_PREREQ_XREADLINK): New macro.
+ (jm_PREREQ): Use it.
+
+2001-09-03 Paul Eggert <eggert@twinsun.com>
+
+ * m4/prereq.m4 (jm_PREREQ): Add jm_PREREQ_XGETCWD.
+ (jm_PREREQ_XGETCWD): New macro.
+
+ * lib/exclude.c (fnmatch_no_wildcards):
+ Fix typo that caused us to do case-folding
+ search even when that was not desired. This occurred only in the
+ no-wildcard case.
+
+ * lib/xgetcwd.c: Include pathmax.h if not HAVE_GETCWD.
+ Do not include xalloc.h.
+ (INITIAL_BUFFER_SIZE): New symbol.
+ Do not use xmalloc / xrealloc, since the caller is responsible for
+ handling errors. Preserve errno around `free' during failure.
+ Do not overrun buffer when using getwd.
+
+ * lib/xgetcwd.c (xgetcwd):
+ Use HAVE_GETCWD_NULL, not defined __GLIBC__ && __GLIBC__ >= 2,
+ to decide whether to use getcwd (NULL, 0).
+
+2001-09-02 Paul Eggert <eggert@twinsun.com>
+
+ * lib/xgetcwd.c: Fix typo in local var; from Jim Meyering.
+
+2001-09-01 Jim Meyering <meyering@lucent.com>
+
+ * exclude.c: Use `""', not `<>' to #include non-system header files.
+ (fnmatch_no_wildcards): Rewrite not to use function names, strcasecmp
+ and strncasecmp as r-values. Unixware didn't have declarations.
+
+2001-08-31 Jim Meyering <meyering@lucent.com>
+
+ * lib/xgetcwd.c (xgetcwd): Reorganize to avoid some duplication.
+ Use an initial, malloc'd, buffer of length 128 rather than
+ a statically allocated one of length 1024.
+
+2001-08-30 Paul Eggert <eggert@twinsun.com>
+
+ * lib/utime.c: Include full-write.h.
+ * lib/xstrtol.c (strtoimax): New decl.
+
+2001-08-29 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.ac (AC_INIT_AUTOMAKE): Version 1.13.22.
+
+ * src/create.c (dump_file): Relativize link names before dumping.
+ This fixes a bug reported by Jose Pedro Oliveira.
+
+ * src/create.c (dump_file): Use offsetof when computing sizes for
+ struct hack; this avoids wasted space in some cases.
+ * src/incremen.c (note_directory, find_directory): Likewise.
+ * src/names.c (name_gather, addname): Likewise.
+
+ * src/extract.c (extract_archive): Use strcpy, not memcpy,
+ for consistency with other code that does similar things.
+ * src/names.c (name_gather): Likewise.
+
+ * src/names.c (read_name_from_file, name_next, name_gather,
+ add_hierarchy_to_namelist): Avoid quadratic behavior when
+ reallocating buffers. Check for buffer size overflow.
+ (addname): Avoid unnecessary clearing of memory.
+
+2001-08-29 "Jan D." <Jan.Djarv@mbox200.swipnet.se>
+
+ * src/extract.c (delay_set_stat): Fix off-by-one error in file
+ name size allocation that caused core dumps.
+
+2001-08-28 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.ac (AC_INIT_AUTOMAKE): Version 1.13.21.
+
+ * configure.ac (GNU_SOURCE): Define to 1, not /**/.
+ (major_t, minor_t, ssize_t): Use new-style AC_CHECK_TYPE.
+ (daddr_t): Remove; no longer used.
+ (jm_PREREQ_HUMAN): Add.
+
+ * acconfig.h: Remove; no longer needed.
+
+ * config.guess, config.sub:
+ New files, from automake 1.5. Gettext 0.10.39 needs them.
+ * depcomp, missing, mkinstalldirs: Upgrade to automake 1.5.
+
+ * Makefile.am (AUTOMAKE_OPTIONS): Add dist-bzip2.
+ (SUBDIRS): Put intl before lib, as gettext requires.
+
+ * ABOUT-NLS: Upgrade to gettext 0.10.39.
+ * intl: Upgrade entire directory to gettext 0.10.39.
+ * m4/codeset.m4, m4/glibc21.m4, m4/iconv.m4:
+ New files, from gettext 0.10.39.
+ * m4/gettext.m4, m4/isc-posix.m4, m4/lcmessage.m4, m4/progtest.m4,
+ Upgrade to gettext 0.10.39,
+ * po/Makefile.in.in: Likewise, except fix a typo in its copying
+ permissions.
+ * po/cat-id-tbl.c, po/stamp-cat-id:
+ Remove; no longer used by gettext 0.10.39.
+ * po/ChangeLog: New file.
+
+ * doc/Makefile.am (EXTRA_DIST): Add freemanuals.texi.
+ $(srcdir)/tar.texi: Likewise.
+ * doc/freemanuals.texi: New file.
+ * doc/tar.texi (Free Software Needs Free Documentation): New appendix.
+ `fileds' -> `fields'
+ * doc/texinfo.tex: Upgrade to version 2001-07-25.07.
+
+ * lib/Makefile.am (EXTRA_DIST): Add strtoll.c, strtoimax.c.
+ (noinst_HEADERS): Add quote.h.
+ (libtar_a_SOURCES): Add quote.c, xstrtoimax.c.
+
+ * lib/exclude.c: Fix typo in '#include <stdint.h>' directive.
+
+ * lib/full-write.c, lib/savedir.c: Comment fix.
+
+ * lib/pathmax.h: Remove.
+
+ * lib/quote.c, lib/quote.h: New files.
+
+ * lib/xgetcwd.c: Don't include pathmax.h.
+ Include stdlib.h and unistd.h if available.
+ Include xalloc.h.
+ (xmalloc, xstrdup, free): Remove decls.
+ (xgetcwd): Don't assume sizes fit in unsigned.
+ Check for overflow when computing sizes.
+ Simplify reallocation code.
+
+ * lib/xmalloc.c: Quote failure tests.
+
+ * lib/strtoumax.c, lib/xstrtoimax.c: New files.
+
+ * lib/strtoimax.c: Renamed from strtouxmax.c. Make it more
+ similar to strtol.c.
+ (UNSIGNED): Renamed from STRTOUXMAX_UNSIGNED.
+ (verify): New macro.
+ (strtoumax, uintmax_t, strtoull, strtol): Remove.
+ (intmax_t, strtoimax, strtol, strtoll): New macros, if UNSIGNED.
+ (strtoimax): Renamed from strtoumax. All uses of unsigned values
+ changed to signed values. Check sizes at compile-time, not
+ run-time. Prefer strtol to strtoll if both work.
+ (main): Remove.
+
+ * lib/xstrtol.h (xstrtoimax): New decl.
+
+ * m4/Makefile.am (EXTRA_DIST):
+ Add codeset.m4, glibc21.m4, iconv.m4, inttypes.m4,
+ longlong.m4, xstrtoimax.m4.
+
+ * m4/inttypes.m4 (jm_AC_HEADER_INTTYPES_H):
+ Remove; now done by autoconf.
+ (jm_AC_TYPE_INTMAX_T, jm_AC_TYPE_UINTMAX_T): Replace with
+ Use AC_CHECK_TYPE instead of merely looking for the header.
+
+ * m4/uintmax_t.m4: Use shorter comment.
+
+ * m4/xstrtoumax.m4 (jm_AC_PREREQ_XSTRTOUMAX):
+ Quote first arg of AC_DEFUN.
+ Require jm_AC_TYPE_INTMAX_T and jm_AC_TYPE_LONG_LONG since they
+ is needed to parse the include file.
+ Simplify logic behind the args to AC_REPLACE.
+
+ * src/Makefile.am (OMIT_DEPENDENCIES): Remove.
+
+ * src/ansi2knr.1, src/ansi2knr.c: Remove; wasn't being used.
+
+ * src/rmt.c (main):
+ Use "Copyright %d" to simplify the translator's job in the future.
+ Advise translator about circle-C.
+ * src/tar.c: (decode_options): Likewise.
+ * tests/genfile.c (main): Likewise.
+
+2001-08-28 Jim Meyering <meyering@lucent.com>
+
+ * lib/argmatch.c: Include "quote.h".
+ (argmatch_invalid): Quote the context.
+
+ * lib/dirname.c (dir_name): Fix typo on PC platforms.
+
+ * lib/backupfile.c, lib/basename.c, lib/dirname.c, lib/strtoul.c:
+ Use single-quote for local .h files.
+
+ * lib/error.h (__attribute__): Don't depend on __STRICT_ANSI__.
+
+ * lib/getopt.c, lib/getopt.h, lib/getopt1.c: Upgrade to recent
+ glibc versions.
+
+ * lib/getdate.y (get_date): Initialize tm_isdst to -1 before
+ invoking mktime the last time.
+
+ * lib/pathmax.h: Use #if rather than #ifdef for HAVE_UNISTD_H.
+
+ * lib/rename.c: Major rewrite by Volker Borchert to use system
+ rename function, but to work around problems with trailing
+ slashes.
+
+ * lib/strtoll.c: New file, from glibc.
+ * lib/strtoul.c: Update from glibc.
+
+ * lib/strtouxmax.c: Renamed from lib/strtoumax.c.
+ Add support for signed numbers, too.
+ (strtoul, strtoull): Do not declare if STRTOUXMAX_UNSIGNED
+ is not defined.
+ (strtol, strtoll): Declare as needed, if STRTOUXMAX_UNSIGNED is
+ not defined.
+ (strtoumax, uintmax_t, strtoull, strtoul): New macros.
+ (main): Use generic names in debugging output.
+ * lib/strtoimax.c: Plus add the following changes of my own:
+ (main): Use accurate names in debugging output.
+
+ * lib/xgetcwd.c (xgetcwd): Use getcwd if glibc 2 or later.
+ Don't use PATH_MAX.
+
+ * m4/c-bs-a.m4, m4/check-decl.m4, m4/d-ino.m4, m4/error.m4,
+ m4/getline.m4, m4/jm-mktime.m4, m4/malloc.m4, m4/mbrtowc.m4,
+ m4/mbstate_t.m4, m4/realloc.m4, m4/uintmax_t.m4, m4/utimbuf.m4,
+ m4/utime.m4, m4/utimes.m4:
+ Quote the first argument in each use of AC_DEFUN.
+
+ * m4/getline.m4: Don't use string.h.
+
+ * m4/inttypes.m4, m4/longlong.m4, m4/xstrtoimax.m4: New files.
+
+ * m4/mbrtowc.m4 (jm_FUNC_MBRTOWC): @%:@ -> #.
+
+2001-08-27 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.ac (AC_INIT_AUTOMAKE): Version 1.13.20.
+
+ The biggest change is the new --exclude semantics and options.
+ The basic idea was suggested by Gerhard Poul; thanks!
+
+ * NEWS: Describe new --exclude semantics and options, and bug fixes.
+ * README: ignfail.sh fails on some NFS hosts.
+ * NEWS, README, lib/xstrtol.h: Add copyright notice.
+
+ * Makefile.am (ACLOCAL_AMFLAGS): Add -I m4.
+ (M4DIR, ACINCLUDE_INPUTS, $(srcdir)/acinclude.m4):
+ Remove; the automake bug has been fixed.
+ * acinclude.m4: Remove.
+
+ * configure.ac: Renamed from configure.in.
+ (AC_PREREQ): Bump from 2.13 to 2.52.
+ (ALL_LINGUAS): Add id, tr. Remove ko, as po/ko.po (dated
+ 1997-05-30) has an encoding error.
+ (jm_AC_HEADER_INTTYPES_H): Remove; now done by autoconf.
+ (AC_FUNC_FNMATCH): Use AC_CONFIG_LINKS, not AC_LINK_FILES.
+
+ * doc/fdl.texi: Update to current GNU version.
+
+ * doc/tar.texi: Put leading '*' in direntry.
+ Accommodate new gfdl sectioning.
+ New option --recursion (the default) that is the inverse of
+ --no-recursion.
+
+ New options --anchored, --ignore-case, --wildcards,
+ --wildcards-match-slash, and their negations (e.g., --no-anchored).
+ Along with --recursion and --no-recursion, these control how exclude
+ patterns are interpreted. The default interpretation of exclude
+ patterns is now --no-anchored --no-ignore-case --recursion
+ --wildcards --wildcards-match-slash.
+
+ * lib/Makefile.am (OMIT_DEPENDENCIES): Remove.
+
+ * lib/exclude.c (bool): Declare, perhaps by including stdbool.h.
+ (<sys/types.h>): Include only if HAVE_SYS_TYPES_H.
+ (<stdlib.h>, <string.h>, <strings.h>, <inttypes.h>, <stdint.h>):
+ Include if available.
+ (<xalloc.h>): Include
+ (SIZE_MAX): Define if <stdint.h> or <inttypes.h> doesn't.
+ (verify): New macro. Use it to verify that EXCLUDE macros do not
+ collide with FNM macros.
+ (struct patopts): New struct.
+ (struct exclude): Use it, as exclude patterns now come with options.
+ (new_exclude): Support above changes.
+ (new_exclude, add_exclude_file):
+ Initial size must now be a power of two to simplify overflow checking.
+ (free_exclude, fnmatch_no_wildcards): New function.
+ (excluded_filename): No longer requires options arg, as the options
+ are determined by add_exclude. Now returns bool, not int.
+ (excluded_filename, add_exclude):
+ Add support for the fancy new exclusion options.
+ (add_exclude, add_exclude_file): Now takes int options arg.
+ Check for arithmetic overflow when computing sizes.
+ (add_exclude_file): xrealloc might modify errno, so don't
+ realloc until after errno might be used.
+
+ * lib/exclude.h (EXCLUDE_ANCHORED, EXCLUDE_INCLUDE,EXCLUDE_WILDCARDS):
+ New macros.
+ (free_exclude): New decl.
+ (add_exclude, add_exclude_file): Now takes int options arg.
+ (excluded_filename): No longer requires options arg, as the options
+ are determined by add_exclude. Now returns bool, not int.
+
+ * lib/prepargs.c: Include <string.h>; required for C99 since
+ we use strlen.
+
+ * lib/quotearg.c:
+ BSD/OS 4.1 wchar.h requires FILE and struct tm to be declared.
+
+ * lib/xstrtol.h (_DECLARE_XSTRTOL): Improve quality of
+ diagnostic for LONGINT_INVALID_SUFFIX_CHAR.
+
+ * m4/Makefile.am (EXTRA_DIST): Add check-decl.m4, mbrtowc.m4.
+ Remove inttypes_h.m4, largefile.m4, mktime.m4.
+
+ * m4/inttypes_h.m4, m4/largefile.m4, m4/mktime.m4: Remove;
+ subsumed by Autoconf 2.50.
+
+ * m4/error.m4: Upgrade to serial 2.
+
+ * m4/fnmatch.m4 (jm_FUNC_FNMATCH): Upgrade to serial 4, but
+ remove test for GNU C library. It's not correct, as some
+ older glibcs are buggy.
+
+ * m4/getline.m4, m4/malloc.m4: Upgrade to serial 4.
+
+ * m4/prereq.m4: Upgrade to serial 20, but then:
+ (jm_PREREQ): Add jm_PREREQ_EXCLUDE.
+ (jm_PREREQ_EXCLUDE): New macro.
+ (jm_PREREQ_HUMAN): Remove jm_AC_HEADER_INTTYPES_H, as it is subsumed
+ by autoconf 2.5x.
+
+ * m4/realloc.m4: Upgrade to serial 4.
+
+ * m4/strerror_r.m4: Revert to serial 1002.
+
+ * m4/uintmax_t.m4: Upgrade to autoconf 2.5x.
+
+ * m4/utimes.m4: Upgrade to latest version (still "serial 3").
+
+ * m4/xstrtoumax.m4: Upgrade to serial 3, but then:
+ (jm_AC_PREREQ_XSTRTOUMAX): Remove jm_AC_HEADER_INTTYPES_H, as
+ it is now subsumed by autoconf. Add inttypes.h.
+
+ * po/cs.po, po/da.po, po/de.po, po/es.po, po/et.po, po/fr.po,
+ po/it.po, po/pl.po, po/sl.po, po/sv.po: Sync with translation project.
+
+ * src/buffer.c (new_volume): Stop if the script exits with an error.
+
+ * src/common.h (excluded_with_slash, excluded_without_slash):
+ Remove, replacing by:
+ (excluded): New decl.
+ (link_error): New decl.
+ (excluded_name): Now returns bool.
+
+ * src/extract.c:
+ (struct delayed_symlinks, extract_archive, apply_delayed_symlinks):
+ Support hard links to symbolic links.
+
+ (struct delayed_symlink): Remove 'names' member, replacing it with
+ 'sources' and 'target' member. All uses changed.
+
+ (struct string_list): New type.
+
+ (delayed_set_stat, extract_archive): Use offsetof when computing sizes
+ for struct hack; this avoids wasted space in some cases.
+
+ (extract_archive): Fix test for absolute pathnames and/or "..".
+ Use link_error to report errors for links.
+ Remove redundant trailing '/' at "really_dir", for all uses, not
+ just before invoking mkdir.
+ If overwriting old files, do not worry so much about existing
+ directories.
+ Fix mode computation in the case where the directory exists.
+
+ (apply_delayed_symlinks): If we can't make a hard link to a symbolic
+ link, make a copy of the symbolic link.
+
+ * src/incremen.c (get_directory_contents):
+ If ignore_failed_read_option, only warn about
+ stat failures.
+
+ * src/list.c (from_header): Do not issue a diagnostic if TYPE is zero.
+ However, check for error even for '-' or '+' case.
+
+ (print_header): Try parsing uids and gids as unsigned integers first,
+ and as a uid_t or gid_t only if that fails. This adds support for
+ listing positive uids and gids that are greater than UID_MAX and
+ GID_MAX.
+
+ * src/misc.c (link_error): New function.
+
+ * src/names.c (collect_and_sort_names):
+ If ignore_failed_read_option, only warn about
+ stat errors.
+
+ (excluded_name): Now returns bool. Simplify, as the fancy
+ features are now all in excluded_filename.
+
+ * src/rtapelib.c (base_name): Remove decl, as system.h now
+ declares it.
+
+ * src/system.h: Include stddef.h if available.
+ (offsetof): Declare if stddef.h doesn't.
+
+ Include <dirname.h>.
+ (FILESYSTEM_PREFIX_LEN, ISSLASH): Remove; now defined by dirname.h.
+
+ * src/tar.c (ANCHORED_OPTION, IGNORE_CASE_OPTION,
+ NO_ANCHORED_OPTION, NO_IGNORE_CASE_OPTION, NO_WILDCARDS_OPTION,
+ NO_WILDCARDS_MATCH_SLASH_OPTION, WILDCARDS_OPTION,
+ WILDCARDS_MATCH_SLASH_OPTION):
+ New enum values.
+
+ (long_options, usage, decode_options): Add support for --anchored,
+ --ignore-case, --no-anchored, --no-ignore-case, --no-wildcards,
+ --no-wildcards-match-slash, --recursion, --wildcards,
+ --wildcards-match-slash.
+
+ (decode_options): Implement the new way of interpreting exclude
+ patterns.
+
+ (usage): --newer-mtime takes a DATE operand. DATE may be a file name.
+
+ (OPTION_STRING, decode_options): Add -I, -y. Currently these options
+ just print error messages suggesting alternatives.
+
+ (add_filtered_exclude): Remove.
+
+ * tests/Makefile.am (TESTS): Alphabetize, except put version.sh first.
+
+ * tests/extrac04.sh (out): Remove
+ directory/subdirectory/file1, as the new semantics for
+ --exclude exclude it.
+
+ * tests/genfile.c (main): Don't use non-ASCII char in msgid.
+
+2001-08-12 Paul Eggert <eggert@twinsun.com>
+
+ * lib/addext.c (<errno.h>): Include.
+ (errno): Declare if not defined.
+ (addext): Work correctly on the Hurd, where pathconf returns -1 and
+ leaves errno alone, because there is no limit. Also, work even if
+ size_t is narrower than long.
+
+2001-07-08 Paul Eggert <eggert@twinsun.com>
+
+ * lib/alloca.c (alloca): Arg is of type size_t, not unsigned.
+
+2001-05-10 Paul Eggert <eggert@twinsun.com>
+
+ * lib/addext.c (ISSLASH, base_name): Remove decls; now in dirname.h.
+ Include <backupfile.h> and <dirname.h> after size_t is defined.
+ (addext): Use base_len to trim redundant trailing slashes instead of
+ doing it ourselves.
+
+ * lib/backupfile.c (ISSLASH, base_name):
+ Remove decls; now in dirname.h.
+ Include <argmatch.h>, <backupfile.h>, <dirname.h> after size_t
+ is defined.
+ (find_backup_file_name): Rename locals to avoid new functions.
+ Use base_len instead of rolling it ourselves.
+ Work even if dirlen is 0.
+ Use a dir of '.' if given the empty string.
+
+ * lib/basename.c:
+ Do not include <stdio.h>, <assert.h>; no longer needed.
+ (FILESYSTEM_PREFIX_LEN, PARAMS, ISSLASH): Remove; now in dirname.h.
+ Include <string.h>, <dirname.h>.
+ (base_name): Allow file names ending in slashes, other than names
+ that are all slashes. In this case, return the basename followed
+ by the slashes.
+
+ * lib/dirname.c: Include <string.h> instead of <stdlib.h>.
+ (FILESYSTEM_PREFIX_LEN, ISSLASH): Remove; now in dirname.h.
+ (dir_len): Renamed from dirlen.
+ All callers changed.
+
+ * lib/dirname.h (DIRECTORY_SEPARATOR, ISSLASH, FILESYSTEM_PREFIX_LEN):
+ New macros.
+ (base_name, base_len, dir_len, strip_trailing_slashes): New decls.
+
+2001-02-16 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c (mbrtowc, mbrtowc, mbsinit):
+ Do not declare or define if HAVE_MBRTOWC,
+ since the test for HAVE_MBRTOWC now requires proper declarations.
+
+ * lib/alloca.c (malloc): Undef before defining.
+
+2001-02-13 Paul Eggert <eggert@twinsun.com>
+
+ * src/compare.c (read_and_process): Use off_t for size.
+ From Maciej W. Rozycki.
+
+2001-01-26 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c: Include stddef.h. From Jim Meyering.
+
+2001-01-12 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AC_INIT_AUTOMAKE): Version 1.13.19.
+
+ * lib/savedir.h (savedir): Remove size arg.
+
+ * doc/tar.texi: Add @setchapternewpage odd.
+ Remove -I as an alias for -T, for now.
+ Add @dircategory.
+ Update copyright. Remove "Published by".
+ Dates beginning with / or . are taken to be file names.
+
+ * src/tar.c (<time.h>): Do not include;
+ (time): Do not declare.
+ (usage): Remove -I as an alias for -T.
+ (OPTION_STRING): Remove -I.
+ (decode_options): Dates that look like an absolute path name,
+ or that start with '.', are presumed to be file names whose
+ dates are taken.
+ Remove 'I' as an aliase for 'T'.
+ Update copyright.
+
+ * src/extract.c (<time.h>): Do not include; system.h now does this.
+ (make_directories): Skip filesystem prefixes.
+ Don't assume '/' is the only separator.
+ (extract_sparse_file): Use new full_write semantics.
+ On write error, return instead of invoking skip_file.
+ Do not free sparsearray; caller does this now.
+ (apply_nonancestor_delayed_set_stat): Do not assume '/' is the only
+ separator.
+ (extract_archive): Don't assume file name lengths fit in int.
+ Report what got stripped from member name; it might be more than '/'.
+ Use new full_write semantics.
+ Do not pass redundant trailing "/" to mkdir, as POSIX does not allow
+ mkdir to ignore it.
+ Do not report mkdir error if old_files_option == KEEP_OLD_FILES.
+
+ * src/buffer.c (<time.h>): Do not include; system.h now does this.
+ (time): Remove decl; likewise.
+ (child_open_for_uncompress): Use new full_write semantics.
+ (flush_write): Use ISSLASH instead of testing for '/'.
+ (flush_read): Likewise.
+
+ * src/rmt.h (_remdev): Look for / anywhere in Path.
+
+ * src/misc.c (contains_dot_dot): Skip filesystem prefix.
+ Don't assume '/' is the only separator.
+ (safer_rmdir): Don't assume '/' is the only separator.
+
+ * src/compare.c (diff_archive): Don't assume '/' is the only separator.
+
+ * lib/dirname.h (dirlen): New decl.
+
+ * src/incremen.c (get_directory_contents):
+ Remove path_size arg; all callers changed.
+ Don't assume '/' is the only directory separator.
+ (gnu_restore): Work even if file name length doesn't fit in int.
+
+ * lib/addext.c (ISSLASH): New macro.
+ (addext): Trim any redundant trailing slashes.
+
+ * src/names.c (name_next):
+ Don't assume '/' is the only directory separator.
+ (namelist_match): Likewise.
+ (add_hierarchy_to_namelist): Remove dirsize arg.
+ Do not assume '/' is the only directory separator.
+ (new_name): Likewise.
+
+ * lib/Makefile.am (noinst_HEADERS): Add dirname.h, full-write.h.
+ (libtar_a_SOURCES): Add dirname.c.
+
+ * src/create.c (relativize):
+ New function, with much of old start_header's guts.
+ Handle filesystem prefixes.
+ (start_header): Use this new function.
+ (init_sparsearray): Don't bother to zero out the new array;
+ it's not needed.
+ (deal_with_sparse): Fix array allocation bug.
+ (create_archive): Don't assume '/' is the only separator.
+ (dump_file): Likewise.
+ Don't worry about leading / in symlink targets.
+
+ * lib/savedir.c (savedir):
+ Remove size arg; it wasn't portable. All callers changed.
+
+ * lib/utime.c (utime_null): Adjust to new full_write convention.
+
+ * configure.in (YACC): Avoid portability problem with Ultrix sh.
+
+ * lib/backupfile.c: Include <dirname.h>.
+ (ISSLASH): New macro.
+ (find_backup_file_name): Use dirlen to calculate directory lengths.
+ (max_backup_version): Strip redundant trailing slashes.
+
+ * src/common.h: Include <full-write.h>.
+ (get_directory_contents): No longer has size arg.
+ (gnu_restore): Arg is size_t, not int.
+
+ * src/system.h: Include <time.h>.
+ (time): Declare if not defined.
+
+ * lib/full-write.c: Include full-write.h, not safe-read.h.
+ full_write returns size_t, with short writes meaning failure.
+ All callers changed.
+
+ * src/rtapelib.c: Include full-write.h.
+
+ * src/rmt.c: Include full-write.h.
+ (main): Update copyright.
+
+ * doc/getdate.texi: Mention that only English is supported.
+ Show how to use "date" so that the output is acceptable to getdate.
+ Mention Z as an abbreviation for UTC.
+
+ * lib/full-write.h: New file.
+
+ * src/list.c: system.h now does time.h stuff.
+
+ * lib/dirname.c:
+ Use HAVE_STDLIB_H, not STDC_HEADERS, to decide whether to include
+ stdlib.h.
+ Do not include string.h, strings.h, or assert.h; no longer needed.
+ (strrchr, memrchr, malloc): Remove decls; no longer needed.
+ Include <xalloc.h>.
+ (base_name): New decl.
+ (BACKSLASH_IS_PATH_SEPARATOR): Remove.
+ (dir_name_r): Remove.
+ (dirlen): New function.
+ (dir_name): Use dirlen instead of dir_name_r.
+ (<string.h>, <strings.h>): Include only if test program.
+ (main): Use "return 0", not "exit (0)".
+
+2000-12-08 Paul Eggert <eggert@twinsun.com>
+
+ * lib/dirname.h: New file.
+
+2000-11-02 Vesselin Atanasov <vesselin@bgnet.bg>
+
+ * lib/fnmatch.c: Do not comment out all the code if we are using
+ the GNU C library, because in some cases we are replacing buggy
+ code in the GNU C library itself.
+
+2000-10-30 Paul Eggert <eggert@twinsun.com>
+
+ * lib/fnmatch.c (FOLD): Do not assume that characters are unsigned.
+
+2000-10-29 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AC_INIT_AUTOMAKE): Version 1.13.18.
+
+ * src/tar.c: Include <fnmatch.h>, for FNM_LEADING_DIR.
+
+2000-10-28 Paul Eggert <eggert@twinsun.com>
+
+ * doc/tar.texi: --no-recursion now applies to extraction, too.
+ * src/create.c (dump_file): no_recurse_option -> ! recursion_option
+ * src/names.c (namelist_match, excluded_name):
+ Do not match subfiles of a directory
+ if --no-recursion is specified.
+ * src/tar.c (NO_RECURSE_OPTION): Remove.
+ (long_options): Have getopt set the --no-recursion flag.
+ (decode_options): Initialize recursion_option to FNM_LEADING_DIR.
+ Remove case for NO_RECURSE_OPTION.
+ * src/common.h (recursion_option):
+ Renamed from no_recurse_option, with sense
+ negated, and with FNM_LEADING_DIR being the nonzero value.
+
+ * names.c (namelist_match): New function.
+ (name_match, name_scan): Use it to eliminate duplicate code.
+ (names_notfound): Remove special case for Amiga.
+
+2000-10-27 Paul Eggert <eggert@twinsun.com>
+
+ * src/misc.c (read_error_details, read_warn_details,
+ read_fatal_details): Don't assume size_t is unsigned long.
+
+ * src/buffer.c (flush_read): If read_full_records_option, try to
+ fill the input buffer, as --delete -f - needs this.
+
+2000-10-24 Paul Eggert <eggert@twinsun.com>
+
+ * m4/strerror_r.m4 (AC_FUNC_STRERROR_R): Port to autoconf 2.13.
+
+ * src/buffer.c (check_label_pattern):
+ Make sure header name is a string before
+ passing it to fnmatch.
+ (init_volume_number): Check for global_volno overflow.
+ (new_volume): Check for global_volno overflow.
+
+ * src/tar.c (decode_options):
+ Check that volume label is not too long to overflow
+ name in tar header block.
+
+ * Makefile.am (EXTRA_DIST): Remove rebox.el.
+
+ * configure.in (HAVE_DECL_STRERROR_R): Remove our handwritten code.
+ (AC_FUNC_STRERROR_R): Use this instead.
+
+2000-10-23 Paul Eggert <eggert@twinsun.com>
+
+ * src/extract.c: Include <time.h>, since we invoke "time".
+
+ * lib/prepargs.c (prepend_default_options):
+ Don't use NULL, for portability.
+
+ * m4/fnmatch.m4: Add "working" to message.
+
+ * src/names.c: (_GNU_SOURCE): Remove; autoconf now does this.
+ Include <hash.h>.
+ (getpwuid, getgrgid): Declare only if system headers don't.
+ (gid_to_gname): Don't invoke setgrent.
+ (namelist): Now static, not global.
+ (nametail): New var. All uses of namelast changed to use
+ nametail, with one extra level of indirection.
+ (name_gather): Use memcpy instead of strncpy + assignment of NUL.
+ (name_match): Set nametail too, when setting namelist to null.
+ (add_hierarchy_to_namelist): Change type of dir arg from char * to
+ struct name *, so that we don't have to look up the name again
+ here. Get change_dir from dir rather than as a separate arg. Add
+ dirsize arg, and pass it along to get_directory_contents. Remove
+ unnecessary check of directory type.
+ (new_name): Do not append a slash if PATH already ends in one.
+ (avoided_names, struct avoided_name): Remove.
+ (avoided_name_table): New var, replacing avoided_names.
+ (hash_avoided_name, compare_avoided_names): New function.
+ (add_avoided_name, is_avoided_name): Use hash table rather than
+ linked list.
+
+ * src/buffer.c (_GNU_SOURCE): Remove; autoconf now does this.
+ (child_open_for_compress, child_open_for_uncompress,
+ close_archive): Propagate any failure of the compression process
+ back to "tar".
+ (open_archive, flush_write, flush_read, close_archive): Do not
+ allocate an array of size PATH_MAX, as PATH_MAX might be (size_t)
+ -1. Instead, allocate an array with the size that's needed.
+ (open_archive): Don't bother checking S_ISCHR of /dev/null.
+ (backspace_output): Don't try to backspace past start of archive.
+ (close_archive): Remove special case for DELETE_SUBCOMMAND.
+
+ * acconfig.h (_GNU_SOURCE, DEFAULT_ARCHIVE, DEFAULT_BLOCKING,
+ DENSITY_LETTER, DEVICE_PREFIX, EMUL_OPEN3, HAVE_GETGRGID,
+ HAVE_GETPWUID, HAVE_MKNOD, HAVE_RTAPELIB, HAVE_ST_FSTYPE_STRING,
+ HAVE_UNION_WAIT, HAVE_UTIME_H, HAVE_VALLOC, MTIO_CHECK_FIELD, PACKAGE,
+ PROTOTYPES, REMOTE_SHELL, STD_INC_PATH, VERSION, WITH_CATALOGS,
+ WITH_DMALLOC, WITH_REGEX):
+ Remove; now generated automatically.
+
+ * configure.in (_GNU_SOURCE): Define to empty, not 1, for
+ compatibility for glibc fragments.
+ (_GNU_SOURCE, HAVE_UTIME_H, MTIO_CHECK_FIELD,
+ HAVE_ST_FSTYPE_STRING, HAVE_MKNOD, REMOTE_SHELL, DENSITY_LETTER,
+ DEVICE_PREFIX, DEFAULT_ARCHIVE, DEFAULT_BLOCKING): Add comment so
+ that we needn't put an entry into acconfig.h.
+ (ALL_LINGUAS): Add da.
+ (AC_C_BACKSLASH_A): Remove; jm_PREREQ_QUOTEARG now does this.
+ (AC_CHECK_HEADERS): Add stdbool.h (for hash.h users), wctype.h
+ (for strtol.c).
+ (AC_MBSTATE_T): Add.
+ (RMT): Append $(EXEEXT).
+ (HAVE_GETGRGID, HAVE_GETPWUID, pe_AC_TYPE_SIGNED_CHAR): Remove.
+ (HAVE_DECL_FREE, HAVE_DECL_GETGRGID, HAVE_DECL_GETPWUID,
+ HAVE_DECL_GETENV, HAVE_DECL_MALLOC, HAVE_DECL_STRTOUL,
+ HAVE_DECL_STRTOULL, HAVE_DECL_STRERROR_R): New macros.
+ (jm_PREREQ_ADDEXT, jm_PREREQ_ERROR, jm_PREREQ_QUOTEARG): Add.
+ (AC_REPLACE_FUNCS): Remove execlp; no longer needed.
+ (AC_CHECK_FUNCS): Add clock_gettime; AC_SEARCH_LIBS wasn't enough.
+ Remove mbrtowc; jm_PREREQ_QUOTEARG now does this.
+ (EMUL_OPEN3): Remove; no longer needed.
+ (DENSITY_LETTER, DEVICE_PREFIX): Simplify m4 quoting.
+
+ * m4/fnmatch.m4 (AC_FUNC_FNMATCH): Detect d*/*1 vs d/s/1 bug.
+
+ * src/common.h: Do not include basename.h.
+ * src/rtapelib.c (base_name): Do not include basename.h;
+ declare base_name instead.
+
+ * lib/basename.h, lib/execlp.c, lib/getpagesize.h, lib/mkdir.c:
+ Remove these files.
+ * lib/getstr.c, lib/getstr.h, lib/hash.h, lib/hash.h, lib/prepargs.c,
+ lib/prepargs.h, lib/savedir.c, lib/savedir.h: New files.
+ * lib/Makefile.am (EXTRA_DIST, noinst_HEADERS, libtar_a_SOURCES):
+ Adjust to the above changes.
+
+ * lib/Makefile.am (AUTOMAKE_OPTIONS): Remove ../src/ansi2knr.
+
+ * src/open3.c: Remove.
+
+ * src/Makefile.am (AUTOMAKE_OPTIONS): Remove ansi2knr.
+ (tar_SOURCES): Remove open3.c.
+ (INCLUDES): Remove -I.., as automake does that.
+ (OMIT_DEPENDENCIES): ../lib/fnmatch.h -> fnmatch.h. Add localedir.h.
+
+ The following changes are to put LOCALEDIR into localedir.h instead
+ of passing it on the command line.
+ (DEFS): Remove.
+ (DISTCLEANFILES): New macro.
+ (localedir.h): New rule.
+ (rmt.o tar.o): Now depend on localedir.h.
+
+ * tests/delete02.sh, tests/extrac04.sh: New files.
+
+ * tests/Makefile.am (AUTOMAKE_OPTIONS): Remove ansi2knr.
+ (TESTS): Add extrac04.sh, and restore delete02.sh.
+ (DEFS): Remove; LOCALEDIR is now done via localedir.h.
+ (INCLUDES): Remove -I.. as automake does this now.
+
+ * src/rtapelib.c (rexec): Don't declare unless using it.
+ (do_command): Simplify signal-handling code slightly.
+
+ * src/delete.c (blocks_needed): Remove. All uses changed to use
+ blocking_factor - new_blocks.
+ (acting_as_filter): New var.
+ (write_record, delete_archive_members): Use acting_as_filter
+ rather than archive == STDIN_FILENO to detect whether we're acting
+ as a filter, as open can return STDIN_FILENO in some cases.
+ (delete_archive_members): Ignore zero blocks if
+ ignore_zeros_option is nonzero. Fix bug that messed up last
+ output block: write_eot can't be used here, as it gets confused
+ when the input is at end of file.
+
+ * src/compare.c (diff_archive): Do not impose an arbitrary limit on
+ symbolic link contents length. Pass directory size to
+ get_directory_contents.
+
+ * m4/decl.m4, m4/error.m4, m4/mbstate_t.m4, m4/prereq.m4,
+ m4/strerror_r.m4: New files.
+ * m4/signedchar.m4: Remove this file.
+ * Makefile.am (ACINCLUDE_INPUTS): Adjust to above changes.
+ * m4/Makefile.am (EXTRA_DIST): Likewise.
+
+ * Makefile.am (DISTCLEANFILES): Add intl/libintl.h.
+
+ * po/da.po: New translation file.
+
+ * src/mangle.c (extract_mangle):
+ Fix diagnostic with wrong number of %s'es.
+
+ * lib/fnmatch.c (fnmatch):
+ Fix some FNM_FILE_NAME and FNM_LEADING_DIR bugs,
+ e.g. fnmatch("d*/*1", "d/s/1", FNM_FILE_NAME) incorrectly yielded zero.
+
+ * lib/full-write.c (full_write): Some buggy drivers return 0 when you
+ fall off a device's end. Detect this.
+
+ * src/system.h (IN_CTYPE_DOMAIN): Renamed from CTYPE_DOMAIN. All
+ uses changed.
+ (open): Remove macro; we no longer support EMUL_OPEN3. Do not
+ include <pathmax.h> and directory include files like <dirent.h>;
+ no longer used. Include <savedir.h> instead.
+ (closedir, signed_char): remove macro; no longer used.
+ (bool, false, true): Include <stdbool.h> if you have the include
+ file, otherwise define.
+
+ * src/misc.c:
+ (is_dot_or_dotdot, closedir_error, closedir_warn, opendir_error,
+ opendir_warn, readdir_error): Remove; no longer needed.
+ (safer_rmdir): Strip leading ./ (or .// or ./// or ././ or etc.)
+ before deciding whether we're trying to remove ".".
+ (remove_any_file): Try unlink first if we are not root. Use
+ savedir when recursively removing directories, to avoid exhausting
+ file descriptors.
+ (savedir_error, savedir_warn, symlink_error): New functions.
+
+ * src/list.c: (read_and): Do not invoke
+ apply_nonancestor_delayed_set_stat; DO_SOMETHING is now
+ responsible for that. Do not invoke apply_delayed_set_stat; our
+ caller is now responsible for that.
+ (read_header): Use signed char instead of signed_char. Prevent
+ later references to current_header from mistakenly treating it as
+ an old GNU header.
+ (from_header): Quote invalid base-64 strings in diagnostics.
+ (time_from_header): Do not warn about future timestamps in
+ archive; check_time now does that.
+ (print_header): Quote unknown file types.
+ (skip_member): New function, replacing skip_extended_headers and
+ now skipping the whole member instead of just the extended
+ headers. All callers changed. This makes the code handle
+ extended headers uniformly, and fixes some bugs.
+
+ * src/update.c (update_archive): Use skip_member.
+
+ * src/extract.c (we_are_root): Now global.
+ (struct delayed_symlink): New type.
+ (delayed_symlink_head): New var.
+ (extr_init, fatal_exit): Invoke extract_finish on fatal errors,
+ not apply_delayed_set_stat.
+ (set_mode, set_stat): Pointer args are now const pointers.
+ (check_time): New function.
+ (set_stat): Warn if setting a file's timestamp to be the future.
+ (make_directories): Do not save and restore errno.
+ (maybe_recoverable): Set errno to ENOENT if we cannot make missing
+ intermediate directories.
+ (extract_archive): Invoke apply_nonancestor_delayed_set_stat here,
+ not in caller. Extract potentially dangerous symbolic links more
+ carefully, deferring their creation until the end, and using a
+ regular file placeholder in the meantime. Do not remove trailing
+ / and /. from file names. Do not bother checking for ".." when
+ checking whether a directory loops back on itself, as loopbacks
+ can occur with symlinks too. Also, in that case, do not bother
+ saving and restoring errno; just set it to EEXIST.
+ (apply_nonancestor_delayed_set_stat): A prefix is a potential
+ ancestor if it ends in slash too (as well as ending in a char just
+ before slash).
+ (apply_delayed_set_stat): Remove.
+ (apply_delayed_symlinks, extract_finish): New functions.
+
+ * doc/fdl.texi: New file.
+ * doc/Makefile.am (EXTRA_DIST): Add fdl.texi.
+ ($(srcdir)/tar.info): Add fdl.texi. Invoke makeinfo with --no-split.
+ * doc/tar.texi: Add Free Documentation License. New section
+ "Overwrite Old Files", and revamp that section to make it easier to
+ follow. "tar" -> "GNU tar" where appropriate. Migrate getdate
+ documentation into getdate.texi. Fix several minor typos. Describe
+ TAR_OPTIONS. Describe incompatibility between incremental backups and
+ --atime-preserve. Describe incompatibility between --verify and other
+ options. Mention that tar normally removes symbolic links rather than
+ following them, when extracting a file of the same name.
+
+ * THANKS: Add gpoul. Change skip's address.
+
+ * po/POTFILES.in: Add lib/human.c.
+
+ * src/common.h (namelist, namelast): Remove decls.
+ (we_are_root, extract_finish, skip_member, savedir_error,
+ savedir_warn, symlink_error, gnu_list_name): New decls.
+ (apply_delayed_set_stat, apply_nonancestor_delayed_set_stat,
+ skip_extended_headers, is_dot_or_dotdot, closedir_error,
+ closedir_warn, opendir_error, opendir_warn, readdir_error,
+ readdir_warn): Remove decls.
+ (get_directory_contents): New off_t arg.
+ (addname): Now returns struct name *.
+
+ * src/tar.h, tests/genfile.c: Fix comments.
+
+ * src/create.c: Include hash.h.
+ (gnu_list_name): Remove decl.
+ (struct link): Remove "next" member.
+ (linklist): Remove.
+ (start_header): Say "leading `FOO'" rather than "`FOO' prefix" for
+ consistency with other diagnostics.
+ (deal_with_sparse): Check for I/O error when closing the file.
+ (create_archive): Do not allocate an array of size PATH_MAX, as
+ PATH_MAX might be (size_t) -1. Instead, allocate an array with
+ the size that's needed.
+ (hash_link, compare_links): New functions.
+ (dump_file): Do not exhaust open file descriptors when descending
+ deeply into a directory, by using savedir rather than
+ opendir/readdir. Do not zero-fill the name buffer unnecessarily.
+ Hash the set of links already created, instead of using a linked
+ list. Fix some bugs in outputting sparse files which caused the
+ sparse tables to be incorrect. When a file unexpectedly shrinks,
+ output zeros rather than garbage. Do not allocate an array of
+ size PATH_MAX, as PATH_MAX might be (size_t) -1. Instead,
+ allocate an array with the size that's needed.
+
+ * src/incremen.c: Include hash.h.
+ (struct directory): Remove "next", "dir_text". Change "name" to
+ be char[1] with struct hack, not const char *. Add "found".
+ (directory_list): Remove. Replaced by directory_table.
+ (directory_table): New var.
+ (nfs_string): Renamed from nfs.
+ (hash_directory, compare_directories): New functions.
+ (note_directory): Now returns struct directory *. First arg is
+ now const pointer. struct stat arg is now dev_t, ino_t, nfs.
+ Remove text arg. New "found" arg, basically corresponding to the
+ old text arg not being null. All callers changed.
+ (note_directory, find_directory): Use hash table rather than
+ linked list.
+ (get_directory_contents): New arg "device". Use savedir to do the
+ hard work. Save the nfs-ness of stat_data, since it might change
+ under us. Use note_directory instead of find_directory to save
+ some work. When adding an "A" record, do it with
+ add_to_accumulator instead of cheating with strcat.
+ (read_directory_file): Use "+" flag before device to indicate
+ whether it was NFS. Fix typo in checking for strtoul error.
+ (write_directory_file_entry): New function.
+ (write_directory_file): Use it, and use the hash routines to
+ traverse the directory table.
+ (gnu_restore): Use savedir rather than opendir/readdir.
+
+ * src/tar.c: Include localedir.h, prepargs.h.
+ (long_options): Now static.
+ (long_options, usage, decode_options): -j is now short for
+ --bzip2, and -I is now an alias for -T.
+ (decode_options, main): argv is not const pointer now.
+ (decode_options): Invoke prepend_default_options to support
+ TAR_OPTIONS. In diagnostic, mention the string that was the
+ invalid blocking factor, tape length, group, owner, or record
+ size. --delete is no longer incompatible with -f -, undoing
+ 2000-01-07 change.
+ (main): Invoke extract_finish at end of extraction.
+
+ * src/rmt.c: Include localedir.h.
+ (main): Update copyright date to 2000.
+
+ * doc/getdate.texi: New file, taken from fileutils 4.0.27, with the
+ following changes: Use @sc where appropriate. Document the ranges of
+ supported times more precisely. Add Eggert to getdate authors.
+ Document old Latin 12m/12pm tradition. Remove list of alphabetic time
+ zone names, as it wasn't correct and people shouldn't be relying on it
+ anyway. Relative items also account for non-DST adjustments. Fix
+ some misspellings.
+
+ * lib/prepargs.c, lib/prepargs.h, tests/extrac04.sh: New file.
+
+ * tests/ignfail.sh: opendir -> savedir in diagnostics.
+
+ * tests/preset.in: Set LANGUAGE to the empty string, for some
+ brain damaged host.
+
+2000-10-20 Paul Eggert <eggert@twinsun.com>
+
+ * m4/fnmatch.m4: Mention the GNU C library.
+
+2000-10-19 Paul Eggert <eggert@twinsun.com>
+
+ * m4/fnmatch.m4: Add a couple more test cases to catch bugs in
+ glibc 2.1.95.
+
+2000-10-17 Paul Eggert <eggert@twinsun.com>
+
+ * lib/human.c (<limits.h>): Do not include; human.h does it if needed.
+ (CHAR_BIT): Remove.
+
+ * lib/human.h (<limits.h>): Include if HAVE_LIMITS_H.
+ (CHAR_BIT): Define if not defined.
+
+2000-09-09 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c: From fileutils: rename ISASCII to IN_CTYPE_DOMAIN.
+
+2000-08-07 Paul Eggert <eggert@twinsun.com>
+
+ * lib/xmalloc.c: Memory exhausted -> memory exhausted
+
+ * lib/xalloc.h (xalloc_msg_memory_exhausted):
+ change to array from char *.
+
+2000-08-06 Paul Eggert <eggert@twinsun.com>
+
+ * m4/mbstate_t.m4: Define mbstate_t to be int, not char, for
+ compatibility with glibc 2.1.3 strftime.c.
+
+2000-07-31 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c (quotearg_n_options):
+ Don't make the initial slot vector a constant,
+ since it might get modified.
+
+ * lib/quotearg.c: Add support for more than one preallocated slot.
+
+2000-07-30 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c (quotearg_n_options):
+ Preallocate a slot 0 buffer, so that the caller
+ can always quote one small component of a "memory exhausted" message
+ in slot 0.
+
+2000-07-23 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c:
+ Include <wchar.h> even if ! (HAVE_MBRTOWC && 1 < MB_LEN_MAX), so that
+ mbstate_t is always defined.
+
+ Do not inspect MB_LEN_MAX, since it's incorrectly defined to be 1 in
+ some GCC installations, and this configuration error is likely to be
+ common.
+
+2000-07-22 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c:
+ When the system forces us to redefine mbstate_t, shadow its mbsinit
+ function. From Bruno Haible.
+
+2000-07-14 Paul Eggert <eggert@twinsun.com>
+
+ * lib/xmalloc.c: Simplify exhausted message.
+
+ * lib/quotearg.h: Update copyright date; from Jim Meyering.
+
+2000-07-13 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.h (enum quoting style):
+ New constant clocale_quoting_style.
+
+ * lib/quotearg.c:
+ (quoting_style_args, quoting_style_vals, quotearg_buffer_restyled):
+ Add support for clocale_quoting_style, undoing previous change to
+ locale_quoting_style.
+
+2000-07-10 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c:
+ <wchar.h>: Include only if HAVE_MBRTOWC && 1 < MB_LEN_MAX,
+ since otherwise we don't need it.
+ (MB_CUR_MAX): Redefine to 1 if ! (HAVE_MBRTOWC && 1 < MB_LEN_MAX),
+ since we don't do multibytes in that case.
+ (quotearg_buffer_restyled): If a unibyte locale, don't bother to
+ invoke multibyte primitives.
+
+ * m4/mbstate_t.m4 (AC_MBSTATE_T):
+ Renamed from AC_MBSTATE_T_OBJECT. All uses changed.
+ Change from a two-part test, which defines both HAVE_MBSTATE_T_OBJECT
+ and mbstate_t, to a single-part test that simply defines mbstate_t.
+
+ * lib/quotearg.c (mbrtowc): Do not use HAVE_WCHAR_H in the definition.
+ Use defined mbstate_t, not HAVE_MBSTATE_T_OBJECT,
+ to decide whether to define the BeOS workaround macro;
+ this adjusts to the change to AC_MBSTATE_T.
+
+ * m4/strerror_r.m4: New file.
+
+2000-07-05 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c: Use double-quote to quote.
+
+ * lib/quotearg.c (N_): New macro.
+ (gettext_default): New function.
+ (quotearg_buffer_restyled): Use gettext_default ("{LEFT QUOTATION MARK}",
+ "\"") for left quote, and gettext_default ("{RIGHT QUOTATION MARK}", "\"")
+ for right quote.
+
+ * lib/quotearg.c (struct quoting_options):
+ Simplify quote_these_too dimension.
+ From Bruno Haible <haible@clisp.cons.org>.
+
+ * m4/mbstate_t.m4 (AC_MBSTATE_T_OBJECT):
+ Test for mbstate_t only if the test
+ for an object-type mbstate_t fails.
+
+ * lib/quotearg.c (mbrtowc): Declare returned type, since BeOS doesn't.
+
+2000-07-03 Paul Eggert <eggert@twinsun.com>
+
+ * m4/mbstate_t.m4 (AC_MBSTATE_T_OBJECT): Port to autoconf 2.13.
+ Add AC_CHECK_HEADERS(stdlib.h), since we use HAVE_STDLIB_H.
+
+ * lib/quotearg.c (mbrtowc):
+ Assign to *pwc, and return 1 only if result is nonzero.
+ (iswprint): Define to ISPRINT if we are substituting our own mbrtowc.
+
+2000-07-02 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c (mbstate_t):
+ Do not define; it should be defined with AC_CHECK_TYPE.
+
+2000-06-26 Paul Eggert <eggert@twinsun.com>
+
+ * m4/mbstate_t.m4: Include stdio.h before wchar.h, to work around
+ a bug in glibc 2.1.3.
+
+ * lib/xmalloc.c: Fix inaccorate comment for xrealloc.
+
+2000-06-19 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c (ISASCII): Add #undef and move definition to follow
+ inclusion of wctype.h to work around solaris2.6 namespace pollution.
+ (ISPRINT): Likewise.
+ Reported by Tom Tromey.
+
+2000-06-15 Paul Eggert <eggert@twinsun.com>
+
+ * lib/human.c (adjust_value): New function.
+ (human_readable_inexact): Apply rounding style even when printing
+ approximate values.
+
+ * lib/human.c: Avoid shadowing warnings.
+ From Jim Meyering.
+
+2000-06-14 Paul Eggert <eggert@twinsun.com>
+
+ * lib/human.c (human_readable_inexact): Allow an input block size
+ that is not a multiple of the output block size, and vice versa.
+
+ * lib/getdate.y (get_date): Apply relative times after time zone
+ indicator, not before.
+
+2000-05-31 Paul Eggert <eggert@twinsun.com>
+
+ * m4/largefile.m4: Rewrite so that we don't need to run getconf,
+ and thus don't need AC_CANONICAL_HOST.
+
+ (AC_SYS_LARGEFILE_FLAGS, AC_SYS_LARGEFILE_SPACE_APPEND): Remove.
+ (AC_SYS_LARGEFILE_TEST_INCLUDES): New macro.
+ (AC_SYS_LARGEFILE_MACRO_VALUE): Change arguments from
+ CODE-TO-SET-DEFAULT to VALUE, INCLUDES, FUNCTION-BODY. All uses
+ changed. Instead of inspecting the output of getconf, try to
+ compile the test program without and with the macro definition.
+ (AC_SYS_LARGEFILE): Do not require AC_CANONICAL_HOST or check for
+ getconf. Instead, check for the needed flags by compiling test
+ programs.
+
+ * configure.in (AC_CANONICAL_HOST): Remove; the largefile stuff no
+ longer needs it.
+ * config.guess, config.sub: Remove these files, for similar reasons.
+
+2000-05-03 Paul Eggert <eggert@twinsun.com>
+
+ * m4/largefile.m4 (AC_SYS_LARGEFILE): Define _XOPEN_SOURCE to be
+ 500, instead of _GNU_SOURCE to be 1, to work around glibc 2.1.3
+ bug. This avoids a clash when files like regex.c that define
+ _GNU_SOURCE.
+
+2000-05-02 Paul Eggert <eggert@twinsun.com>
+
+ * m4/largefile.m4 (AC_SYS_LARGEFILE):
+ Define _GNU_SOURCE if this is needed to make
+ ftello visible (e.g. glibc 2.1.3). Use compile-time test, rather than
+ inspecting host and OS, to decide whether to define _LARGEFILE_SOURCE.
+
+ * lib/quotearg.c (mbrtowc, mbstat_t):
+ Add definitions if !HAVE_MBSTATE_T_OBJECT.
+ (<wctype.h>): Include if HAVE_WCTYPE_H.
+ (iswprint): Define to 1 if we lack it
+
+2000-04-18 Paul Eggert <eggert@twinsun.com>
+
+ * m4/mbstate_t.m4: New file.
+
+2000-04-17 Bruno Haible <haible@clisp.cons.org>
+
+ * tests/ignfail.sh: Test for uid 0 along with user "root".
+
+2000-04-05 Paul Eggert <eggert@twinsun.com>
+
+ * m4/largefile.m4 (AC_SYS_LARGEFILE_FLAGS):
+ Don't use -n32 on IRIX if the installer said
+ otherwise.
+
+2000-02-28 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c (ALERT_CHAR): New macro.
+ (quotearg_buffer_restyled): Use it.
+
+2000-02-23 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+
+ * src/list.c (tartime): Fix off-by-one error when copying year if
+ OLD_CTIME.
+
+2000-02-18 Paul Eggert <eggert@twinsun.com>
+
+ * lib/getdate.y: Handle two-digit years with leading zeros correctly.
+ (textint): New typedef.
+ (parser_control): Changed from struct parser_control to typedef
+ (for consistency). Member year changed from int to textint. All
+ uses changed.
+ (YYSTYPE): Removed; replaced by %union with int and textint
+ members.
+ (tID): Removed; not used.
+ (tDAY, tDAY_UNIT, tDAYZONE, tHOUR_UNIT, tID, tLOCAL_ZONE,
+ tMERIDIAN, tMINUTE_UNIT, tMONTH, tMONTH_UNIT tSEC_UNIT, tSNUMBER,
+ tUNUMBER, tYEAR_UNIT, tZONE, o_merid): Now of type <intval>.
+ (tSNUMBER, tUNUMBER): Now of type <textintval>.
+ (date, number, to_year): Use width of number in digits, not its
+ value, to determine whether it's a 2-digit year, or a 2-digit
+ time.
+ (yylex): Store number of digits of numeric tokens. Return '?' for
+ unknown identifiers, rather than (unused) tID.
+
+2000-01-16 Paul Eggert <eggert@twinsun.com>
+
+ * lib/quotearg.c (quotearg_buffer_restyled):
+ Do not quote alert, backslash, formfeed,
+ and vertical tab unnecessarily in shell quoting style.
+
+2000-01-15 Paul Eggert <eggert@twinsun.com>
+
+ * m4/c-bs-a.m4:
+ Change quoting to be compatible with future autoconf versions.
+
+2000-01-11 Paul Eggert <eggert@twinsun.com>
+
+ * lib/exclude.c (FILESYSTEM_PREFIX_LEN, ISSLASH): Remove unused macros.
+
+2000-01-07 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AC_INIT_AUTOMAKE): Version 1.13.17.
+
+ Fix bug with fnmatch.h dependency, as follows:
+ * src/Makefile.am (OMIT_DEPENDENCIES): New macro.
+ * lib/Makefile.am (OMIT_DEPENDENCIES): New macro.
+
+ * src/common.h (apply_nonancestor_delayed_set_stat):
+ Renamed from apply_delayed_set_stat.
+ (apply_delayed_set_stat, decode_mode, chmod_error_details,
+ chown_error_details, close_warn, closedir_warn, mkdir_error,
+ read_error_details, read_fatal_details, read_warn_details,
+ seek_error_details, seek_warn_details, utime_error,
+ write_error_details, write_fatal_details): New decls.
+
+ Make diagnostic messages more regular.
+ * src/create.c (dump_file): Quote file names with colons if possible.
+ * src/compare.c (diff_archive): Likewise.
+ * src/extract.c (repair_delayed_set_stat, extract_archive): Likewise.
+ * src/incremen.c (get_directory_contents, gnu_restore): Likewise.
+ * src/mangle.c (extract_mangle): Likewise.
+ * src/misc.c (call_arg_error, call_arg_fatal, call_arg_warn):
+ Likewise.
+ * src/buffer.c (archive_write_error, flush_archive, close_archive,
+ new_volume, xclose):
+ Use error message functions to report errors consistently.
+ * src/compare.c (diff_sparse_files, diff_archive): Likewise.
+ * src/create.c (finish_sparse_file, dump_file): Likewise.
+ * src/extract.c (set_mode, set_stat, extract_sparse_file,
+ extract_archive): Likewise.
+ * src/list.c (list_archive): Likewise.
+ * src/update.c (append_file): Likewise.
+ * src/compare.c (diff_init, diff_sparse_files):
+ Use xalloc_die to report memory exhaustion.
+ * src/incremen.c (gnu_restore): Likewise.
+ * src/list.c (read_header): Likewise.
+ * src/mangle.c (extract_mangle): Likewise.
+ * src/misc.c (maybe_backup_file): Likewise.
+ * src/tar.c (decode_options): Likewise.
+ * src/compare.c (read_and_process, fill_in_sparse_array,
+ diff_sparse_files):
+ Use consistent terminology for unexpected-EOF message.
+ * src/extract.c (extract_sparse_file, extract_archive): Likewise.
+ * src/list.c (list_archive, read_header, skip_file,
+ skip_extended_headers): Likewise.
+ * src/buffer.c (archive_write_error): Add noreturn attribute to decl.
+ (xdup2): Regularize messages with rest of tar.
+
+ * src/buffer.c (flush_read): Don't read past EOF.
+
+ * src/extract.c (extr_init):
+ If we run out of memory, invoke apply_delayed_set_stat.
+ (prepare_to_extract): Don't complain if we can't remove ".".
+ (apply_delayed_set_stat): New function.
+ (apply_nonancestor_delayed_set_stat):
+ Renamed from apply_delayed_set_stat. All uses changed.
+ Don't remove head if it doesn't apply.
+
+ * src/create.c (find_new_file_size):
+ Return size instead of storing through pointer.
+ All callers changed.
+ (deal_with_sparse): Don't keep reading after read errors.
+ (finish_sparse_file): Just abort if there is an internal error.
+ (dump_file): Fix typo: stat_warn and stat_error were interchanged.
+ Don't restore access times on directories during incremental dumps
+ until after dealing with the directory.
+ If ignoring failed reads, count closedir, read, and unknown
+ file errors as warnings, not errors.
+ Fix buffer overrun problem when dumping sparse files.
+
+ * src/list.c (read_and):
+ Invoke apply_nonancestor_delayed_set_stat on file names
+ after handling them.
+ (decode_mode): Remove; moved to misc.c.
+
+ * src/misc.c (safer_rmdir): New function.
+ (remove_any_file): Use it to avoid problems with rmdir(".").
+ (maybe_backup_file): Regularize diagnostics.
+ (undo_backup_file): Likewise.
+ (decode_mode): Moved here from list.c.
+ (chmod_error_details, chown_error_details, close_fatal,
+ close_warn, closedir_warn, mkdir_error, read_error_details,
+ read_warn_details, read_fatal_details, seek_error_details,
+ seek_warn_details, utime_error, write_error_details,
+ write_fatal_details): New functions.
+
+ * src/delete.c (save_record): Remove static variable (now local).
+ (move_archive): Don't position before start of archive.
+ (write_record): Abort if count is zero at inopportune time.
+ Plug memory leak.
+
+ * src/tar.c (decode_options): --delete and -f - are now
+ incompatible, since we didn't have time to fix their bugs.
+
+ * tests/Makefile.am (TESTS): Remove delete02.sh.
+ * tests/ignfail.sh: Adjust to new quoting scheme again.
+
+2000-01-06 Paul Eggert <eggert@twinsun.com>
+
+ * lib/getdate.y: Sync tm_diff with the GNU C Library.
+ (TM_YEAR_BASE): Renamed from TM_YEAR_ORIGIN. All uses changed.
+ (tm_diff): Renamed from difftm. All uses changed.
+ Replace body with that taken from GNU C Library 2.1.3pre1.
+ (get_date): Prefer tm_gmtoff to tm_diff if available.
+
+1999-12-29 "Melissa O'Neill" <oneill@cs.sfu.ca>
+
+ * tests/incremen.sh: Invoke stat on newly created file so that its
+ ctime is updated on Nextstep.
+
+1999-12-21 Machael Stone <mstone@cs.loyola.edu>
+
+ * lib/getdate.y (get_date):
+ Fix typo when checking for time_t overflow in time zone calculations.
+
+1999-12-13 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AC_INIT_AUTOMAKE): Version 1.13.16.
+
+ * README-alpha: New file.
+ * README: New sections for gzip and bzip2, Solaris.
+ Remove mention of BACKLOG.
+
+ * configure.in (AC_C_BACKSLASH_A): Add.
+ (AC_CHECK_HEADERS): Add wchar.h.
+ (AC_CHECK_FUNCS): Add mbrtowc.
+ (AC_FUNC_CLOSEDIR_VOID): Add.
+
+ * tests/Makefile.am (TESTS): Add delete02.sh.
+ (POSTPONED_TESTS): Remove.
+ (EXTRA_DIST): Remove $(POSTPONED_TESTS).
+
+ * tests/preset.in:
+ Set LC_ALL rather than LANGUAGE, LANG, and LC_MESSAGES.
+
+ * tests/ignfail.sh (err): Adjust to new quoting scheme.
+
+ * tests/delete02.sh: Fix typo: need to list archive2, not archive.
+
+ * tests/extrac03.sh: Use -P option, so that .. doesn't get diagnosed.
+
+ * src/tar.c ("quotearg.h"): New include.
+ (usage): Now has __attribute__ ((noreturn)).
+ (confirm): Report errno if we can't open tty.
+ (confirm, decode_options):
+ Quote arbitrary strings in diagnostics.
+ (OVERWRITE_OPTION): New constant.
+ (long_options, usage, decode_options): New --overwrite option.
+ (decode_options): --keep-old-files, --overwrite, and --unlink-first
+ are now mutually exclusive.
+ Don't assume that gettext preserves errno.
+ (main): Set default quoting style to escape_quoting_style.
+
+ * src/update.c (<quotearg.h>): New include.
+ (append_file):
+ Don't assume that gettext preserves errno.
+ Quote arbitrary strings in diagnostics.
+ Check for close error.
+
+ * src/names.c (<quotearg.h>): New include.
+ (name_init, name_next, name_close, names_notfound,
+ collect_and_sort_names): Don't assume that gettext preserves
+ errno. Quote arbitrary strings in diagnostics.
+ (excluded_name): Fix typo that caused empty patterns to be
+ mishandled.
+
+ * src/misc.c (<quotearg.h>): New include.
+ (quote_copy_string): Quote only newline and backslash; the output is no
+ longer meant for humans, and is locale-independent.
+ (contains_dot_dot): New function.
+ (remove_any_file): Don't use lstat; just rmdir the file and then use
+ unlink if the rmdir fails because the file isn't a directory.
+ Check for readdir and closedir errors.
+ (maybe_backup_file): Report "stat" for stat errors.
+ (maybe_backup_file, chdir_do):
+ Quote arbitrary strings in diagnostics.
+ (maybe_backup_file, undo_last_backup):
+ Don't assume that gettext preserves errno.
+ (call_arg_error, call_arg_fatal, call_arg_warn,
+ chdir_fatal, close_error, closedir_error, exec_fatal, mkfifo_error,
+ mknod_error, open_error, open_fatal, open_warn, opendir_error,
+ opendir_warn, read_error, read_fatal, readdir_error, readdir_warn,
+ readlink_error, readlink_warn, seek_error, seek_warn, stat_error,
+ stat_warn, truncate_error, truncate_warn, unlink_error, waitpid_error,
+ write_error, write_fatal, xfork, xpipe, quote_n, quote): New functions.
+
+ * src/system.h (__attribute__): New macro.
+ (O_NDELAY, O_NONBLOCK, O_APPEND): Remove.
+ (S_ISDOOR): New macro.
+ (closedir): New macro, if CLOSEDIR_VOID.
+
+ * src/rmt.c, src/rtapelib.c (decode_oflag):
+ O_APPEND might not be defined.
+
+ * src/list.c: (read_and, list_archive):
+ Quote arbitrary strings in diagnostics.
+ (from_header): Use locale_quoting_style to quote diagnostics.
+ (print_header, print_for_mkdir): Quote with quotearg, not quote_copy_string.
+
+ * src/rmt.h (REM_BIAS): Increase from 128 to (1 << 30).
+
+ * src/Makefile.am: Use ## for copyright comments.
+
+ * src/extract.c (<quotearg.h>): New include.
+ (enum permstatus): New enum.
+ (struct delayed_set_stat): file_name is now at end of buffer, to avoid
+ two mallocs. New members file_name_len, invert_permissions, permstatus.
+ (extr_init): Remove hack that silently adjusted newdir_umask.
+ (set_mode, set_stat): New args invert_permissions, permstatus, typeflag.
+ Use these args to decide whether and how to set modes.
+ (set_mode, set_stat, prepare_to_extract, extract_sparse_file, extract_archive):
+ Don't assume that gettext preserves errno.
+ (set_stat): Remove arg symlink_flag; subsumed by typeflag.
+ (delay_set_stat, repair_delayed_set_stat): New functions.
+ (make_directories): Avoid mkdir where last part of path is "..".
+ Create a struct delayed_set_stat for each directory made.
+ (prepare_to_extract): Renamed from unlink_destination, and
+ return 0 immediately if to_stdout_option; all callers changed.
+ (maybe_recoverable): New parameter interdir_made.
+ Add support for --overwrite.
+ (extract_sparse_file, extract_archive):
+ Quote arbitrary strings in diagnostics.
+ (extract_archive): By default, warn about ".." in member names, and skip them.
+ Don't open files with O_NONBLOCK or O_APPEND.
+ Open with O_TRUNC only if --overwrite; otherwise, use O_EXCL to avoid
+ overwriting them. Pass only rwxrwxrwx permissions to `open' and `mkdir',
+ minus the current umask. Keep track of intermediate directories made,
+ to avoid looping when making x/../x when x doesn't exist; the
+ earlier code solved this in a different way that didn't fit well
+ into the new scheme. Don't extract permissions onto existing
+ directories unless --overwrite is given. Do not add -wx------
+ permissions to new directories permanently; just do it temporarily.
+ Remove no-longer-needed hack with MSDOS and directory time stamps.
+ (apply_delayed_set_stat): New argument specifies which directories to
+ fix statuses of. Do not wait until the end of extraction to fix
+ statuses; instead, fix a directory's status once we exit that directory.
+ This requires less memory and does the right thing in some cases
+ where the old method didn't.
+ (fatal_exit): New function.
+
+ * src/incremen.c (<quotearg.h>): New include.
+ (get_directory_contents, gnu_restore):
+ Check for readdir and closedir errors.
+ (get_directory_contents, read_directory_file, gnu_restore):
+ Quote arbitrary strings in diagnostics.
+ (get_directory_contents, read_directory_file, write_directory_file):
+ Don't assume that gettext preserves errno.
+
+ * src/create.c (<quotearg.h>): New include.
+ (start_header): Use `member names' to refer to archive member names, not
+ `archive names'. Warn about `..' in member names.
+ (finish_sparse_file, dump_file):
+ Quote arbitrary strings in diagnostics.
+ (finish_sparse_file, dump_file):
+ Don't assume that gettext preserves errno.
+ (dump_file): Don't use `access' to determine whether a directory is readable;
+ this isn't reliable if tar is setuid. Use `opendir' instead.
+ Check for readdir and closedir failures.
+ Don't dump sockets as if they were fifos; just warn and skip.
+
+ * src/delete.c (move_archive):
+ Don't report fatal error merely because sizes don't fit
+ into struct mtop values; fall back on lseek instead.
+ Say `Cannot' uniformly, instead of `Could not' sometimes and `Cannot' others.
+ Say `reposition' instead of `re-position'.
+ (delete_archive_members):
+ Set archive to STDOUT_FILENO before outputting trailing buffer.
+
+ * src/compare.c (<quotearg.h>): New include.
+ (diff_init): Use `Cannot' uniformly, instead of `Could not' sometimes
+ and `Cannot' others.
+ (report_difference, diff_archive):
+ Quote arbitrary strings in diagnostics.
+ (process_rawdata, diff_sparse_files, get_stat_data, diff_archive, seek_warn):
+ Don't assume that gettext preserves errno.
+ (diff_archive): Don't open regular files with O_NONBLOCK.
+ Preserve access times of files if --atime.
+
+ * src/common.h (FATAL_ERROR): Use new fatal_exit function to exit.
+ (FATAL_ERROR, USAGE): Don't return 0.
+ (enum old files): New enum.
+ (old_files_option): New variable, replacing keep_old_files_option and
+ unlink_first_option.
+ (apply_delayed_set_stat): Now takes char const * param.
+ (fatal_exit, contains_dot_dot, chdir_fatal, close_error,
+ closedir_error, exec_fatal, mkfifo_error, mknod_error, open_error,
+ open_fatal, open_warn, opendir_error, opendir_warn, read_error,
+ read_fatal, readdir_error, readdir_warn, readlink_error,
+ readlink_warn, seek_error, seek_warn, stat_error, stat_warn,
+ truncate_error, truncate_warn, unlink_error, waitpid_error,
+ write_error, write_fatal, xfork, xpipe, quote, quote_n): New decls.
+
+ * src/buffer.c:
+ (xclose, xdup2, child_open_for_compress, child_open_for_uncompress,
+ archive_write_error, archive_read_error, flush_archive, close_archive,
+ init_volume_number, new_volume):
+ Don't assume that gettext preserves errno.
+
+ (xdup2): Don't report errno if dup returns an unexpected nonnegative value.
+ (open_archive): Reject multivolume verify attempts a bit earlier.
+ Rename local variable `access', in case it's defined by system header.
+
+ (open_archive, backspace_output): Use `Cannot' uniformly, instead of
+ `Could not' sometimes and `Cannot' others.
+
+ (open_archive, flush_read, flush_archive, close_archive, new_volume):
+ Quote arbitrary strings in diagnostics.
+
+ (read_error): Set archive to STDOUT_FILENO temporarily when writing
+ archive buffer.
+
+ (init_volume_number): Check for input and output errors in volno_file.
+
+ (new_volume): Use new fatal_exit function to exit, and new xfork
+ function to fork.
+
+ * m4/Makefile.am (EXTRA_DIST): Add c-bs-a.m4.
+
+ * Makefile.am (ACINCLUDE_INPUTS): Add $(M4DIR)/c-bs-a.m4.
+
+ * doc/tar.texi: Add --overwrite.
+ --absolute-names rejects ".." in names.
+
+ * lib/quotearg.c: Add support for multibyte characters.
+ (ISGRAPH): Remove.
+ (ISPRINT): New macro.
+ (<wchar.h>): Include if HAVE_MBRTOWC && HAVE_WCHAR_H.
+ (isprint, mbrtowc, mbsinit, mbstate_t): New macros,
+ defined if ! (HAVE_MBRTOWC && HAVE_WCHAR_H).
+ (quotearg_buffer_restyled): New function, with most of the old
+ quotearg_buffer's contents.
+ Major rewrite to support multibyte characters.
+ (quotearg_buffer): Now just calls quotearg_buffer_restyled.
+
+ * m4/c-bs-a.m4: New file.
+
+ * lib/Makefile.am: Use ## for copyright notice.
+
+ * scripts/Makefile.am: Use ## on copyright notice.
+
+ * doc/Makefile.am:
+ ($(srcdir)/tar.info, tar.dvi): We now use texinfo 4.0.
+
+1999-12-05 Paul Eggert <eggert@twinsun.com>
+
+ * doc/ChangeLog, lib/ChangeLog, scripts/ChangeLog,
+ src/ChangeLog, tests/ChangeLog: Remove these files.
+ * ChangeLog.1: New file, incorporating the above files, plus old
+ ChangeLog entries.
+ * Makefile.am (EXTRA_DIST): Add ChangeLog.1.
+
+1999-12-05 Dale Worley <worley@ariadne.com>
+
+ * src/compare.c (<utime.h>, struct utimbuf): Add.
+ (diff_archive): Restore access times if --atime.
+ * doc/tar.texi: Explain that --atime also preserves modification time.
+
+1999-12-04 Gerhard Poul <gpoul@gnu.org>
+
+ * ABOUT-NLS: Update to latest version from ftp.gnu.org.
+ * BACKLOG, TODO: Remove.
+ * Makefile.am (all-local, BABYL, dist-zoo, id, ID): Remove.
+ * README: Bring up to date.
+
+1999-12-03 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): Version 1.13.15.
+
+ * src/compare.c (diff_archive):
+ Do not set errno to EPIPE; we no longer use perror.
+
+ * src/create.c (dump_file):
+ If a parent directory said that a file should be there but it is
+ absent, diagnose it as being removed in the meantime.
+ Do not pass meaningless errno to ERROR when reporting that the
+ file changed as we read it.
+ Report that a file changed if its ctime changes; this is more
+ sensitive than mtime+size, and more accurate.
+
+ * src/incremen.c (enum children): New type.
+ (struct directory): Change old char allnew member to new enum children
+ children member.
+ All uses changed.
+ (get_directory_contents): When doing an incremental dump that does
+ not cross filesystem boundaries, dump the mount points, even though
+ they are in a different filesystem. This is for convenience when
+ restoring, and for consistency with non-incremental dumps.
+ This requires a 3-way flag for keeping track of which children we want,
+ so we use enum children rather than boolean.
+
+ * src/open3.c (modes): Remove.
+ (open3): Remove unportable assumptions about flag encodings.
+ Use `stat' instead of `access' for testing file existence,
+ to avoid problems with setuid programs.
+
+ * src/names.c (name_next): If file names are given both in the
+ command line (e.g. via -C) and in a file (via -T), do not
+ ignore the command-line names.
+
+ * m4/uintmax_t.m4: Backport to autoconf 2.13.
+
+ * doc/tar.texi: Clarify getdate authorship.
+
+1999-11-23 Paul Eggert <eggert@twinsun.com>
+
+ * lib/Makefile.am (DISTCLEANFILES): New macro.
+
+ * configure.in (tar_fnmatch_hin):
+ Remove; it runs afoul of a bug in autoconf 2.13.
+ Instead, always link fnmatch.h to some file, even if it's a throwaway.
+
+1999-11-19 Paul Eggert <eggert@twinsun.com>
+
+ * m4/largefile.m4: Update serial.
+
+1999-11-18 Paul Eggert <eggert@twinsun.com>
+
+ * m4/largefile.m4 (AC_SYS_LARGEFILE_FLAGS): Work around a bug in
+ the QNX shell, which doesn't propagate exit status of failed
+ commands inside shell assignments.
+
+1999-11-07 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): Version 1.13.14.
+
+ * configure.in (AC_PREREQ): Bump to 2.13.
+ (ALL_LINGUAS): Add pt_BR, ja.
+ (AC_FUNC_FNMATCH): Remove lib/funmatch.h before invoking, not after.
+ (tar_cv_path_RSH): Prefer a non-symlink rsh to a symlink one,
+ for AIX crossbuilds.
+
+ * doc/tar.texi: New node create options for --ignore-failed-read.
+ Remove unused version control symbols.
+ Modernize texinfo usage.
+
+ * src/tar.c (usage): Add examples.
+
+ * m4/fnmatch.m4 (AC_FUNC_FNMATCH):
+ Include fnmatch.h when testing fnmatch.
+
+ * src/common.h (collect_and_sort_names): New decl.
+
+ * src/list.c (from_header):
+ Handle 32-bit two's complement negative time stamps
+ even if the leading octal digit is 2 or 3.
+
+ * src/extract.c (set_stat): Remove duplicate code.
+
+ * src/create.c (to_chars): Remove trailing newline from warning.
+ (dump_file): Ignore doors.
+ (finish_header): Report block numbers with origin 0, not origin 1.
+
+ * src/rmt.c: Include getopt.h.
+ (long_opts): New constant.
+ (usage): New function.
+ (main): Implement --help and --version.
+ Output usage message if arguments are bad.
+
+1999-10-10 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): Version 1.13.13.
+
+ * README: Remove --with-dmalloc.
+ Add --disable-largefile.
+ Remove old NeXT dirent problems, or AIX valloc problems.
+ Remove old union wait advice, and old %lld advice.
+ Remove advice about FreeBSD 2.1.7, ISC 4.1mu, Ultrix `make'.
+
+ * doc/tar.texi: Clarify documentation for portable file names.
+
+ * configure.in (AM_WITH_DMALLOC): Remove.
+ (ALL_LINGUAS): Add ja.
+
+ * src/tar.c (decode_options):
+ Invalid dates are now treated as (time_t) -1.
+ Redo version message to conform to GNU standards.
+
+ * src/create.c (dump_file):
+ Fix typo: last two args to dump_file were interchanged.
+ * src/update.c (update_archive): Likewise.
+
+ * src/common.h (tartime): New decl.
+
+ * src/list.c (tartime): Now extern.
+ (read_and): Invalid headers cause errors, not warnings.
+
+1999-10-03 Paul Eggert <eggert@twinsun.com>
+
+ * lib/getdate.y (__attribute__):
+ Don't use if GCC claims to be before 2.8; this is
+ needed for OPENStep 4.2 cc. Also, don't use if strict ANSI.
+
+1999-09-25 Paul Eggert <eggert@twinsun.com>
+
+ * lib/fnmatch.c, lib/fnmatch.hin: Merge changes from latest glibc.
+ * lib/getopt.c, lib/getopt.h, lib/getopt1.c: Likewise.
+
+ * tests/incremen.sh: Add yet another sleep.
+
+1999-09-24 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS: A read error now causes a nonzero exit status.
+
+ * src/create.c (to_chars): Fix base-256 output.
+
+ * src/buffer.c (write_error):
+ Read error is an error, not just a warning.
+
+1999-09-24 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): Version 1.13.12.
+
+ * src/tar.c (<time.h>): Include.
+ (time): Declare if not defined.
+ (confirm): Don't read past EOF.
+ (long_options, usage): Add --no-same-owner, --no-same-permissions.
+ (main): Use clock_gettime if available.
+
+ * tests/Makefile.am (TESTS): Add incremen.sh
+ (INCLUDES): Add -I../lib, for fnmatch.h.
+
+ * src/update.c (update_archive):
+ Remove call to name_expand; had no effect.
+ Use chdir_do to change into directory.
+ Use deref_stat instead of stat.
+ Use add_avoided_name to mark names to be avoided; the old method of
+ setting a bit with the name caused all descendants of that name to
+ be avoided, in some circumstances.
+
+ * tests/incremen.sh: Remove unnecessary sleeps.
+
+ * src/names.c (name_next): Go back to using plain chdir.
+ (name_gather): Use chdir_arg to keep track of arguments to chdir.
+ (addname): Likewise.
+ (name_match): Use chdir_do to act on chdir args.
+ (merge_sort): Moved here from incremen.c.
+ (compare_names, add_hierarchy_to_namelist, collect_and_sort_names):
+ Likewise.
+ (name_expand): Remove.
+ (name_from_list): Skip fake names.
+ Use chdir_do to act on chdir args.
+ (struct avoided_name): New struct.
+ (avoided_names): New var.
+ (add_avoided_name, is_avoided_name): New functions.
+
+ * src/system.h (stat, lstat): Define in terms of statx on
+ STX_HIDDEN && !_LARGE_FILES /* AIX */ hosts.
+ (UCHAR_MAX): New macro.
+ (TYPE_MAXIMUM): Cast to arg type, for types narrow than int.
+
+ * m4/largefile.m4: Work around GCC 2.95.1 bug with HP-UX 10.20.
+
+ * src/incremen.c (<time.h>): Remove include; no longer used.
+ (time): Remove decl.
+ (time_now): Remove.
+ (get_directory_contents): Use deref_stat.
+ Consider a subdirectory to be all new only if
+ listed_incremental_option or if it its timestamp is newer than the
+ cutoff.
+ (add_hierarchy_to_namelist, merge_sort): Move to names.c.
+ (read_directory_file): Now extern. Do not set time_now.
+ (write_directory_file): Renamed from write_dir_file.
+ Use start_time instead of time_now.
+ (compare_names, collect_and_sort_names): Move to names.c.
+
+ * src/mangle.c (<time.h>): Remove; not used.
+ (time): Do not declare.
+
+ * src/misc.c (chdir_from_initial_wd): Remove.
+ (deref_stat): New function.
+ (struct wd): New struct.
+ (wd, wds, wd_alloc): New variables.
+ (chdir_arg, chdir_do): New function.
+
+ * src/compare.c (get_stat_data): Use deref_stat.
+
+ * src/common.h (name_expand): Remove.
+
+ * src/list.c (time): Declare if not defined.
+ (base_64_digits): Moved here from create.c.
+ (base64_map): Use UCHAR_MAX for size, not less-clear (unsigned char)
+ -1.
+ (read_and): Don't get time from header unless we need it now;
+ as getting time can cause duplicate diagnostics if bogus.
+ Remove "Hmm, " from diagnostic.
+ Use "Skipping to next header" uniformly.
+ (from_header): Renamed from from_chars. All uses changed.
+ Allow different forms for unportable 2's complement numbers.
+ Don't check for extended forms when parsing checksums.
+ Parse base-256 output.
+ (gid_from_header): Renamed from gid_from_chars. All uses changed.
+ (major_from_header): Renamed from major_from_chars. All uses changed.
+ (minor_from_header): Renamed from minor_from_chars. All uses changed.
+ (mode_from_header): Renamed from mode_from_chars. All uses changed.
+ (off_from_header): Renamed from off_from_chars. All uses changed.
+ (size_from_header): Renamed from size_from_chars. All uses changed.
+ (time_from_header): Renamed from time_from_chars. All uses changed.
+ Warn about future timestamps.
+ (uid_from_header): Renamed from uid_from_chars. All uses changed.
+ (uintmax_from_header): Renamed from uintmax_from_chars.
+ All uses changed.
+ (tartime): New function, incorporating isotime.
+ (isotime): Delete.
+ (print_header): Use tartime.
+
+ * src/create.c (to_chars): Fix typo in decl.
+ Don't assign through char const *.
+ Rename name_expand back to collect_and_sort_names.
+
+ * src/extract.c (<time.h>): No need to include.
+ (time): No need to declare.
+ (now): Remove variable.
+ (extr_init): Don't initialize `now'.
+ Increment same_permissions_option and same_owner_option if we_are_root
+ is nonzero; this supports the new --no-same-owner option.
+ (set_stat): Use start_time instead of `now'.
+
+ * src/create.c (struct link): Remove unused linkcount member.
+ (base_64_digits): Move to list.c.
+ (base_8_digits): Remove.
+ (to_octal): New function, with some of old contents of to_base.
+ (to_base): Remove.
+ (to_base256): New function.
+ (to_chars): Use base 256, not base 64, for huge values.
+ (mode_to_chars): Don't use two's complement in GNU format or POSIX
+ format.
+ (dump_file): Interchange last two arguments. If TOP_LEVEL is negative,
+ it means we have an incremental dump where we don't know whether this
+ is a top-level call.
+ Use deref_stat instead of statx / stat / lstat.
+ Cast result of alloca.
+ Check for dates if 0 < top_level, not if listed_incremental_option.
+ Move multiple-link check after directory check.
+ Do not dump avoided names.
+ Dump hard links to symbolic names as links, not as separate
+ symbolic links.
+ start_header cannot return a null pointer, so don't test for it.
+ Likewise for find_next_block.
+
+ * src/buffer.c, src/common.h (<human.h>): Include.
+ (read_error): Read error is an error, not just a warning.
+ (print_total_written): Also print human-readable byte count, and
+ bytes/s.
+ (open_archive, flush_write): Use start_time, not current time.
+ (flush_read): Report about garbage bytes ignored at end of archive,
+ but act on non-garbage bytes (instead of ignoring them).
+ (new_volume): Use WARN for warnings.
+
+ * doc/Makefile.am:
+ ($(srcdir)/tar.info): Add -I$(srcdir) so that subdir builds work.
+
+ * Makefile.am (ACINCLUDE_INPUTS): Add $(M4DIR)/fnmatch.m4.
+
+ * m4/Makefile.am (EXTRA_DIST): Add fnmatch.m4.
+
+ * lib/Makefile.am (noinst_HEADERS):
+ Rename fnmatch.h to fnmatch.hin; add human.h.
+ (libtar_a_SOURCES): Add human.c, xstrtoul.c.
+ (INCLUDES): Remove -I.. -I$(srcdir) -- automake adds this for us.
+
+ * src/Makefile.am (rmt_LDADD, tar_LDADD): New macros.
+
+ * lib/fnmatch.c (strchrnul):
+ Define to __strchrnul if _LIBC, to our own replacement otherwise.
+ Do not define if !_LIBC and if it already exists.
+ (internal_fnmatch): Use it.
+
+ * configure.in (tar_LDADD): New variable, used only when linking tar.
+ (rmt_LDADD): Similarly, for rmt.
+ (AC_FUNC_FNMATCH): Link fnnmatch.hin to fnmatch.h if we're using our
+ fnmatch.c; otherwise, use the system fnmatch.h.
+
+ * doc/tar.texi: Add --no-same-owner, --no-same-permissions.
+ Modernize sample backup script.
+
+ * THANKS: Martin Goik's email address has changed.
+
+ * m4/fnmatch.m4: New file.
+
+1999-09-03 Paul Eggert <eggert@twinsun.com>
+
+ * lib/lchown.h (ENOSYS): Don't use ENOMSG; it's not in NeXTStep3.3.
+ Use EINVAL instead.
+
+1999-08-29 Paul Eggert <eggert@twinsun.com>
+
+ * lib/getdate.y (get_date):
+ Rename outermost local `probe' to `quarter'.
+ Rename latter local `tm' to probe_tm.
+ From: Jim Meyering <meyering@ascend.com>
+ Message-ID: <uryn1vafyyc.fsf@ixi.eng.ascend.com>
+
+1999-08-28 Paul Eggert <eggert@twinsun.com>
+
+ * lib/getdate.y (PC): New macro; use it when possible.
+ (number): Handle `Nov 11 1996' example correctly.
+ See Risks Digest 20.55 (1999-08-27)
+ http://catless.ncl.ac.uk/Risks/20.55.html#subj18
+
+1999-08-23 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): Version 1.13.11.
+
+ Remove minor cases of lint from many source files: this includes
+ unnecessary casts, uses of NULL, etc.
+
+ * configure.in (AC_PROG_YACC): Remove.
+ (YACC): Always use bison.
+ (AC_STRUCT_TIMEZONE): Add.
+ (AC_REPLACE_FUNCS): Add strcasecmp, strncasecmp.
+
+ * doc/tar.texi: --bzip2 is now -I. Remove obsolete time zone info.
+ Fix spelling.
+
+ * lib/Makefile.am (EXTRA_DIST): Add strcasecmp.c, strncasecmp.c.
+ ($(srcdir)/getdate.c): Rename y.tab.c to getdate.c only if successful.
+
+ * lib/strcasecmp.c, lib/strncasecmp.c: New files.
+
+ * src/common.h (merge_sort): Remove decl; no longer exported.
+
+ * src/system.h (voidstar): Remove.
+ (memcpy, memcmp): Cast args.
+ ("xalloc.h"): Add include.
+ (xmalloc, xrealloc): Remove decl.
+
+ * src/mangle.c (time): Do not declare if defined.
+ (first_mangle, mangled_num): Remove.
+
+ * src/list.c (from_chars): Report out-of-range values more precisely.
+ (off_from_chars): Do not allow negative offsets.
+ (uid_from_chars): Allow negative uids.
+
+ * src/create.c (linklist): Now static.
+ (to_chars): Fix wording of message to match from_chars.
+
+ * src/misc.c (merge_sort): Move to incremen.c.
+ * src/incremen.c (merge_sort): Move here from misc.c; now static.
+ It's too painful to make it both generic and portable.
+ (read_directory_file): "timestamp" -> "time stamp" in messages.
+
+ * src/tar.c (long_options, usage, main): -y is now -I (for --bzip).
+ (usage): Fix misspelling.
+ (OPTION_STRING): -y is now -I.
+ (decode_options): Use -1, not EOF, for getopt_long result.
+ Fix typo when invoking xstrtoumax: look for LONGINT_OK, not LONG_MAX.
+ Handle operands after any "--" argument.
+ (main): Report any output errors.
+
+ * src/rmt.c (main): status is ssize_t, not long.
+
+ * src/names.c (name_gather): Handle trailing -C option correctly.
+ (addname): use memcpy, not strncpy, to copy a string of known length.
+ (name_match): Handle trailing -C option correctly.
+ Propagate -C option to following files.
+ (name_match, name_scan): Remove redundant matching code.
+
+ * src/buffer.c (open_archive): Use American spelling in diagnostic.
+
+ * lib/getdate.y: Major rewrite. Add copyright notice.
+ (<stdio.h>): Include only if testing.
+ (ISUPPER): Remove.
+ (ISLOWER): New macro.
+ (<string.h>): Include if HAVE_STRING_H, not USG.
+ (bcopy): Remove.
+ (yymaxdepth, ..., yycheck): Don't bother to redefine, since we assume
+ bison.
+ (EPOCH_YEAR): Renamed from EPOCH.
+ (table): Renamed from TABLE.
+ (meridian): Now an anonymous enum.
+ (struct parser_control): New type.
+ (YYLEX_PARAM, YYPARSE_PARAM, YYSTYPE): New macros.
+ (yyInput, ..., yyRelYear): Migrated into struct parser_control.
+ (%pure_parser): Added, so that the parser is pure.
+ (%union): Removed; the type is now just plain int.
+ All %type directives removed.
+ (tLOCAL_ZONE): New %token.
+ (month_day_table): Renamed from MonthDayTable.
+ (gmtime, localtime, mktime, time): Declare only if not defined.
+ (meridian_table): New table.
+ (dst_table): New table.
+ (units_table): renamed from UnitsTable.
+ (relative_time_table): Renamed from OtherTable.
+ (time_zone_table): Renamed from TimezoneTable. Modernized.
+ (military_table): Renamed from MilitaryTable.
+ (to_hour): Renamed from ToHour.
+ (to_year): Renamed from ToYear.
+ (lookup_zone): New function.
+ (LookupWord): Renamed from lookup_word. Use lookup_zone for time
+ zones.
+ (yylex): Now reentrant. All callers changed.
+ (get_date): Add support for local time zone abbreviations.
+ Make it reentrant.
+
+1999-08-20 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): Version 1.13.10.
+
+ * src/create.c (to_chars): Generate GNU base-64 representation
+ if we are generating an old or new GNU format tar file for a
+ number that can't be represented with the POSIX format.
+
+ * configure.in (AC_CHECK_FUNCS): Add fchdir.
+ (AM_FUNC_GETLINE): Add.
+ (LIBOBJS): Add getline.o to workaround comment.
+ * Makefile.am (ACINCLUDE_INPUTS): Add $(M4DIR)/getline.m4.
+ * m4/Makefile.am (EXTRA_DIST): Add getline.m4.
+ * lib/Makefile.am (noinst_HEADERS): Add getline.h, save-cwd.h.
+ (libtar_a_SOURCES): Add save-cwd.c, xgetcwd.c.
+ * lib/getline.c, lib/getline.h, lib/save-cwd.c,
+ lib/save-cwd.h, m4/getline.m4: New files.
+
+ * src/misc.c (<save-cwd.h>): Include.
+ (chdir_from_initial_wd): New function.
+
+ * src/names.c (name_next): Use chdir_from_initial_wd, not chdir.
+ (name_gather): Handle `-C x -C y' correctly.
+ Do not rely on addname to handle -C.
+ (addname): New CHANGE_DIR parameter. All callers changed.
+ Remove ugly calls to getcwd; no longer needed.
+ (name_match, name_from_list): Use chdir_from_initial_wd, not chdir.
+
+ * src/incremen.c (listed_incremental_stream): New var.
+ (read_directory_file): Remove arbitrary limits on file name length.
+ Do not attempt to get the working directory; we can bypass this
+ on fchdir hosts. Open the listed_incremental_option file for both
+ read and write instead of opening it twice. Check for I/O errors
+ when doing I/O to this file. Check for invalid data in the file,
+ and report line numbers of invalid data.
+ (write_dir_file): Likewise.
+ (collect_and_sort_names): Use chdir_from_initial_wd, not chdir.
+ Do not invoke write_dir_file; that's our caller's responsibility.
+
+ * src/list.c (max): New macro.
+ (isotime): Now takes time_t, not time_t *. Report the decimal values
+ of times that can't be broken down.
+ (print_header): Don't assume that major and minor device numbers can
+ fit into uintmax_t.
+
+ * src/common.h (struct name): change_dir is now char const *.
+ (write_directory_file): Remove unused decl.
+ (STRINGIFY_BIGINT): Assume b always points to UINTMAX_STRSIZE_BOUND
+ chars; the old `sizeof (b)' broke when b was a pointer not an array.
+ (chdir_from_initial_wd): New decl.
+ (addname): New 2nd arg.
+
+ * THANKS: Torsten Lull -> Catrin Urbanneck
+
+1999-08-18 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (HAVE_GETHOSTENT, HAVE_SETSOCKOPT):
+ Don't depend on ac_cv_func variables.
+ From Albert Chin-A-Young <china@thewrittenword.com>.
+
+1999-08-18 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): Version 1.13.9
+
+ * m4/signedchar.m4: New file.
+ * configure.in (pe_AC_TYPE_SIGNED_CHAR): Add.
+ * src/system.h (signed_char): New macro.
+ * Makefile.am (ACINCLUDE_INPUTS): Add $(M4DIR)/signedchar.m4.
+ * m4/Makefile.am (EXTRA_DIST): Add signedchar.m4.
+
+ * src/create.c (write_eot): Write at least two zero blocks.
+
+ * src/extract.c (extract_archive): Fix sparse array bug:
+ we did not find end of array correctly.
+
+ * src/compare.c: (fill_in_sparse_array, diff_sparse_files):
+ Don't assume find_next_block yields nonnull.
+ * src/extract.c (extract_sparse_file, extract_archive): Likewise.
+ * src/list.c (skip_extended_headers): Likewise.
+
+ * src/list.c (read_and, list_archive): Simplify code.
+ (read_header): Fix computation of signed checksums on machines where
+ char is unsigned.
+ Do not consider a block to be zero unless all its bytes are zero,
+ even the checksum bytes. Do not attempt to parse the checksum of
+ a zero block. Fix memory leak with long names and links.
+ (from_chars): Accommodate a buggy tar that outputs leading NUL
+ if the previous field overflows.
+
+ * src/misc.c (quote_copy_string): Generate \177 for '\177', not
+ \?, for portability to non-ASCII hosts.
+
+1999-08-16 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (AM_INIT_AUTOMAKE), NEWS: Version 1.13.8.
+
+ * src/extract.c (make_directories): Do not chown intermediate
+ directories, even if we are root.
+
+ * src/list.c (read_header): Fix bugs when interpreting
+ POSIX-compliant headers that do not contain null bytes in the
+ header or link names.
+
+1999-08-14 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (AM_INIT_AUTOMAKE), NEWS: Version 1.13.7.
+
+ * configure.in (AC_CHECK_HEADERS): Remove sys/wait.h.
+ (AC_HEADER_SYS_WAIT): Add.
+ (AC_REPLACE_FUNCS): Add waitpid.
+ (tar_cv_header_union_wait, HAVE_UNION_WAIT): Remove.
+ * lib/waitpid.c: New file.
+ * lib/Makefile.am (EXTRA_DIST): Add waitpid.c.
+ * src/system.h (WCOREDUMP): Remove; no longer used.
+ (WIFSTOPPED): Likewise.
+ (WEXITSTATUS, WIFSIGNALED): Default to Solaris 7 versions.
+ * src/buffer.c (child_open_for_compress): Undo previous change.
+ (close_archive): Use waitpid, POSIX-style, instead of old BSD style.
+ (new_volume): Likewise.
+
+ * src/buffer.c, src/extract.c, src/incremen.c (time):
+ Don't declare if defined.
+ * src/extract.c (extr_init): Remove unneeded cast around 0 arg to time.
+ * src/incremen.c (read_directory_file):
+ Invoke `time' the same way everyone else does.
+ Check validity of --listed-incremental file contents a bit better.
+ Do not worry about --after-date-option; tar.c now checks this.
+ * src/list.c (isotime): Report ??? if localtime returns null.
+ Don't assume years fit into four digits.
+ Don't append trailing newline.
+ (print_header): Report ??? if localtime returns null;
+ Don't assume years fit into four digits.
+
+ * src/compare.c (diff_archive): Do not fall back on absolute name
+ when --absolute-names is not specified.
+
+ * src/create.c (start_header):
+ Include text of ignored filesystem prefix in warning.
+ (create_archive): Check for excluded names when doing incremental
+ pass through directory.
+ (dump_file): Do not dump old files explicitly given on command line
+ when using --listed-incremental. Do not strip ./ prefix from names.
+
+ * src/tar.c: -g now implies after_date_option = 1.
+ -g and -N are now incompatible options.
+
+ * doc/tar.texi: Explain --exclude better. Don't strip leading `./'.
+
+1999-08-11 Jeff Dairiki <dairiki@dairiki.org>
+
+ * src/list.c (read_header): Don't parse OLDGNU_FORMAT
+ incremental headers as POSIX prefixes.
+
+1999-08-11 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in: Version 1.13.6.
+
+ * configure.in (ALL_LINGUAS): Add pt_BR.
+ * po/pt_BR.po: New file.
+
+ * doc/Makefile.am ($(srcdir)/tar.info, $(srcdir)/header.texi):
+ Renamed from tar.info and header.texi; adjust actions so that
+ they work in other directories.
+
+ * doc/tar.texi: Add -y and --bzip2.
+ Patterns containing / now exclude only file names whose prefix match.
+
+ * lib/exclude.h (excluded_filename): New option parameter.
+ (add_exclude_file): New ADD_FUNC parameter.
+ (excluded_pathname): Remove decl.
+ * lib/exclude.c (_GNU_SOURCE):
+ Remove; no longer needed since we don't use FNM_ macros.
+ (excluded_filename): Renamed from excluded_filename_opts.
+ (excluded_filename, excluded_pathname): Remove.
+ (add_exclude_file): New ADD_FUNC parameter.
+
+ * po/POTFILES.in: Add lib/quotearg.c.
+
+ * src/buffer.c (_GNU_SOURCE): Define.
+ (<fnmatch.h>): Include unconditionally.
+ (child_open_for_compress): Dup after closing, to avoid possible file
+ descriptor exhaustion.
+ (flush_write): Use FILESYSTEM_PREFIX_LEN instead of MSDOS ifdef.
+ (flush_read): Likewise.
+
+ * src/common.h (LG_8, LG_64): New macros.
+ (excluded_with_slash, excluded_without_slash): New vars.
+ (excluded): Remove.
+ (base_64_digits): New decl.
+ (gid_to_chars, major_to_chars, minor_to_chars, mode_to_chars,
+ off_to_chars, size_to_chars, time_to_chars, uid_to_chars,
+ uintmax_to_chars,
+ GID_TO_CHARS, MAJOR_TO_CHARS, MINOR_TO_CHARS, MODE_TO_CHARS,
+ OFF_TO_CHARS, SIZE_TO_CHARS, TIME_TO_CHARS, UID_TO_CHARS,
+ UINTMAX_TO_CHARS):
+ Renamed from gid_to_oct, major_to_oct, minor_to_oct, mode_to_oct,
+ off_to_oct, size_to_oct, time_to_oct, uid_to_oct, uintmax_to_oct,
+ GID_TO_OCT, MAJOR_TO_OCT, MINOR_TO_OCT, MODE_TO_OCT, OFF_TO_OCT,
+ SIZE_TO_OCT, TIME_TO_OCT, UID_TO_OCT, UINTMAX_TO_OCT,
+ respectively. All definitions and uses changed.
+ (excluded_name): New decl.
+
+ * src/compare.c (diff_archive):
+ Open files with O_NONBLOCK instead of O_NDELAY.
+
+ * src/create.c (base_64_digits): New constant.
+ (base_8_digits): New macro.
+ (MAX_VAL_WITH_DIGITS): New macro.
+ (to_base): First half of old to_oct. Support base 64 too.
+ (to_chars): Other half of old to_oct, for 64-bit support.
+ (GID_NOBODY, UID_NOBODY): Don't define if the headers don't.
+ (gid_substitute, uid_substitute): Look up names dynamically if
+ GID_NOBODY and UID_NOBODY aren't defined; use -2 if all else fails.
+ (mode_to_chars): Renamed from mode_to_oct.
+ Support negative values in all the _to_chars functions.
+ (start_header): Use FILESYSTEM_PREFIX_LEN instead of MSDOS ifdef.
+ Abort if archive format is DEFAULT_FORMAT when it shouldn't be.
+ (dump_file): Inspect entire pathname, not just new file name
+ component, when deciding whether to exclude it.
+
+ * src/extract.c (extract_archive):
+ Open files with O_NONBLOCK instead of O_NDELAY.
+
+ * src/incremen.c (get_directory_contents):
+ Inspect entire pathname, not just new file name
+ component, when deciding whether to exclude it.
+
+ * src/list.c (<fnmatch.h>): Do not include.
+ (from_chars): Renamed from from_oct. New parameter specifing
+ the negative of the minimum allowed value. Support negative
+ and base-64 values.
+ (base64_map): New var.
+ (base64_init): New function.
+ (print_header): Output numeric uids and gids if numeric_owner_option.
+
+ * src/misc.c (quote_copy_string): Use LG_8 instead of constants.
+
+ * src/names.c (_GNU_SOURCE): Define.
+ (<fnmatch.h>): Include unconditionally.
+ (excluded_name): New function, taking over duties of excluded_pathname.
+ All uses changed.
+
+ * src/rmt.c (decode_oflag): New function.
+ (main): Use it to support symbolic open flags.
+
+ * src/rtapelib.c (encode_oflag): New function.
+ (rmt_open__): Do not allow newlines in the path.
+ Propagate errno correctly.
+ Decode symbolic open flags, if present.
+
+ * src/system.h (FILESYSTEM_PREFIX_LEN, ISSLASH, O_ACCMODE, O_NONBLOCK):
+ New macros.
+
+ * src/tar.c: (long_options, usage, OPTION_STRING, decode_options):
+ New -y or --bzip2 option.
+ (add_filtered_exclude): New function.
+ (decode_options): Put excluded patterns with / into
+ excluded_with_slash, and without / into excluded_without_slash.
+ Compare newer_mtime_option to its new initial value
+ TYPE_MINIMUM (time_t) when deciding whether more than one
+ threshold date was specified.
+
+1999-07-20 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in: Version 1.13.5.
+
+ * src/common.h (FATAL_ERROR): Invoke apply_delayed_set_stat
+ before exiting.
+ * src/buffer.c (new_volume): Likewise.
+ * src/incremen.c (read_directory_file): Likewise.
+ * src/tar.c (decode_options):
+ ERROR ((TAREXIT_FAILURE, ... -> FATAL_ERROR ((0,
+ for consistency.
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): Version 1.13.4.
+ * configure.in (AC_CHECK_FUNCS): Add lstat, readlink, symlink.
+
+ * src/system.h (lstat): Define only if !HAVE_LSTAT && !defined lstat.
+ (S_ISMPB, S_ISMPC, S_ISNWK): Remove unused macros.
+ (S_ISBLK, S_ISCHR, S_ISCTG, S_ISFIFO, S_ISLNK, S_ISSOCK):
+ Define to 0 if the corresponding S_IF* macro is not defined.
+ (mkfifo): Do not define if already defined, or if S_IFIFO
+ is not defined.
+
+ * src/compare.c (diff_archive): Use HAVE_READLINK, not
+ S_ISLNK, to determine whether to invoke readlink.
+ * src/create.c (dump_file): Likewise.
+
+ * src/extract.c (set_mode):
+ Do not chmod unless we are root or the -p option was given;
+ this matches historical practice.
+ (unlink_destination): New function, which checks for unlink failures.
+ (maybe_recoverable): Stay quiet if -U.
+ (extract_archive): Use O_EXCL if unlink_first_option.
+ Report unlink failures.
+ Use HAVE_SYMLINK, not S_ISLNK, to determine whether symlink exists.
+ Use HAVE_MKFIFO || defined mkfifo, not S_ISFIFO, to determine whether
+ mkfifo exists.
+
+ * src/incremen.c (get_directory_contents): Depend on
+ S_ISHIDDEN, not AIX, to determine whether to invoke S_ISHIDDEN.
+
+ * src/list.c: Remove S_IS* ifdefs.
+ * src/misc.c (maybe_backup_file): Likewise.
+
+ * src/misc.c (maybe_backup_file):
+ "Virtual memory exhausted" -> "Memory exhausted",
+ to conform to the other places this message is issued.
+
+ * src/mangle.c (extract_mangle):
+ Replace #ifdef S_ISLNK with #ifdef HAVE_SYMLINK.
+
+ * src/rtapelib.c (rmt_open__):
+ Remove typo that caused us to omit the first char
+ of the basename.
+
+1999-07-16 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): version 1.13.3.
+
+ * doc/tar.texi: A path name is excluded if any of its file name
+ components matches an excluded pattern, even if the path name was
+ specified on the command line.
+ * src/create.c (create_archive): Likewise.
+ * src/list.c (read_and): Likewise.
+ * src/update.c (update_archive): Likewise.
+ * lib/exclude.h (excluded_pathname): New decl.
+ * lib/exclude.c (_GNU_SOURCE): Define.
+ (FILESYSTEM_PREFIX_LEN, ISSLASH): New macros.
+ (excluded_filename_opts): New function.
+ (excluded_pathname): New function.
+
+ * lib/Makefile.am (EXTRA_DIST):
+ xstrtol.c moved here from libtar_a_SOURCES.
+ (libtar_a_SOURCES): Move xstrtol.c to EXTRA_DIST.
+ Remove xstrtoul.c; no longer needed.
+ * lib/xstrtol.c: Remove.
+
+ * src/tar.c (decode_options):
+ Set newer_time_option to TYPE_MINIMUM, so that
+ negative timestamps are handled correctly.
+ Replace invocations of xstrtol and xstrtoul with xstrtoumax, for
+ uniformity (and so that we don't need to have the other fns).
+ (main): Remove call to init_total_written; no longer needed.
+
+ * configure.in (AC_CHECK_SIZEOF): Remove no-longer-needed
+ checks for unsigned long and long long.
+ * src/arith.c: Remove.
+ * src/Makefile.am (tar_SOURCES): Remove arith.c.
+ * po/POTFILES.in: Remove src/arith.c.
+ * src/arith.h: Use double, to simplify configuration gotchas.
+ (tarlong): Now double.
+ (TARLONG_FORMAT): New macro.
+ (BITS_PER_BYTE, BITS_PER_TARLONG, SUPERDIGIT, BITS_PER_SUPERDIGIT,
+ LONGS_PER_TARLONG, SIZEOF_TARLONG, struct tarlong,
+ zerop_tarlong_helper, lessp_tarlong_helper, clear_tarlong_helper,
+ add_to_tarlong_helper, mult_tarlong_helper, print_tarlong_helper,
+ zerop_tarlong, lessp_tarlong, clear_tarlong, add_to_tarlong,
+ mult_tarlong, print_tarlong): Remove. All callers replaced with
+ arithmetic ops.
+
+ * src/common.h (init_total_written): Remove decl.
+
+ * src/buffer.c (total_written):
+ Remove; replaced with prev_written + bytes_written.
+ (prev_written): New var.
+ (init_total_written): Remove.
+ (print_total_written): Use TARLONG_FORMAT instead of print_tarlong.
+
+ * m4/ulonglong.m4 (jm_AC_TYPE_UNSIGNED_LONG_LONG):
+ Make sure that we can shift, multiply
+ and divide unsigned long long values; Ultrix cc can't do it.
+
+ * lib/modechange.c (mode_compile): Use uintmax_t, not unsigned long.
+ Check for any unknown bits, not just unknown bits left of the leftmost
+ known bit.
+
+ * lib/quotearg.c (quotearg_buffer):
+ Don't quote spaces if C quoting style.
+ * src/list.c (from_oct):
+ Use C quoting style for error; omit trailing NULs.
+
+1999-07-14 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (AM_INIT_AUTOMAKE), NEWS: Version 1.13.2.
+
+ * m4/xstrtoumax.m4 (jm_AC_PREREQ_XSTRTOUMAX): Check whether
+ <inttypes.h> defines strtoumax as a macro (and not as a function).
+ HP-UX 10.20 does this.
+
+ * src/tar.c (usage): tar-bugs@gnu.org -> bug-tar@gnu.org
+ * PORTS, README, TODO, doc/tar.texi: Likewise.
+
+1999-07-12 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (AM_INIT_AUTOMAKE): Version 1.13.1.
+ (LIBOBJS): Add mktime.o to automake 1.4 bug workaround.
+
+ * src/list.c (decode_header):
+ Do not assume that S_IFBLK and S_IFCHR are defined.
+
+ * src/create.c (start_header): Do not assume S_IFMT is defined.
+ (dump_file): Remove unnecessary check for screwy apollo lossage.
+ Do not assume S_IFBLK and S_IFCHR are defined.
+
+ * src/extract.c (extract_archive):
+ Test whether S_IFCHR and S_IFBLK are nonzero,
+ not whether they are defined, for consistency with other tests.
+
+ * src/buffer.c (is_regular_file):
+ Don't succeed on files that we can't access due to
+ permissions problems.
+ (open_archive): Fix wording on fatal error message.
+ Don't bother to stat /dev/null if the archive is not a character
+ special device.
+
+ * src/compare.c (process_rawdata, diff_sparse_files, diff_archive):
+ Report an error, not a warning, for I/O errors.
+ (process_rawdata, process_dumpdir, diff_sparse_files):
+ Change ungrammatical "Data differs" to "Contents differ".
+ (get_stat_data): Find hidden files on AIX.
+ Accept file name as argument; all uses changed.
+ (get_stat_data, diff_archive): Use system error message for
+ nonexistent files rather than rolling our own.
+ (diff_archive): Unknown file types are errors, not warnings.
+ Normalize spelling of message to "File type differs".
+ Use get_stat_data to get link status, for consistency.
+ Do not inspect st_rdev for fifos.
+ Do not assume st_mode values contain only file types and mode bits.
+ Check for mode changes and device number changes separately.
+
+ * src/update.c (append_file):
+ Open the file before statting it, to avoid a race.
+ Complain about file shrinkage only when we reach EOF.
+
+1999-07-08 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): Version 1.13 released.
+
+ * configure.in (AC_EXEEXT): Add.
+
+ * lib/Makefile.am (noinst_HEADERS):
+ Add basename.h, exclude.h. Remove full-write.h.
+ (libtar_a_SOURCES): Add exclude.c.
+
+ * lib/basename.h, lib/exclude.c, lib/exclude.h, lib/safe-read.h:
+ New files.
+ * lib/full-write.c: Include safe-read.h instead of full-write.h.
+ * lib/safe-read.h (safe_read): New decl.
+ * src/rmt.c: Include safe-read.h.
+ * src/rtapelib.c: Include basename.h, save-read.h.
+ (rmt_open__): Use base_name to compute base name.
+
+ * src/common.h:
+ Include basename.h, exclude.h; don't include full-write.h.
+ (exclude_option): Remove decl.
+ (excluded): New decl.
+ (add_exclude, add_exclude_file, check_exclude): Remove decls.
+
+ * src/list.c (read_and):
+ Use excluded_filename instead of check_exclude.
+ Check base name of incoming file name, not entire file name, when
+ deciding whether to exclude it.
+
+ * src/create.c (finish_sparse_file):
+ Use excluded_filename instead of check_exclude.
+ Don't bother to stat excluded file names.
+ * src/incremen.c (get_directory_contents): Likewise.
+
+ * src/names.c (exclude_pool, exclude_pool_size,
+ allocated_exclude_pool_size, simple_exclude_array,
+ simple_excludes, allocated_simple_excludes,
+ pattern_exclude_array, pattern_excludes,
+ allocated_pattern_excludes, add_exclude, add_exclude_file,
+ check_exclude):
+ Remove; now done in ../lib/exclude.c.
+
+ * src/tar.c (decode_options): Initialize `excluded'.
+ Use new add_exclude_file and add_exclude functions.
+
+1999-07-05 Paul Eggert <eggert@twinsun.com>
+
+ * m4/gettext.m4: Use changequote rather than [[ ]].
+
+ * lib/safe-read.c: Renamed from lib/full-read.c.
+ (safe_read): Renamed from full_read. All uses changed.
+ * lib/safe-read.h, lib/full-write.h: New files.
+ * lib/Makefile.am (noinst_HEADERS): Add full-write.h, safe-read.h.
+ (libtar_a_SOURCES): Rename full-read.c to safe-read.c.
+ * lib/full-write.c: Include full-write.h.
+ * src/common.h: Include full-write.h, safe-read.h.
+ * src/system.h: (full_read, full_write): Remove decls.
+
+ * src/Makefile.am (datadir): New var; needed for Solaris gettext.
+
+ * src/system.h (bindtextdomain, textdomain): undef before
+ defining, to avoid preprocessor warnings with --disable-nls
+ on hosts whose locale.h includes libintl.h.
+
+ * lib/xstrtol.c (__strtol): Remove decl; it doesn't work if __strtol
+ expands to a macro, which occurs in HP-UX 10.20 with strtoumax.
+ (strtol, strtoul): New decls (for pre-ANSI hosts), to replace
+ the above decl.
+
+1999-07-02 Paul Eggert <eggert@twinsun.com>
+
+ * Makefile.am (ACINCLUDE_INPUTS): Add $(M4DIR)/mktime.m4.
+ * m4/mktime.m4: New file.
+ * m4/Makefile.am.in, m4/README: Remove these files.
+ * m4/Makefile.am (EXTRA_DIST): Add mktime.m4;
+ remove README, Makefile.am.in.
+ (Makefile.am): Remove rule; it didn't work in BSD/OS 4.0.
+ * m4/jm-mktime.m4 (jm_FUNC_MKTIME): Invoke AC_FUNC_MKTIME,
+ not AM_FUNC_MKTIME.
+
+ * src/tar.c: Include signal.h.
+ (SIGCHLD): Define to SIGCLD if SIGCLD is defined but SIGCHLD is not.
+ (main): Ensure SIGCHLD is not ignored.
+
+ (BACKUP_OPTION, DELETE_OPTION, EXCLUDE_OPTION, GROUP_OPTION,
+ MODE_OPTION, NEWER_MTIME_OPTION, NO_RECURSE_OPTION, NULL_OPTION,
+ OWNER_OPTION, POSIX_OPTION, PRESERVE_OPTION, RECORD_SIZE_OPTION,
+ RSH_COMMAND_OPTION, SUFFIX_OPTION, USE_COMPRESS_PROGRAM_OPTION,
+ VOLNO_FILE_OPTION, OBSOLETE_ABSOLUTE_NAMES,
+ OBSOLETE_BLOCK_COMPRESS, OBSOLETE_BLOCKING_FACTOR,
+ OBSOLETE_BLOCK_NUMBER, OBSOLETE_READ_FULL_RECORDS, OBSOLETE_TOUCH,
+ OBSOLETE_VERSION_CONTROL): Make sure they can't be valid chars, so
+ they don't overlap with char codes. Use an enum instead of a lot
+ of #defines.
+
+ * src/system.h (ISASCII): Remove.
+ (CTYPE_DOMAIN, ISDIGIT, ISODIGIT, ISPRINT, ISSPACE, S_ISUID,
+ S_ISGID, S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP,
+ S_IROTH, S_IWOTH, S_IXOTH, MODE_WXUSR, MODE_R, MODE_RW,
+ MODE_RWX, MODE_ALL, SEEK_SET, SEEK_CUR, SEEK_END, CHAR_MAX,
+ LONG_MAX): New macros.
+
+ * src/incremen.c (ISDIGIT, ISSPACE): Remove; now in system.h.
+ (read_directory_file): Cast ISSPACE arg to unsigned char.
+ * src/misc.c (ISPRINT): Remove; now in system.h.
+ (remove_any_file): Add brackets to pacify gcc -Wall.
+ * src/list.c: Don't include <ctype.h>; system.h already does this.
+ (ISODIGIT, ISSPACE): Remove; now in system.h.
+ (decode_header): No need to AND mode with 07777; MODE_FROM_OCT
+ does this now.
+ (from_oct): Cast ISSPACE arg to unsigned char.
+
+ * src/create.c (mode_to_oct): Translate modes from internal to
+ external form.
+ * src/list.c (mode_from_oct): Translate modes from external to
+ internal form. Do not complain about unrecognized mode bits.
+ * src/common.h (TSUID, TSGID, TSVTX, TUREAD, TUWRITE, TUEXEC,
+ TGREAD, TGWRITE, TGEXEC, TOREAD, TOWRITE, TOEXEC): Remove undefs.
+
+ * src/extract.c: (extr_init, make_directories, extract_archive):
+ Do not assume mode bits have traditional Unix values.
+ * src/list.c (decode_mode): Likewise.
+ * src/create.c (start_header, dump_file): Likewise.
+ * src/buffer.c (child_open_for_compress,
+ child_open_for_uncompress, open_archive, (close_archive): Likewise.
+ * src/compare.c (diff_archive): Likewise.
+
+ * src/extract.c (set_mode): Use %04 not %0.4 format.
+ (extract_sparse_file): Do not use data_block uninitialized.
+ Check for lseek failures.
+
+ * src/rtapelib.c (rmt_lseek__):
+ Convert lseek whence values to portable integers on the wire.
+ * src/rmt.c (main): Likewise. Check for whence values out of range.
+
+ * src/create.c (finish_sparse_file): Use lseek whence macros
+ instead of integers.
+ * src/buffer.c (backspace_output): Likewise.
+ * src/compare.c (diff_archive, verify_volume): Likewise.
+ * src/delete.c (move_archive): Likewise.
+ * src/extract.c (extract_sparse_file): Likewise.
+
+ * src/create.c (dump_file): Do not invoke finish_sparse_file
+ on a negative file descriptor.
+
+ * src/buffer.c: Add braces to pacify gcc -Wall.
+
+ * src/compare.c (diff_sparse_files): Report lseek errors.
+
+ * configure.in (ALL_LINGUAS): Add cs, es, ru.
+
+ * PORTS, TODO: gnu.ai.mit.edu -> gnu.org
+
+ * src/arith.c, src/buffer.c (new_volume): Don't put ^G in
+ message to be internationalized; \a doesn't work with msgfmt.
+
+ * src/tar.c (long_options, main, usage, OPTION_STRING):
+ Remove -E or --ending-file.
+ * src/list.c (read_and): Likewise.
+ * src/common.h (ending_file_option): Likewise.
+ * src/buffer.c (close_archive): Likewise.
+
+ * tests/after: Don't run two commands together in a pipeline,
+ as some old shells mishandle pipeline exit status.
+
+1999-06-28 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (AM_INIT_AUTOMAKE): version 1.12.64015.
+ * NEWS: Describe changes since 1.12.
+ * README: Update bug reporting address; move paxutils ref to NEWS.
+
+ Handle EINTR correctly.
+ * lib/Makefile.am (libtar_a_SOURCES): Add full-read.c, full-write.c.
+ * lib/full-read.c, lib/full-write.c: New files.
+ * src/buffer.c (child_open_for_compress, child_open_for_uncompress):
+ Prefer full_read to read and full_write to write.
+ * src/compare.c (process_rawdata, diff_sparse_files): Likewise.
+ * src/create.c (deal_with_sparse, finish_sparse_file, dump_file):
+ Likewise.
+ * src/extract.c (extract_sparse_file): Likewise.
+ * src/rmt.c (get_string, main, report_error_message,
+ report_numbered_error): Likewise.
+ * src/rmt.h (rmtread, rmtwrite): Likewise.
+ * src/rtapelib.c (do_command, get_status_string, rmt_read__,
+ rmt_write__, rmt_ioctl__): Likewise.
+ * src/update.c (append_file): Likewise.
+ * src/system.h (full_read, full_write): New decls.
+
+ * po/POTFILES.in: Add lib/argmatch.c, lib/error.c lib/getopt.c,
+ lib/xmalloc.c, src/arith.c, src/misc.c.
+
+ * src/system.h (STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO):
+ New macros. All uses of STDIN and STDOUT changed.
+ * src/rmt.c (prepare_record_buffer, main): Use STDIN_FILENO
+ instead of 0 and STDOUT_FILENO instead of 1.
+ * src/rtapelib.c (_rmt_rexec): Use STDIN_FILENO and STDOUT_FILENO
+ instead of fileno (stdin) and fileno (stdout) or 0 and 1.
+
+ * src/rmt.c (private_strerror): Avoid const. Translate results.
+
+ * tests/Makefile.am (TESTS): Remove incremen.sh; it doesn't work
+ in the presence of NFS clock skew.
+
+1999-06-25 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (AM_INIT_AUTOMAKE): version 1.12.64014.
+
+ * src/buffer.c (write_archive_buffer): New function.
+ (child_open_for_compress, flush_write, flush_read): Use it to write
+ buffers.
+ (open_archive): Report error if fstat of archive fails.
+ Improve efficiency of check for /dev/null.
+ Also, fix some corner cases with remote archives and /dev/null checking.
+ (close_archive): Test for input fifo only if not remote.
+ Truncate output archive only if it's not remote.
+
+ * src/misc.c (remove_any_file):
+ Don't terminate if you see . or ..; just skip them.
+
+1999-06-18 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (AM_INIT_AUTOMAKE): version 1.12.64013.
+
+ Output sizes using a format that's more compatible with
+ traditional tar (and with GNU Emacs).
+ * src/common.h (GID_TO_OCT, MAJOR_TO_OCT, MINOR_TO_OCT,
+ MODE_TO_OCT, SIZE_TO_OCT, UID_TO_OCT, UINTMAX_TO_OCT):
+ Don't subtract 1 from size.
+ * src/create.c (to_oct): Prepend leading zeros, not spaces.
+ Output a trailing NUL unless the value won't fit without it.
+ (finish_header): No need to append NUL to chksum, now that
+ to_oct is doing it.
+
+1999-06-16 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): version 1.12.64012.
+
+ * src/Makefile.am (LDADD): Link libtar.a after @INTLLIBS@, since
+ @INTLLIBS@ might invoke rpl_realloc.
+
+ * src/tar.c (backup_type): Remove decl; backupfile.h now has it.
+ (intconv): Remove; use xstrto* fns instead.
+ ("xstrtol.h"): Include.
+ (check_decimal): Remove.
+ (long_options, usage, OPTION_STRING, decode_options):
+ Remove -y, --bzip2, --unbzip2.
+ (decode_options): Use xget_version instead of get_version.
+ Check for overflow with -b and -L and RECORD_SIZE_OPTION.
+ Replace invocations of check_decimal with xstrtoumax.
+
+ * tests/preset.in (echo_n, echo_c): Remove.
+
+ * tests/after: Don't rely on $echo_c and $echo_n.
+
+ * lib/addext.c, lib/dirname.c, lib/lchown.c, lib/lchown.h,
+ lib/malloc.c, lib/mktime.c, lib/realloc.c, lib/strtol.c, lib/strtoul.c,
+ lib/strtoull.c, lib/strtoumax.c, lib/utime.c, lib/xstrtol.c,
+ lib/xstrtol.h, lib/xstrtoul.c, lib/xstrtoumax.c,
+ m4/Makefile.am.in, m4/README, m4/ccstdc.m4, m4/d-ino.m4,
+ m4/gettext.m4, m4/inttypes_h.m4, m4/isc-posix.m4,
+ m4/jm-mktime.m4, m4/largefile.m4, m4/lcmessage.m4,
+ m4/malloc.m4, m4/progtest.m4, m4/realloc.m4, m4/uintmax_t.m4,
+ m4/ulonglong.m4, m4/utimbuf.m4, m4/utime.m4, m4/utimes.m4,
+ m4/xstrtoumax.m4: New files.
+
+ * configure.in(fp_PROG_ECHO): Remove; no longer needed.
+ (AC_SYS_LARGEFILE): Renamed from AC_LFS.
+ (jm_AC_HEADER_INTTYPES_H): Replaces inline code.
+ (jm_STRUCT_DIRENT_D_INO, jm_AC_TYPE_UINTMAX_T, jm_AC_PREREQ_XSTRTOUMAX): Add.
+ (AC_CHECK_FUNCS): Remove lchown.
+ (AC_REPLACE_FUNCS): Remove basename, dirname.
+ Add lchown, strtol, strtoul.
+ (jm_FUNC_MKTIME): Add.
+ (LIBOBJS): Replace .o with $U.o, so that the .o files in LIBOBJS
+ are also built via the ANSI2KNR-filtering rules.
+ Use a no-op line to work around bug in automake 1.4 with malloc and
+ realloc.
+ (AC_OUTPUT): Add m4/Makefile.
+
+ * lib/Makefile.am (EXTRA_DIST):
+ Add lchown.c, malloc.c, mktime.c, realloc.c,
+ strtol.c, strtoul.c, strtoull.c, strtoumax.c, utime.c.
+ (noinst_HEADERS): Add lchown.h, modechange.h, xstrtol.h.
+ (libtar_a_SOURCES): Add addext.c, basename.c, xstrtol.c,
+ xstrtoul.c, xstrtoumax.c. Remove getversion.c.
+ ($(srcdir)/getdate.c:): Remove `expect conflicts' line.
+
+ * src/system.h (uintmax_t): Don't declare; configure now does this.
+
+ * src/common.h (backup_type): New decl.
+ * src/common.h, src/misc.c, src/tar.c:
+ Move include of backupfile.h to common.h.
+
+ * src/misc.c (maybe_backup_file):
+ Pass backup_type to find_backup_file_name.
+
+ * src/list.c (print_header): Change sizes of uform and gform from 11 to
+ UINTMAX_STRSIZE_BOUND.
+
+ * doc/tar.texi: Remove --bzip2.
+ Fix @xref typos reported by latest makeinfo.
+
+ * Makefile.am (ACLOCAL_AMFLAGS): New macro.
+ (SUBDIRS): Add m4.
+ (M4DIR, ACINCLUDE_INPUTS): New macros.
+ ($(srcdir)/acinclude.m4): New rule.
+
+ * acconfig.h (ENABLE_NLS, HAVE_CATGETS, HAVE_GETTEXT,
+ HAVE_INTTYPES_H, HAVE_LC_MESSAGES, HAVE_STPCPY): Remve #undefs;
+ now generated automatically by autoconf.
+
+1999-05-15 Paul Eggert <eggert@twinsun.com>
+
+ * doc/tar.texi: Remove -y.
+
+1999-04-09 Paul Eggert <eggert@twinsun.com>
+
+ * src/system.h (INT_STRLEN_BOUND): Fix off-by-factor-of-10 typo
+ (we were allocating too much storage).
+ (uintmax_t): Don't declare; configure now does this.
+
+ * ABOUT-NLS: Update to gettext 0.10.35 edition.
+
+1999-03-22 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): version 1.12.64010
+
+ * acinclude.m4 (AC_LFS_FLAGS):
+ Don't use -mabi=n32 with GCC on IRIX 6.2; it's the default.
+ (AC_LFS): -n32, -o32, and -n64 are CPPFLAGS, not CFLAGS.
+ (jm_FUNC_MALLOC, jm_FUNC_REALLOC): New macros.
+
+ * configure.in (jm_FUNC_MALLOC, jm_FUNC_REALLOC):
+ New macros; needed for latest GNU xmalloc.c.
+
+ * Makefile.am (noinst_HEADERS): Add quotearg.h, xalloc.h.
+ (libtar_a_SOURCES): Add quotearg.c.
+ * list.c: Include <quotearg.h>.
+ (from_oct): Add forward decl.
+ (read_header): Return HEADER_FAILURE if we can't parse the checksum.
+ (from_oct): Report an error only if TYPE is nonzero.
+ Quote any funny characters in bad header.
+
+1999-03-20 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): version 1.12.64009
+
+ * acinclude.m4 (AC_LFS_FLAGS): Add support for IRIX 6.2 and later.
+ (AC_LFS_SPACE_APPEND): Assume $2 is quoted properly; all callers
+ changed.
+ (AC_LFS): Simplify AIX revision number test.
+
+1999-03-17 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): version 1.12.64008
+
+ * configure.in (AC_VALIDATE_CACHED_SYSTEM_TUPLE):
+ Remove; it doesn't work that well
+ with AC_CANONICAL_HOST.
+ (fp_WITH_INCLUDED_MALLOC): Remove; we'll just use the system malloc.
+
+ * Makefile.am (EXTRA_DIST): Remove AC-PATCHES, AM-PATCHES, BI-PATCHES.
+
+ * Makefile.am (EXTRA_DIST): Remove gmalloc.c.
+
+ * acinclude.m4 (fp_WITH_INCLUDED_MALLOC): Remove.
+
+ * tar.texi: Fix bug-report addr.
+
+ * README: Remove --with-included-malloc.
+ Upgrade version numbers of build software.
+
+1999-03-07 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): Version 1.12.64007.
+
+ * acinclude.m4 (AM_WITH_NLS): Port to Solaris 2.5.1,
+ where bindtextdomain and gettext require -lintl.
+ (AC_LFS_FLAGS): Simplify so that it only gets the flags;
+ `no' means it failed.
+ (AC_LFS_SPACE_APPEND, AC_LFS_MACRO_VALUE): New macros.
+ (AC_LFS): Use them. Set _FILE_OFFSET_BITS, _LARGEFILE_SOURCE, and
+ _LARGE_FILES from LFS_CFLAGS, so that in the normal case we don't need
+ to add anything to the command line (it's all in config.h).
+ Put any extra -D and -I options into CPPFLAGS, the rest into CFLAGS.
+
+1999-03-01 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): Version 1.12.64006.
+
+ * acinclude.m4 (AC_LFS_FLAGS): Port to AIX 4.2.
+
+ * src/list.c: (gid_from_oct, major_from_oct, minor_from_oct,
+ mode_from_oct, off_from_oct, size_from_oct, time_from_oct,
+ uid_from_oct, uintmax_from_oct): Use TYPE_MAXIMUM instead of macros
+ like OFF_MAX, which are not reliable
+ (e.g. OFF_MAX in AIX 4.2 is incorrect).
+ * src/system.h (GID_MAX, MAJOR_MAX, MINOR_MAX, MODE_MAX, OFF_MAX,
+ SIZE_MAX, TIME_MAX,UID_MAX, UINTMAX_MAX): Remove; no longer used.
+
+ * src/incremen.c (get_directory_contents):
+ Don't use statx if _LARGE_FILES; it doesn't work under AIX 4.2.
+ Have statx depend on STX_HIDDEN, not AIX.
+
+ * src/create.c (to_oct):
+ New parameter substitute, giving a substitute value to use
+ when the original value is out of range. Do not append a space to the
+ output; modern tars don't. When a value is out of range, specify the
+ maximum value, not the number of bits.
+ (GID_NOBODY, UID_NOBODY): New macros.
+ (gid_to_oct, uid_to_oct): Use them as substitutes.
+ (finish_header): Do not assume that UINTMAX_TO_OCT appends a space.
+ (dump_file): Check whether the file changed as we read it.
+
+ * src/rmt.c (main): Remove suspicious AIX/386 code.
+
+1999-02-19 Paul Eggert <eggert@twinsun.com>
+
+ * intl/localealias.c (read_alias_file): Don't assume that memcpy
+ returns a type compatible with char *; it doesn't on SunOS
+ 4.1.4 with Sun cc, since <string.h> doesn't declare memcpy.
+
+ * NEWS, configure.in (AM_INIT_AUTOMAKE): Version 1.12.64005.
+
+ * src/tar.c (long_options, usage): Prefer --unbzip2 to --bunzip2.
+ * doc/tar.texi: Add --bzip2, --unbzip2 options.
+
+ * configure.in (AC_CANONICAL_HOST, AC_VALIDATE_CACHED_SYSTEM_TUPLE):
+ Add.
+ (AC_LINK_FILES): Omit; AM_GNU_GETTEXT now does this.
+ (AC_OUTPUT): Omit munging of po/Makefile; AM_GNU_GETTEXT now does this.
+ * acinclude.m4 (AM_WITH_NLS):
+ Update to latest gettext version (serial 5).
+ (AC_LFS_FLAGS): New macro
+ (AC_LFS): Use it. Append to CFLAGS, LDFLAGS, LDLIBS instead of
+ working only with unset variables. Append to CFLAGS, not CPPFLAGS.
+ Work properly in cross-compilation scenario, by checking for getconf
+ with AC_CHECK_TOOL and by ditching uname in favor of
+ AC_CANONICAL_HOST and $host_os. Add --disable-lfs option.
+
+ * lib/getdate.y: Update to fileutils 4.0 getdate.y, with one patch:
+ replace FORCE_ALLOCA_H with HAVE_ALLOCA_H.
+ * lib/Makefile.am (AUTOMAKE_OPTIONS): Append ../src/ansi2knr,
+ since getdate.y now uses ANSI code.
+
+ * config.guess, config.sub: New files; taken from automake 1.4.
+
+ * intl/Makefile.in, intl/VERSION, intl/bindtextdom.c,
+ intl/cat-compat.c, intl/dcgettext.c, intl/dgettext.c,
+ intl/explodename.c, intl/finddomain.c, intl/gettext.c,
+ intl/gettext.h, intl/gettextP.h, intl/hash-string.h,
+ intl/l10nflist.c, intl/libgettext.h, intl/loadinfo.h,
+ intl/loadmsgcat.c, intl/localealias.c, intl/textdomain.c:
+ Update to GNU gettext 0.10.35, with patches as per GCC snapshot 990109.
+
+1999-02-01 Paul Eggert <eggert@twinsun.com>
+
+ * src/tar.c: Update copyright.
+
+ * NEWS: 1.12.64004
+
+1999-02-01 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in: Version 1.12.64004
+
+ * configure.in (AC_LFS): Use this macro, instead of open-coding it.
+
+ * acinclude.m4 (AC_LFS, AM_PROG_CC_STDC): New macros.
+
+ * src/extract.c (extract_archive): Fix bug when extracting sparse
+ files: they were trashing the tar file header.
+
+ * src/tar.c: (long_options, usage, OPTION_STRING, decode_options):
+ Add -y or --bzip2 or --bunzip2 option.
+
+1999-01-30 Paul Eggert <eggert@twinsun.com>
+
+ * src/names.c (cached_no_such_uname, cached_no_such_gname,
+ cached_no_such_uid, cached_no_such_gid): New vars.
+ (uid_to_uname, gid_to_gname, uname_to_uid, gname_to_gid):
+ Cache failures, too.
+
+ * src/tar.c (decode_options):
+ Don't pass names longer than UNAME_FIELD_SIZE to
+ uname_to_uid, as it messes up the cache. Similarly for gname_to_uid.
+
+1999-01-27 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in: Version 1.12.64003
+
+ * src/buffer.c (backspace_output, close_archive): Cast
+ rmtlseek position arg to off_t, for benefit of K&R compilers
+ with long long.
+ * src/compare.c (verify_volume): Likewise.
+
+ * NEWS, configure.in: Version 1.12.64002
+
+ * src/create.c (gid_to_oct, major_to_oct, minor_to_oct, mode_to_oct,
+ off_to_oct, size_to_oct, time_to_oct, uid_to_oct):
+ Cast arg to uintmax_t for benefit of pre-ANSI compilers with long long.
+ * src/list.c: (gid_from_oct, major_from_oct, minor_from_oct,
+ mode_from_oct, off_from_oct, size_from_oct, time_from_oct,
+ uid_from_oct): Likewise.
+
+1999-01-25 Paul Eggert <eggert@twinsun.com>
+
+ * incremen.sh: Fix timing bug in regression test.
+
+1999-01-22 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, configure.in: Update version
+
+ * Makefile.am (localedir): Change to $(datadir)/locale.
+ (DEFS): New macro, defining LOCALEDIR.
+ (tar.o, tar._o, rmt.o, rmt._o): Remove.
+ (INCLUDES): Add -I..
+
+ * Makefile.am (localedir): Change to $(datadir)/locale.
+
+1999-01-21 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, README, configure.in: Unofficial version 1.12.64001.
+
+ * tests/Makefile.am (localedir): Change to $(datadir)/locale.
+ * src/Makefile.am (localedir): Likewise.
+ (DEFS): New macro, defining LOCALEDIR.
+ (tar.o, tar._o, rmt.o, rmt._o): Remove.
+ (INCLUDES): Add `-I..'.
+
+ * tests/incremen.sh: Fix timing bug.
+
+1999-01-20 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, README, configure.in: Unofficial version 1.12.64000.
+ `lfs.7' changed to `64000' in version number
+ to conform to gnits standards.
+
+ * COPYING, INSTALL, doc/texinfo.tex, install-sh, missing,
+ mkinstalldirs, ansi2knr.c: Update to latest public versions.
+
+ Rebuild with automake 1.4 and autoconf 2.13, to work around some
+ porting problems.
+
+1998-12-07 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, README, configure.in: Unofficial version 1.12.lfs.6.
+
+ * src/list.c (read_header):
+ Accept file names as specified by POSIX.1-1996 section 10.1.1.
+
+1998-11-30 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in: Quote the output of uname.
+
+ * src/extract.c (set_stat): chmod after chown even when not root;
+ if we are using --same-owner this is needed e.g. on Solaris 2.5.1.
+
+1998-11-15 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, README, configure.in: Unofficial version 1.12.lfs.5.
+
+ * configure.in (ac_test_CPPFLAGS, ac_test_LDFLAGS, ac_test_LIBS,
+ ac_getconfs, ac_result): Special case for HP-UX 10.20 or later.
+
+1998-10-28 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, README, configure.in: Unofficial version 1.12.lfs.4.
+
+ * src/system.h (voidstar): Use void * if __STDC__ is defined,
+ not merely nonzero.
+
+ * src/rtapelib.c: Don't use rexec code unless compiled with WITH_REXEC.
+ On many installations, rexec is disabled.
+
+1998-08-07 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, README, configure.in: Unofficial version 1.12.lfs.3.
+
+ * src/names.c (uid_to_uname, gid_to_gname): Don't used cached name
+ for nameless users and groups.
+
+1998-02-17 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, README, configure.in: Unofficial version 1.12.lfs.2.
+ * NEWS, README: Add explanation of why this isn't an official version.
+
+1998-02-02 Paul Eggert <eggert@twinsun.com>
+
+ * NEWS, README, configure.in: Unofficial version 1.12.lfs.1.
+ This is an unofficial version.
+
+1997-12-17 Paul Eggert <eggert@twinsun.com>
+
+ * src/incremen.c (ST_DEV_MSB): New macro.
+ (NFS_FILE_STAT): Use most significant bit of st_dev,
+ even if it's unsigned.
+
+1997-12-08 Paul Eggert <eggert@twinsun.com>
+
+ * src/system.h (ST_NBLOCKS): Fix typo in definition.
+
+1997-11-19 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (HAVE_INTTYPES_H):
+ Don't ignore cache variable if it's already set.
+
+1997-11-10 Paul Eggert <eggert@twinsun.com>
+
+ * src/rmt.c (main): Don't assume mt_count is of type daddr_t.
+ * src/delete.c (records_read): Now off_t.
+ (move_archive): Don't assume mt_count is of type daddr_t.
+
+1997-10-30 Paul Eggert <eggert@twinsun.com>
+
+ * configure.in (CPPFLAGS, LDFLAGS, LIBS):
+ Set to appropriate values if large file support
+ needs explicit enabling.
+ (HAVE_INTTYPES_H, HAVE_ST_FSTYPE_STRING, daddr_t, major_t, minor_t,
+ ssize_t):
+ New macros to configure.
+ (AC_TYPE_MODE_T, AC_TYPE_PID_T, AC_TYPE_OFF_T): Add.
+
+ * acconfig.h (daddr_t, HAVE_INTTYPES_H, HAVE_ST_FSTYPE_STRING,
+ major_t, minor_t, ssize_t): New macros.
+
+ * src/arith.h (TARLONG_FORMAT):
+ Fix typo: %uld -> %lu. Use unsigned when long long
+ (%lld -> %llu).
+ (add_to_tarlong_helper, mult_tarlong_helper): 2nd arg is now unsigned long.
+ (add_to_tarlong, mult_tarlong): Cast 2nd arg to unsigned long.
+
+ * src/arith.c (add_to_tarlong_helper, mult_tarlong_helper):
+ 2nd arg is now unsigned long.
+
+ * src/rmt.c (allocated_size): Now size_t, and now initialized to 0.
+ (prepare_record_buffer): Arg is now size_t.
+ Remove now-useless casts.
+
+ (main): Use `long' for status, so that it can store ssize_t.
+ Use daddr_t, mode_t, size_t, off_t when appropriate.
+ Convert daddr_t and off_t values ourselves, since they might be longer
+ than long. Convert other types using `long' primitives.
+ When processing MTIOCTOP, do not try to pass resulting
+ count back, since it won't work (it could be too large) and it's
+ not expected anyway.
+
+ * src/update.c:
+ (append_file) Use off_t, size_t, ssize_t when appropriate. Remove
+ now-useless casts. Use unsigned long to print *_t types, except use
+ STRINGIFY_BIGINT for off_t.
+ (update_archive): Cast -1 to dev_t when necessary.
+
+ * src/tar.c (check_decimal):
+ Now returns 1 if successful, 0 otherwise, and returns
+ uintmax_t value into new arg. Check for arithmetic overflow.
+ (decode_options): Avoid overflow if record_size fits in size_t but not int.
+ Check for overflow on user or group ids.
+
+ * src/compare.c (diff_init, process_rawdata, read_and_process,
+ diff_sparse_files, diff_archive):
+ Use off_t, pid_t, size_t, ssize_t when appropriate.
+ Remove now-useless casts. Use unsigned long to print *_t types,
+ except use STRINGIFY_BIGINT for off_t.
+
+ (process_noop, process_rawdata, process_dumpdir, read_and_process):
+ Size arg is now size_t.
+
+ (diff_sparse_files): Arg is now off_t. Check for size_t overflow
+ when allocating buffer.
+
+ * src/rtapelib.c:
+ (do_command, rmt_open__, rmt_read__, rmt_lseek__, rmt_ioctl__):
+ Use pid_t, size_t, ssize_t when appropriate. Remove now-useless casts.
+ Use unsigned long to print *_t types, except use STRINGIFY_BIGINT for
+ off_t.
+
+ (get_status_string, get_status_off): New function.
+ (get_status): Now returns long, so that it can store ssize_t.
+ Invoke get_status_string to do the real work.
+ (rmt_read__, rmt_write__): Now returns ssize_t. Size arg is now size_t.
+ (rmt_lseek__): Now returns off_t, using new get_status_off function.
+ (rmt_ioctl__): Convert mt_count by hand,
+ since it might be longer than long.
+
+ * src/mangle.c (extract_mangle):
+ Check for overflow when converting off_t to size_t.
+ Use off_t, size_t when appropriate. Remove now-useless casts.
+
+ * src/system.h (mode_t): Remove; now done by autoconf.
+ (ST_NBLOCKS): Do not overflow if st_size is near maximum.
+ Return number of ST_NBLOCKSIZE-byte blocks,
+ not number of 512-byte blocks;
+ this also helps to avoid overflow.
+ (st_blocks): Declare if needed.
+ (ST_NBLOCKSIZE): New macro.
+ (<limits.h>, <inttypes.h>): Include if available.
+ (CHAR_BIT): New macro.
+ (uintmax_t): New typedef.
+ (TYPE_SIGNED, TYPE_MINIMUM, TYPE_MAXIMUM, INT_STRLEN_BOUND,
+ UINTMAX_STRSIZE_BOUND, GID_MAX, MAJOR_MAX, MINOR_MAX, MODE_MAX,
+ OFF_MAX, SIZE_MAX, TIME_MAX, UID_MAX, UINTMAX_MAX): New macros.
+
+ * src/names.c (name_init):
+ Fix typo in error message: FILE* was passed, but char*
+ was wanted.
+
+ (read_name_from_file, name_gather, addname, name_match, name_scan,
+ add_exclude): Use size_t when appropriate. Remove now-useless casts.
+
+ (exclude_pool_size, allocated_exclude_pool_size): Now size_t.
+
+ * src/extract.c (newdir_umask, current_umask): Now mode_t.
+ (extract_sparse_file): Args now use off_t.
+
+ (set_mode, set_stat, make_directories, extract_sparse_file,
+ extract_archive): Use off_t, size_t, ssize_t when appropriate. Remove
+ now-useless casts. Use unsigned long to print *_t types, except use
+ STRINGIFY_BIGINT for off_t.
+
+ * src/misc.c (quote_copy_string):
+ Use size_t when appropriate. Remove now-useless casts.
+
+ * src/list.c (read_and, list_archive, read_header, decode_mode,
+ print_header, print_for_mkdir):
+ Use mode_t, off_t, size_t when appropriate. Remove
+ now-useless casts. Use unsigned long to print *_t types, except use
+ STRINGIFY_BIGINT for off_t.
+
+ (read_header): Check for overflow when converting header size.
+
+ (from_oct): Now static. Now returns uintmax_t. `where' arg is now
+ const char *. Size arg is now size_t. Now takes new type and maxval
+ args. Compute result using uintmax_t, not long. Report error if
+ field does not contain octal number in range.
+ (gid_from_oct, major_from_oct, minor_from_oct, mode_from_oct,
+ off_from_oct, size_from_oct, time_from_oct, uid_from_oct,
+ uintmax_from_oct): New functions.
+
+ (stringify_uintmax_t_backwards): New function.
+
+ (decode_mode, print_for_mkdir): Mode arg is now mode_t.
+ (skip_file): Offset arg is now off_t.
+
+ * src/buffer.c (record_start_block, save_totsize, save_sizeleft,
+ real_s_totsize, real_s_sizeleft, current_block_ordinal):
+ Now off_t.
+ (write_error): Arg is now ssize_t.
+ (child_pid): Now pid_t.
+ (available_space_after): Now size_t.
+
+ (child_open_for_compress, child_open_for_uncompress, flush_write,
+ open_archive, flush_write, write_error, flush_read, close_archive):
+ Use pid_t, ssize_t, size_t when appropriate. Remove now-useless
+ casts. Use unsigned long to print *_t types, except use
+ STRINGIFY_BIGINT for off_t.
+
+ * src/delete.c (records_read): Now daddr_t.
+ (move_archive): Arg is now daddr_t. Check for overflow when
+ computing offset.
+ (move_archive, delete_archive_members): Use daddr_t, off_t when
+ appropriate. Remove now-useless casts.
+
+ * src/rmt.h (rmt_read__, rmt_write__): Now returns ssize_t.
+ (rmt_lseek): Now returns off_t.
+
+ * src/create.c (to_oct):
+ Now static. Value arg is now uintmax_t. Accept new args
+ giving name of type of octal field, for error messages. Report an
+ error if the value is too large to fit in the field.
+ (gid_to_oct, major_to_oct, minor_to_oct, mode_to_oct, off_to_oct,
+ size_to_oct, time_to_oct, uid_to_oct, uintmax_to_oct): New functions.
+
+ (write_eot, write_long, finish_header, deal_with_sparse,
+ finish_sparse_file, dump_file): Use dev_t, off_t, ssize_t, size_t when
+ appropriate. Remove now-useless casts. Use unsigned long to print
+ *_t types, except use STRINGIFY_BIGINT for off_t.
+
+ (find_new_file_size): 1st arg is now off_t*.
+ (finish_sparse_file): Args now use off_t, not long.
+ Check for lseek error.
+ (create_archive, dump_file): Cast -1 to dev_t when necessary.
+ (dump_file): Device arg is now dev_t.
+ Avoid overflow when testing whether file has holes
+ by using the new ST_NBLOCKSIZE macro.
+
+ * src/incremen.c (struct accumulator, add_to_accumulator,
+ get_directory_contents, add_hierarchy_to_namelist, gnu_restore):
+ Use size_t for sizes.
+ (struct directory, get_directory_contents, add_hierarchy_to_namelist):
+ Use dev_t, ino_t for devices and inodes.
+ (gnu_restore): Use off_t for file offsets.
+ (struct directory): Use char for flags. Add new flag `nfs'.
+ (nfs): New constant
+ (NFS_FILE_STAT): New macro.
+ (note_directory): Accept struct stat * instead of
+ device and inode number. All callers changed.
+ (note_directory, get_directory_contents):
+ Use NFS_FILE_STAT to determine whether directory is an NFS directory.
+ (write_dir_file): Cast time_t to unsigned long before printing as %lu.
+
+ * src/common.h (record_size, struct name, struct sp_array,
+ available_space_after):
+ Use size_t for sizes.
+ (save_sizeleft, save_totsize, current_block_ordinal, skip_file):
+ Use off_t for file offsets.
+ (struct name): dir_contents is now const char *, not char *.
+ (dump_file, get_directory_contents): Use dev_t for devices.
+ (to_oct): Remove decl.
+ (GID_TO_OCT, MAJOR_TO_OCT, MINOR_TO_OCT, MODE_TO_OCT, SIZE_TO_OCT,
+ UID_TO_OCT, UINTMAX_TO_OCT, OFF_TO_OCT, TIME_TO_OCT, STRINGIFY_BIGINT,
+ GID_FROM_OCT, MAJOR_FROM_OCT, MINOR_FROM_OCT, MODE_FROM_OCT,
+ OFF_FROM_OCT, SIZE_FROM_OCT, TIME_FROM_OCT, UID_FROM_OCT,
+ UINTMAX_FROM_OCT): New macros.
+ (gid_to_oct, major_to_oct, minor_to_oct, mode_to_oct, off_to_oct,
+ size_to_oct, time_to_oct, uid_to_oct, uintmax_to_oct,
+ stringify_uintmax_t_backwards, gid_from_oct, major_from_oct,
+ minor_from_oct, mode_from_oct, off_from_oct, size_from_oct,
+ time_from_oct, uid_from_oct, uintmax_from_oct): New decls.
+ (print_for_mkdir): 2nd arg is now mode_t.
+
+See ChangeLog.1 for earlier changes.
+
+
+Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GNU tar.
+
+GNU tar is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU tar is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU tar; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
diff --git a/contrib/tar/ChangeLog.1 b/contrib/tar/ChangeLog.1
new file mode 100644
index 0000000..050398e
--- /dev/null
+++ b/contrib/tar/ChangeLog.1
@@ -0,0 +1,5887 @@
+Currently there is just one ChangeLog file for tar, but
+there used to be separate ChangeLog files for each subdirectory.
+This file records what used to be in those separate files.
+
+Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+Free Software Foundation, Inc.
+
+This file is part of GNU Tar.
+
+GNU Tar is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Tar is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Tar; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+
+
+----- ChangeLog -----
+
+1997-04-25 François Pinard <pinard@iro.umontreal.ca>
+
+ * Release 1.12.
+
+ * configure.in: Check for the inline keyword.
+
+1997-04-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (BABYL): Delete admin/RMAIL, renamed rmail/announce.
+
+ * PORTS: New file.
+ (EXTRA_DIST): Adjusted.
+
+1997-04-23 François Pinard <pinard@iro.umontreal.ca>
+
+ * BI-PATCHES: Patches for Bison 1.25.
+ * Makefile.am (EXTRA_DIST): Adjusted.
+
+ * configure.in (AC_PROG_INSTALL): Call deleted. AM_INIT_AUTOMAKE
+ takes care of this already.
+
+1997-04-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11q.
+
+ * configure.in: Use gethostent instead of gethostbyname while
+ checking for -lnsl. It seems SINIX systems require this.
+ Reported by Bruno Haible.
+
+1997-04-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * acinclude.m4: New fp_WITH_INCLUDED_MALLOC macro.
+ * configure.in: Use it instead of the HP/UX test for GNU malloc.
+ Reported by Bruno Haible.
+
+1997-04-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11p.
+
+ * acinclude.m4 (cl_FUNC_GMALLOC): New macro, yet still unused, as
+ it requires config.guess. I have to think more about this.
+ Reported by Bruno Haible.
+
+1997-04-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * AC-PATCHES: Patches for Autoconf 2.12.
+ * AM-PATCHES: Patches for Automake 1.1n.
+ * Makefile.am (EXTRA_DIST): Adjusted.
+
+1997-04-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Ensure all cpp directives are left justified.
+ Reported by Kaveh R. Ghazi.
+
+1997-04-12 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Add fnmatch.o to LIBOBJS if AC_FUNC_FNMATCH
+ says no working copy was found. This is not done automatically.
+ Reported by Bruno Haible, Bryant Fujimoto, John David Anglin,
+ Kaveh R. Ghazi, Laurent Caillat-Vallet, Sakai Kiyotaka and
+ Santiago Vila Doncel.
+
+1997-04-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Much simplify the -lsocket and -lnsl tests.
+ Reported by Larry Schwimmer.
+
+1997-04-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11o.
+
+ * configure.in: Do not check for gettimeofday anymore.
+
+ * configure.in: Do not anymore blindly add -lnsl if gethostname
+ is found, nor -lsocket if setsockopt is found. Instead, for
+ resolving setsockopt, try none, -lsocket, and -lsocket -lnsl,
+ in that order. For resoving gethostbyname, try none, than -lnsl.
+ Reported by Ariel Faigon, Heiko Schlichting, Jean-Philippe
+ Martin-Flatin, John J. Szetela, John R. Vanderpool, Kaveh
+ R. Ghazi, Larry Schwimmer, Marcus Daniels, Mark Bynum and
+ Russell Cattelan.
+
+1997-04-10 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Define _GNU_SOURCE to get FNM_LEADIR_DIR, etc.
+ * acconfig.h: Document _GNU_SOURCE.
+ Reported by Andreas Jaeger, Becki Kain, Brendan Kehoe, David
+ N. Brown, J. Dean Brock, James V. DI Toro III, Jeffrey Mark
+ Siskind, Jürgen Reiss, Paul Eggert, Roland McGrath, Rolf
+ Niepraschk, Roman Gollent, Thomas Bushnell n/BSG and Ulrich
+ Drepper.
+
+1997-03-26 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in (ALL_LINGUAS): Add it.
+
+1997-03-20 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Require Autoconf 2.12.
+
+1997-02-25 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Use AM_CONFIG_HEADER and AM_GNU_GETTEXT instead
+ of AC_CONFIG_HEADER and ud_GNU_GETTEXT. Use AC_FUNC_FNMATCH
+ instead of AM_FUNC_FNMATCH. Do not take care anymore of stamp-h
+ in AC_OUTPUT, leave it to Automake.
+ * acinclude.m4: Replaced whole, from elsewhere.
+ * Makefile.am (EXTRA_DIST): Leave README-alpha to Automake.
+
+1997-02-12 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Delete README-alpha code, Automake handles it now.
+
+1996-11-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.14.
+
+ * Makefile.am (BABYL): Add admin/RMAIL.
+
+ * configure.in: Check for sys/buf.h, as BSD/OS.
+ Reported by Dan Reish.
+
+1996-11-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Replace a missing basename.
+ Reported by Bryant Fujimoto, Erick Branderhorst, Greg Black, John
+ David Anglin, John J. Szetela, Kaveh R. Ghazi, Kurt Jaeger, Marcus
+ Daniels, Santiago Vila Doncel and William Bader.
+
+1996-11-08 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.13.
+
+ * configure.in: Replace a missing dirname.
+
+1996-10-07 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Clean out some macro calls made useless since
+ AM_INIT_AUTOMAKE implies them.
+
+1996-09-20 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Do not check anymore for regex.
+
+1996-09-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.12
+
+ * configure.in: Check echo for newline suppression.
+
+1996-09-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Do not add open3.o to LIBOBJS anymore.
+
+1996-09-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in (ALL_LINGUAS): Add pl.
+
+1996-09-04 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in (AC_OUTPUT): Prepare tests/Makefile and tests/preset.
+ * Use AM_ version of fp_ macros.
+
+ * Makefile.am (SUBDIRS): Add tests/.
+
+1996-07-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.11.
+
+ * configure.in: Use AC_PREREQ(2.10).
+
+1996-07-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in (ALL_LINGUAS): Add nl.
+ Reported by Erick Branderhorst.
+
+1996-07-12 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.10.
+
+ * configure.in (ALL_LINGUAS): Add ko and sl.
+
+1996-05-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check for fsync, and linux/fd.h.
+ Reported by Marty Leisner.
+
+1996-04-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (EXTRA_DIST): New name for DIST_OTHERS.
+
+ * configure.in (ALL_LINGUAS): Add no.
+
+ * Makefile.am (BABYL): Consider rmail/* instead of rmail/*/*.
+
+1996-02-28 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Avoid PROGRAMS, instead use RMT to substitute rmt.
+ * Makefile.am (SUBDIRS): Use intl and po instead of @INTLSUB@ and
+ @POSUB@.
+
+ * configure.in: Check for poll.h and stropts.h.
+ Check for nap, napms, poll, select and usleep.
+
+1996-02-12 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: Remove CONFIG_HEADER, not required by Automake 0.29.
+ * configure.in: Temporarily remove a \ in AC_OUTPUT for automake.
+
+1996-02-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check size of unsigned long (assume 32 bits if
+ cross-compiling) and long long (assume not available).
+
+1996-01-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (AUTOMAKE_OPTIONS): Select gnits and dist-shar.
+ (dist-zoo): New goal, experimental for now.
+
+1996-01-07 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: Force distribution of BACKLOG.
+ Reported by Jonathan Thornburg.
+
+ * Makefile.am: Declare BABYL. Force distribution of AUTHORS
+ and rebox.el. Add id, ID and dist-shar targets. Add parts of
+ previous Makefile.in as FIXME comments.
+
+1995-12-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Ensure there is a link for libintl.h.
+ Reported by Daniel S. Barclay, Göran Uddeborg, Jonathan Thornburg,
+ Ken Raeburn and Minh Tran-Le.
+
+1995-12-29 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.9.
+
+ * Makefile.am: New file.
+
+ * configure.in: Decide if README-alpha should be distributed.
+ From Ulrich Drepper.
+
+1995-12-28 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in (AC_OUTPUT): Call sed for po/Makefile.in.
+
+ * Makefile.in: Distribute ABOUT-NLS rather than NLS, and do not
+ distribute config.guess or config.sub anymore.
+
+ * configure.in: Test for lchown.
+
+1995-12-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Prefer avoiding union wait, and use it only if
+ using int fails. This turns around the previous test, as directly
+ checking for union wait is seemingly seeking for trouble.
+ Reported by Alan Bawden, Chris Arthur, Coranth Gryphon,
+ Jean-Philippe Martin-Flatin, Robert Bernstein and Tarang Kumar
+ Patel.
+
+ * configure.in: Check for strerror, so lib/error.c will not try to
+ define sys_errlist in the case strerror is already provided.
+ Reported by Coranth Gryphon, Chris Arthur, David J. MacKenzie,
+ Erich Stefan Boleyn, Greg Black, Jason R. Mastaler, Michael
+ Innis Bushnell, Robert Bernstein, Santiago Vila Doncel, Skip
+ Montanaro and Thomas Krebs.
+
+ * configure.in: Quote the selected shell. I wonder why this
+ error did not show up before!
+
+ * configure.in: Check <sys/tprintf.h> and <sys/device.h> for BSDi.
+ Reported by Chris Arthur and Skip Montanaro.
+
+1995-12-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Be more systematic at caching test results.
+ Reported by Ulrich Drepper.
+
+ * configure.in: While checking for remote tape header files, only
+ include <sgtty.h> if it was found to exist.
+
+ * configure.in: Prefer #if to #ifdef while checking for open3.
+
+1995-11-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check for net/errno.h and sys/inet.h, trying to
+ get EOPNOTSUPP defined.
+
+ * configure.in: Check for sgtty.h.
+
+1995-11-06 François Pinard <pinard@iro.umontreal.ca>
+
+ * acconfig.h: Document HAVE_STPCPY for the time being. I do not
+ understand yet why this is mandatory: it should be automatic
+ from AC_CHECK_FUNCS(stpcpy) in aclocal.m4, through autoheader.
+
+ * configure.in: Use fp_FUNC_FNMATCH, to get around non-working
+ versions on SCO Unix 3.2v4.2, and Solaris.
+ Reported by Chad Hurwitz, Dennis Pixton, Per Foreby, Richard
+ Westerik, Robert Weiner and Tom Tromey.
+
+1995-10-27 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Add /usr/bin/rcmd as a possible remote shell, as
+ this is the name used by SCO Unix 3.2.4.
+ Reported by Bela Lubkin and Rodney Brown.
+
+1995-07-23 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Adapt for GNU gettext 0.8.
+
+1995-07-10 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (default): Define to all.
+
+1995-06-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: For mknod, also include <sys/types.h> prior to
+ <sys/stat.h>, as Ultrix needs this.
+ Reported by Bruce Jerrick, Bryant Fujimoto, Conrad Hughes, Erich
+ Stefan Boleyn, Jason R. Mastaler, Joshua R. Poulson, Jurgen Botz,
+ Serge Granik, Simon Wright, Ulrich Drepper and Vince Del Vecchio.
+
+ * configure.in: Replace execlp as needed (for Minix, mainly).
+
+ * configure.in: Force compilation of lib/open3.c if required.
+ Clean out old NO_OPEN3 code.
+
+1995-06-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Release 1.11.8.
+
+ * Makefile.in (DISTFILES): Distribute config.guess and config.sub.
+ Reported by Ulrich Drepper.
+
+ * acconfig.h, aclocal.m4, configure.in: Last minutes
+ additions, and glimpses to the future gettext 0.6.1.
+ Reported by Ulrich Drepper.
+
+ * acconfig.h: Document HAVE_MKNOD.
+ * configure.in: Test for mknod only once <sys/stat.h> included.
+ Reported by Alan Modra, Ray Dassen and Ulrich Drepper.
+
+ * aclocal.m4: Test for re_rx_search instead of rx_compile, the
+ latter not being exported unless RX_WANT_RX_DEFS is defined.
+ Reported by Alan Modra.
+
+1995-06-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (dist): Do not hide copying rule.
+
+ * configure.in: Adjustments to NLS, so .sed scripts may now all
+ reside in intl/.
+
+1995-06-13 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (pot): New goal, triggering po/tar.pot.
+
+1995-06-07 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Substitute POTFILES by contents of po/POTFILES.
+
+ * configure.in: More adjustments for GNU gettext 0.6.
+ * config.guess, config.sub: New files, all taken from gettext 0.6.
+
+1995-06-04 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (check): New goal.
+
+1995-05-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (DISTFILES): Do not distribute SUPPORT, now
+ integrated in the documentation.
+ Reported by Karl Berry.
+
+1995-05-28 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check for isascii, not iascii.
+ Reported by Alan Modra, Bruno Haible and Greg McGary.
+
+1995-05-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.7.
+
+ * Makefile.in (DISTFILES): Distribute NLS.
+ * configure.in, acconfig.h: Many adjustments for GNU gettext.
+
+1995-05-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Clean glocale out.
+ * Makefile.in (SUBDIRS): Add po.
+ * Makefile.in (pofile): New goal.
+
+1995-05-08 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Call ud_WITH_NLS, create intl/Makefile.in.
+ Compute size of unsigned short and unsigned int.
+
+ * acconfig.h: Document ENABLE_NLS, HAVE_CATGETS and HAVE_GETTEXT.
+ * Makefile.in: Process intl subdirectory.
+
+ * configure.in (LINGUAS): Add pt.
+ * src/pt.po: New file, for Portuguese.
+ Reported by Antonio Jose Coutinho.
+
+1995-03-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Remove GLOCALE, add LINGUAS, use fp_WITH_CATALOGS.
+ * acconfig.h: Add description for WITH_CATALOGS.
+
+1995-02-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in, Makefile.in: Replace `date' by `echo timestamp'.
+
+1995-02-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Support ID files. Do not distribute TAGS.
+
+1995-02-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (maintainer-clean): New name for realclean.
+
+1995-01-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check for <sys/ioccom.h>.
+ Reported by Joseph E. Sacco.
+
+1995-01-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (DISTFILES): Distribute SUPPORT, with *pre*-releases.
+
+1994-12-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check for isascii.
+ Reported by Bruno Haible.
+
+1994-12-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Use fp_WITH_REGEX.
+ * acconfig.h: Document WITH_REGEX.
+
+1994-12-10 François Pinard <pinard@iro.umontreal.ca>
+
+ * src/de.tt: New file, for German.
+ Reported by Ulrich Drepper.
+
+1994-12-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.6.
+
+ * configure.in: Localize, adapting from how it is done in sharutils.
+
+ * src/fr.tt: New file, for French.
+
+ * configure.in, {,*/}Makefile.in, acconfig.h:
+ Rename PRODUCT to PACKAGE.
+
+1994-11-26 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check for <libintl.h> and <locale.h>.
+
+1994-11-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check for const only after having found possible
+ ANSIfying compiler flags, this is of no use to check it before.
+
+1994-11-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * {,*/}Makefile.in: Clean up, following those of GNU m4. I will
+ not detail all the changes here.
+ * configure.in: Likewise.
+ * acconfig.h: Document PRODUCT and VERSION.
+
+1994-10-04 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Correct shell assignment for ac_cv_path_RSH.
+ Reported by Kaveh R. Ghazi.
+
+1994-09-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Cleanup... Use subshells for all cd's.
+ (MDEFINES): Do not use $(INSTALL...), because ./install-sh will
+ not be relocated correctly.
+ (DISTFILES): Distribute install-sh, not install.sh.
+ (tags): Make only in lib and src.
+ (TAGS): Deleted.
+ (distclean, realclean): Remove config.status.
+ (distclean-local): Don't.
+ (*-recursive): Combine, use sed to strip -recursive in subgoals.
+ (Makefile): Have ./config.status create this Makefile only.
+ (stamp-h): Have ./config.status create config.h only. Do not
+ create stamp-h here, it is now done from configure.
+ (stamp-h.in): Use date instead of touch.
+ * configure.in (AC_OUTPUT): Create stamp-h.
+
+1994-09-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Use fp_ macros for accessing aclocal.m4. Revert
+ _OS_ macros to their previous names, to follow Autoconf.
+
+1994-09-08 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Delete AC_OS_XENIX, now within AC_HEADER_DIRENT.
+
+1994-09-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in (PROGS): Warn if $DEFAULT_ARCHIVE was specified,
+ while not being found on the current system.
+ Reported by Robert Bernstein.
+
+1994-08-31 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Distribute it.
+
+ * Makefile.in (distclean-local): Delete config.log.
+
+1994-08-27 François Pinard <pinard@iro.umontreal.ca>
+
+ * acconfig.h: Document HAVE_UNION_WAIT, no more in Autoconf.
+
+1994-08-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Replace AC_SYS_REMOTE_TAPE by its definition,
+ distillating it around. It is going out of Autoconf.
+ Do not backslash quotes anymore while defining unquoted, this is
+ now corrected in Autoconf.
+
+1994-08-23 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Do not define RTAPELIB nor HAVE_RTAPELIB.
+
+1994-08-22 François Pinard <pinard@iro.umontreal.ca>
+
+ Little cleanup in installation:
+ * configure.in: Do not check for wait3, this function is not used.
+ * Makefile.in: Remove useless RSH substitutions.
+
+ * configure.in: Use `-g -O' instead of `-g' as CFLAGS default
+ value, when GNU C is being used. Delay testing for presets.
+ Reported by Chris Arthur.
+
+1994-08-21 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.5.
+
+ * Makefile.in (BACKLOG, dist, shar): Correct for when a different
+ build directory.
+
+ * configure.in: Check for union wait. Adapted from make 3.71.
+
+ * configure.in: Replace both mkdir and rmdir, not just mkdir,
+ because NS32016 running SysVr2.2 has mkdir and lacks rmdir.
+ Reported by Greg Black.
+
+ * configure.in: Do not try anymore to discover the archive device
+ by looking around for various device names. If the installer does
+ not override it, nicely use `-' as a convenient default.
+ Reported by Andreas Schwab and Kaveh R. Ghazi.
+
+1994-08-20 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Correct a checking message.
+ Reported by Bruno Haible.
+
+1994-08-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Replace AC_PROG_RSH with its expansion. Correct
+ the no/true confusion in tests. Do not substitute RSH anymore in
+ src/Makefile, instead define REMOTE_SHELL in config.h. Replace
+ NO_REMOTE by HAVE_RTAPELIB, with inverted meaning. Substitute
+ RTAPELIB by $Urtapelib.o instead of rtapelib.o.
+ * acconfig.h: Document HAVE_RTAPELIB and REMOTE_SHELL.
+ Reported by Andreas Schwab.
+
+ * configure.in: Checking for remote shell, use the RSH environment
+ variable if set. This is done only when not already in the cache.
+ Reported by Kaveh R. Ghazi.
+
+ * configure.in: Include <sys/types.h> when testing <utime.h>.
+ Reported by Andreas Schwab.
+
+ * configure.in: Also create doc/Makefile.
+ * Makefile.in: Add doc in subdirs, set infodir, update MDEFINES.
+
+1994-08-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Undo the `test -b' patch of 1994-08-05. Ultrix
+ 4.2 test does not know about -b. Grrr...
+ Reported by Kaveh R. Ghazi.
+
+ * configure.in: Check for <sys/gentape.h>, HAVE_SYS_GENTAPE_H
+ is tested in rmt.c. Check for <sys/tape.h>, to avoid playing
+ with M_UNIX anymore in rmt.c.
+ Reported by Daniel R. Guilderson and Kaveh R. Ghazi.
+
+ * configure.in: Use proper function names in AC_CHECK_LIB's.
+ Reported by Alexander Dupuy and Kurt Jaeger.
+
+ * configure.in: Use $LIBOBJS, not LIBOJBS, while adding to it.
+ Reported by Demizu Noritoshi and Kaveh R. Ghazi.
+
+1994-08-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.4.
+
+1994-08-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Decide MTIO_CHECK_FIELD by grepping <sys/mtio.h>.
+ * acconfig.h: Document it.
+ Reported by Ben A. Mesander.
+
+ * Makefile.in: Substitute CC, INSTALL, INSTALL_PROGRAM,
+ INSTALL_DATA, RSH, CFLAGS, LDFLAGS, LIBS, prefix, exec_prefix,
+ binprefix, bindir and libexecdir.
+ (MDEFINES): New, using the previous substitutions.
+ (all, install, uninstall): Use it.
+ Reported by Bruno Haible.
+
+1994-08-13 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check for <sys/wait.h>.
+
+1994-08-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: For <utime.h>, also ensure struct utimbuf is
+ defined by the header file before defining HAVE_UTIME_H. Some
+ systems will not define the structure without _POSIX_SOURCE.
+ * acconfig.h: Document HAVE_UTIME_H.
+ Reported by James W. McKelvey and Robert E. Brown.
+
+ * configure.in: Instead of replacing strstr, check for it, so
+ HAVE_STRSTR gets defined, then replace it explicitely if required.
+
+1994-08-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Updated for Autoconf 2.0.
+
+1994-08-08 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Replace memset, mkdir (and rmdir), rename, strstr,
+ ftruncate, when not found.
+ Reported by Kaveh R. Ghazi (for memset and strstr).
+ Reported by Bruno Haible (for mkdir and rename).
+
+1994-08-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Remove padding test.
+ * acconfig.h: Remove PADDING_IN_TAR_HEADER.
+ Reported by Bruno Haible.
+
+ * configure.in: While defining DEFAULT_ARCHIVE, check for a block
+ device, instead of mere existence. But is `test -b' portable?
+ Test for /dev/fd0, instead of for /dev/fd. Put rct tests last.
+ Reported by Andreas Schwab.
+
+ * configure.in: Define uid_t and gid_t if necessary.
+ Reported by Jonathan I. Kamens.
+
+ * Makefile.in (distclean-local): Delete config.cache.
+ Reported by Thomas Koenig.
+
+ * configure.in: Change malloc_dbg to dmalloc, mutatis mutandi.
+ * acconfig.h: According changes.
+
+ * configure.in: Test for broken stat macros, and for mkfifo.
+
+ * configure.in: Check for ST_BLKSIZE and ST_BLOCKS.
+
+1994-08-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.3.
+
+ * Makefile.in (dist, shar): Distribute the scripts directory.
+
+1994-08-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check for <memory.h>.
+
+1994-07-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: When --with-malloc-dbg, define WITH_MALLOC_DBG and
+ add -lmalloc_dbg to LIBS.
+ * acconfig.h: Document WITH_MALLOC_DBG.
+
+ * configure.in: Try deciding DEVICE_PREFIX and DENSITY_LETTER from
+ the selected DEFAULT_ARCHIVE.
+ * acconfig.h: Document DEVICE_PREFIX and DENSITY_LETTER.
+ Reported by Danny R. Johnston.
+
+1994-07-29 François Pinard <pinard@iro.umontreal.ca>
+
+ * aclocal.m4: Adapt AC_PROTOTYPES to caching.
+
+ * Using configure as generated by a more recent Autoconf solves a
+ problem of rename being rejected on HP-UX in ANSI mode, because of
+ a conflicting prototype from <stdio.h>. In this context, Autoconf
+ now uses ctype.c instead for defining __stub macros.
+ Reported by Alan Modra, Burkhard Plache, Edward Welbourne,
+ Henrik Bakman, Jeffrey Goldberg, Jim Farrell, Kimmy Posey,
+ Michael Maass, Mike Nolan, Richard Lloyd, Robert McGraw,
+ Robert W. Kim, Stefan Skoglund, Tarang Kumar Patel, Tilman
+ Schmidt, Tim Ramsey, Van Snyder and W. Phillip Moore.
+
+1994-07-26 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check for <fcntl.h>. Do not define BSD42, do
+ not look anymore if /vmunix, /sdmach or /../../mach exist.
+ * acconfig.h: Remove BSD42.
+
+1994-07-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Add gmalloc.o to LIBOBJS, instead of AC_SUBST'ing
+ MALLOC. Check for valloc only if gmalloc.o is not being selected.
+ valloc was possibly defined both in "port.h" and GNU malloc.
+ * acconfig.h: Add a description for HAVE_VALLOC.
+ J.T. Conklin, Nelson H.F. Beebe and Tilman Schmidt.
+
+1994-07-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Use provided fnmatch only as a replacement.
+
+ * configure.in: Check for <sys/io/trioctl.h>, needed for
+ defining _IOW and _IOR on the Tektronix XD88.
+ Reported by Kaveh R. Ghazi.
+
+1994-07-20 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (BACKLOG): New goal, for summarizing the
+ maintainance backlog. Distribute file BACKLOG.
+
+1994-07-08 François Pinard <pinard@iro.umontreal.ca>
+
+ * regex.c, regex.h: Use newer versions. This solves a few
+ problems reported by users.
+ Reported by Chris Hopps and John David Anglin.
+
+1994-07-06 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check for <utime.h>.
+
+1994-07-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Substitute DEFAULT_ARCHIVE and DEFAULT_BLOCKING
+ from the environment. Check for /dev/tape first while trying to
+ decide the default archive, because it is often symlinked right.
+ * acconfig.h: Explain DEFAULT_ARCHIVE and DEFAULT_BLOCKING.
+
+ * configure.in: Use AC_SET_MAKE.
+ * Makefile.in: Use @SET_MAKE@.
+ Reported by Jim Meyering.
+
+ * configure.in: Integrate the check, previously in testpad.c,
+ about a needed padding field in the tar header struct.
+ * acconfig.h: Explain PADDING_IN_TAR_HEADER.
+
+1994-07-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Check for -linet, this library is required on
+ a few systems for gettimeofday() or getservbyname(). Also, on ISC
+ 4.0, this avoids a broken version of rename().
+ Reported by Dean Gaudet, Goeran Uddeborg, Mike Rogers and
+ Peder Chr. Norgaard.
+
+ * configure.in: Ensure -lsocket is tested after -lnsl. This is
+ required in particular for SINIX-Z, an SVR4.0 system.
+ Reported by Manfred Weichel and Mark Frost.
+
+ * configure.in: All tests reordered for clarity.
+
+1994-07-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: Use AC_TIME_WITH_SYS_TIME, test for <sys/time.h>.
+ This should solve the problem of multiple inclusions of <time.h>.
+ Also, also check for <sys/timeb.h>, for getdate.y tests this.
+ Reported by Jim Meyering, John Rouillard, Karl Berry and Rick
+ Emerson.
+
+1994-06-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * configure.in: AC_CONST was already added since 1.11.2, but no
+ ChangeLog entry for it, so here is one, with list of reporters.
+ * AIX 3.2 RS/6000 IBM's compiler was unable to compile regex.c,
+ this might be solved already through improved Autoconf tests.
+
+ Reported by Alexey Vovenko, Ben A. Mesander, Bryant
+ Fujimoto, Christian. T. Dum, Christopher Vickery, Dan Bloch,
+ David K. Drum, David Lemson, Demizu Noritoshi, Dimitris
+ Fousekis, Ezra Peisach, Hugh Secker-Walker, Indra Singhal,
+ J.T. Conklin, Jan Hoeglund, Janice Burton, Jeff Siegel,
+ Jim Blandy, John L. Chmielewski, John Rouillard, Jonathan
+ N. Sherman, Kevin D Quitt, Kurt Jaeger, Mark Frost, Matthew
+ Braun, Michael Kubik, Michael Helm, Moritz D. Klingholz,
+ Neil Jerram, Nelson H.F. Beebe, Nick Barron, Paul Eggert,
+ R. Scott Butler, Rob Parry, Ron Guilmette, Scott Grosch,
+ Sherwood and Stephen Saroff.
+
+ * Makefile.in: Completely replaced, lurking at the previous one.
+ At the same time, solve a few minor problems reported by users.
+ The most frequently reported ones pertained to a trailing \ in a
+ comment, and rmt installing in /etc.
+ Reported by Dean Gaudet, Gerben Wierda, James W. McKelvey,
+ John L. Chmielewski, Karl Berry, Mike Rogers, Ralf Suckow and
+ Richard Lloyd.
+
+ * configure.in: Also process lib/Makefile.in and src/Makefile.in.
+ Substitute CFLAGS, LDFLAGS and YFLAGS from the environment.
+ Use AC_CHECKING instead of using echo explicitely.
+ Use AC_HEADER_CHECK(unistd.h) instead of obsolete AC_UNISTD_H.
+
+ * configure.in: Generate a configuration header file. This not
+ only puts less clutter in make output, but also goes around some
+ compilers' limits about the number of allowed -D options.
+ Reported by Nelson H.F. Beebe.
+
+ * acconfig.h: New file.
+
+ * Split distribution into a few subdirectories, for easing
+ maintainance. So far: src, lib, scripts, msdos which are to be
+ distributed; then rmail, texinfo, ARCH and misc to be kept here.
+ * scripts/ChangeLog: Initialized by moving entries related to
+ scripts out of this ChangeLog.
+
+ * Taking over maintenance duties.
+
+
+----- doc/ChangeLog -----
+
+1997-04-23 François Pinard <pinard@iro.umontreal.ca>
+
+ * Release 1.12.
+
+ * Makefile.am (EXTRA_DIST): Remove tar-mew.texi for the release.
+ (tar.dvi) [!PUBLISH]: Delete @smallbook. Call sed in all cases.
+
+1997-04-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11o.
+
+ * Makefile.am (tar.info): Comment about needed makeinfo version.
+ Reported by Sherwood Botsford.
+
+1997-04-10 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (EXTRA_DIST): Add tar-mew.texi.
+
+1997-03-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (tar.dvi): Merely use tar.texi and rely on -I to
+ resolve it in $(srcdir). Remove tmp-tar.info* files right away.
+ (CLEANFILES): Define to tmp-*.
+
+1997-03-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: Rename RENDERING, QUALITY, DRAFT and DEBUG to
+ RENDITION, PUBLISH, DISTRIB and PROOF respectively. Ensure that
+ `@set DISTRIB' gets replaced after macro-expansion and before TeX.
+
+1996-11-06 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.13.
+
+ * getdate.texi: New file, from elsewhere.
+ * tar.texi: Replace a lot of text by an include of getdate.texi.
+ * Makefile.am: Adjusted.
+
+1996-08-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.12.
+
+ * Makefile.am (EXTRA_DIST): Remove texinfo.tex, now that Automake
+ handles it automatically.
+
+1996-07-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.11.
+
+ * Makefile.am (tar.info): Remove -I$(srcdir), which was useless.
+
+1996-07-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (EXTRA_DIST): Include texinfo.tex, until Automake
+ does it automatically.
+
+1996-07-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.10.
+
+ * Makefile.am (EXTRA_DIST): Distribute convtexi.pl, for now.
+
+1996-04-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: Implement rendering levels (QUALITY, DRAFT or DEBUG).
+
+1996-04-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (EXTRA_DIST): New name for DIST_OTHER.
+
+1996-03-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (tar.dvi): Comment about needed makeinfo version.
+ Reported by Jonathan Thornburg.
+
+1996-02-12 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: Replace TEXINFO by info_TEXINFOS for Automake 0.29.
+
+1996-01-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (AUTOMAKE_OPTIONS): Select gnits.
+
+1996-01-08 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: New file.
+ * tar.texi: New name for tar.texinfo.
+
+1995-12-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (check): New goal, doing nothing.
+ Reported by Cesar Romani, Joachim Seelig, Mark Bynum and Ulrich
+ Drepper.
+
+1995-11-29 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (clean): Remove tmp-* files.
+
+1995-11-27 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Use -I$(srcdir) with makeinfo, and -otmp-tar.info
+ so tar.info in build directory does not shadow the real one.
+ (tar.dvi): Depend on version.texi. Add $(srcdir) to TEXINPUTS so
+ texinfo.tex is found, as texi2dvi gets no clue from the file name.
+ (DISTFILES): Also distribute tar.info-8.
+
+1995-11-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (DISTFILES): Distribute ChangeLog.
+ * ChangeLog: New file, extracted from top-level ChangeLog.
+
+1995-06-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Get rid of docwarn.texi, now replaced by
+ the @UNREVISED macro, right into tar.texinfo.
+
+1995-06-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (tar.dvi): First macro-expand tar.texinfo.
+
+1995-06-07 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Use subdir and distdir.
+
+1995-06-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.texinfo: Use header.texi.
+ * Makefile.in: Prepare header.texi from src/tar.h.
+ Distribute it.
+
+1995-05-28 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (DISTFILES): Add tar.info-3.
+ Reported by Bruno Haible.
+
+1995-02-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Replace `date' by `echo timestamp'.
+
+1995-02-13 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Use top_srcdir.
+
+1995-02-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (maintainer-clean): New name for realclean.
+
+1994-12-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (DISTFILES): Include docwarn.texi.
+
+1994-11-07 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (stamp-vti): Use new -r option to date.
+
+1994-11-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (realclean): Also remove stamp-vti.
+
+1994-09-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Cleanup...
+ (texclean): Deleted, merged into mostlyclean.
+ (Makefile): Have ./config.status create this Makefile only.
+
+1994-08-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (tar.info): Make the documentation in the source
+ directory only.
+
+1994-08-21 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Correct for when a different build directory.
+
+ * docwarn.texi: New file.
+ * Makefile.in: Distribute it.
+
+1994-08-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: New file.
+ * tar.texinfo: New file.
+ * texinfo.tex: New, from elsewhere.
+
+
+----- lib/ChangeLog -----
+
+1997-04-25 François Pinard <pinard@iro.umontreal.ca>
+
+ * Release 1.12.
+
+1997-04-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11p.
+
+ The distribution did not have getdate.c updated:
+ * Makefile.am (libtar_a_SOURCES): Use getdate.y, not getdate.c.
+ (EXTRA_DIST): Do not include getdate.y anymore.
+ * getdate.c: Specify $(srcdir)/, to silence GNU make.
+ Reported by Bruno Haible.
+
+1997-04-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (getdate.c): Announce 13 conflicts, not 10.
+ Reported by Bruno Haible, Bryant Fujimoto and Wolfram Wagner.
+
+1997-04-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11o.
+
+ * getdate.h: New file.
+ * Makefile.am: Adjusted.
+
+1997-04-10 François Pinard <pinard@iro.umontreal.ca>
+
+ * modechange.c, modechange.h: New files.
+ * Makefile.am: Adjusted.
+
+1997-02-25 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: Adapt library name to Automake 1.1l.
+
+1996-11-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.14.
+
+ * basename.c: New file.
+
+1996-11-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.13.
+
+ * Makefile.am: Use tar_DEPENDENCIES. Avoid BUILT_SOURCES,
+ put getdate.c instead of getdate.y in tar_SOURCES and keep
+ getdate.c in EXTRA_DIST.
+
+1996-11-06 François Pinard <pinard@iro.umontreal.ca>
+
+ * argmatch.c, argmatch.h, backupfile.c, backupfile.h, dirname.c,
+ getversion.c: New files.
+ * Makefile.am: Adjusted.
+ Reported by Marty Leisner.
+
+1996-10-31 François Pinard <pinard@iro.umontreal.ca>
+
+ * safe-stat.h: Deleted.
+ * Makefile.am (noinst_HEADERS): Adjusted.
+ Reported by Jim Meyering.
+
+1996-09-20 François Pinard <pinard@iro.umontreal.ca>
+
+ * regex.c, regex.h, rx.c, rx.h: Deleted.
+ * Makefile.am: Adjusted.
+
+1996-09-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.12.
+
+ * execlp.c: Include stdio.h, not only stdio!
+
+1996-09-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * open3.h: File deleted after being merged into system.h.
+ * open3.c: File deleted, moved back into src/.
+ * Makefile.am: Adjusted.
+ Reported by Jim Meyering.
+
+1996-08-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (EXTRA_DIST): $(BUILT_SOURCES) is no longer
+ necessary, as Automake now handles it automatically.
+
+1996-07-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.11.
+
+ * Makefile.am (EXTRA_DIST): Move stpcpy.c there, from tar_SOURCES.
+ Reported by Ulrich Drepper.
+
+1996-04-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.10.
+
+ * Makefile.am (EXTRA_DIST): New name for DIST_OTHER.
+
+1996-02-28 François Pinard <pinard@iro.umontreal.ca>
+
+ * msleep.c: New file, from elsewhere.
+ * Makefile.am: Adjusted.
+
+1996-02-12 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: Remove CONFIG_HEADER, not required by Automake 0.29.
+
+1996-01-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (AUTOMAKE_OPTIONS): Select gnits.
+
+1996-01-07 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: Add parts of previous Makefile.in as FIXME comments.
+
+1996-01-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * error.h: New file, from elsewhere.
+ * Makefile.am: Add error.h to HEADERS.
+ Reported by Jim Meyering.
+
+1995-12-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (INCLUDES): Add -I../intl to get libintl.h.
+ Reported by Daniel S. Barclay, Göran Uddeborg, Jonathan Thornburg
+ and Minh Tran-Le.
+
+1995-12-29 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.9.
+
+ * Makefile.am: New file.
+
+1995-11-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (DISTFILES): Distribute ChangeLog.
+ * ChangeLog: New, extracted from the top-level ChangeLog.
+
+1995-06-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * execlp.c (execlp): New, extracted from src/port.c.
+ * Makefile.in: Adjusted.
+
+ * open3.h: New, moved from src/.
+ * open3.c: New, extracted from src/port.c.
+ * Makefile.in: Adjusted.
+ Clean out old NO_OPEN3 code.
+
+ * insremque.h, insremque.c: Deleted.
+ * Makefile.in: Adjusted.
+
+1995-06-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (DISTFILES): Remove COPYING.LIB.
+ * COPYING.LIB: Deleted.
+
+1995-06-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (dist): Do not hide copying rule.
+
+1995-06-07 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Use subdir and distdir.
+
+ * stpcpy.c, xgetcwd.c: New functions needed by gettext.
+ * Makefile.in: Adjusted to always compile these.
+
+1995-05-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * insremque.h, insremque.c: New files, from GNU gettext.
+ * Makefile.in: Take care of insremque.[hc].
+
+1995-03-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Remove GLOCALE, add LINGUAS, use fp_WITH_CATALOGS.
+
+1995-02-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Support ID files. Do not distribute TAGS.
+
+1995-02-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (maintainer-clean): New name for realclean.
+
+1994-12-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * safe-stat.h: New, from elsewhere. This solves the fact that
+ mkdir.c, rmdir.c and rename.c were needing it.
+ * Makefile.in (Makefile): Distribute it.
+ Reported by Bruno Haible and Sherwood Botsford.
+
+1994-12-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * rx.c, rx.h: New, from elsewhere.
+ * Makefile.in: Adjust accordingly.
+
+1994-12-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Localize, adapting from how it is done in sharutils.
+
+1994-09-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Cleanup...
+ (DISTFILES): Distribute TAGS.
+ (check): Deleted.
+ (TAGS): Make TAGS in $(srcdir) only.
+ (distclean): Do not remove TAGS.
+ (realclean): Remove TAGS.
+ (Makefile): Have ./config.status create this Makefile only.
+
+1994-08-22 François Pinard <pinard@iro.umontreal.ca>
+
+ Little cleanup in installation:
+ * Makefile.in (install, check): Depend on all.
+
+1994-08-21 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Correct for when a different build directory.
+
+ * rmdir.c: New, split out of mkdir.c.
+ * Makefile.in: Distribute it.
+ Reported by Greg Black.
+
+1994-08-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * ftruncate.c: Revised, because there is no ftruncate
+ capability whatsoever in Interactive Unix.
+ Reported by Peder Chr. Norgaard.
+
+1994-08-08 François Pinard <pinard@iro.umontreal.ca>
+ * memset.c, mkdir.c, rename.c, strstr.c and
+ ftruncate.c: New, from elsewhere.
+ * Makefile.in: Distribute them.
+
+1994-08-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (getdate.c): Tell the installer to expect 10
+ shift/reduce conflicts instead of 9.
+ Reported by Andreas Schwab.
+
+ * fileblocks.c: New, from elsewhere.
+ * Makefile.in: Distribute it.
+
+1994-08-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * xstrdup.c: New, from elsewhere.
+ * Makefile.in: Adjusted.
+
+1994-07-29 François Pinard <pinard@iro.umontreal.ca>
+
+ * error.c: Add error_print_progname virtual routine.
+
+1994-07-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * gmalloc.c: New, from elsewhere. This renames and updates
+ what was previously malloc.c. This also solves __const vs const.
+ * Makefile.in: Distribute gmalloc.c.
+ Reported by Cliff Krumvieda, Francois Pinard, Henrik Bakman,
+ J.T. Conklin, Nelson H.F. Beebe and Tilman Schmidt.
+
+1994-07-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (LIBOBJS): Get configured list of replacements.
+ * fnmatch.h: Undefine FNM_PATHNAME and FNM_PERIOD, for HP-UX
+ defines them in <unistd.h>.
+
+ * getdate.y: Acknowledging here a few reports which are
+ likely solved by going to an updated version of getdate.y.
+ Reported by Andrey A. Chernov, Bruce Evans, Dean Gaudet, Ian
+ T. Zimmerman, Jeff Prothero, Mike Nolan, Milan Hodoscek, Peder
+ Chr. Norgaard, Sarah Quady, Tarang Kumar Patel and Thomas
+ Koenig.
+
+1994-07-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * xmalloc.c: New file, from elsewhere.
+ * error.c: New, from elsewhere.
+ * Makefile.in: Adjusted.
+
+1994-06-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: New file.
+
+
+----- po/ChangeLog -----
+
+1997-04-25 François Pinard <pinard@iro.umontreal.ca>
+
+ * Release 1.12.
+
+1997-04-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11p.
+
+ * fr.po: Updated file.
+
+1997-04-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11o.
+
+1997-03-26 François Pinard <pinard@iro.umontreal.ca>
+
+ * it.po: New file.
+
+1997-02-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * pl.po: Updated file.
+
+1996-11-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * POTFILES.in: Add src/common.h.
+ Reported by Christian Kirsch.
+
+1996-11-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.14.
+
+ * POTFILES.in: Adjust for changes in src/.
+
+1996-09-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.12.
+
+ * pl.po: New file.
+
+1995-06-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Release 1.11.8.
+
+ * Makefile.in (.po.gmo): Force moving the created .gmo file to
+ $(srcdir), in case it was not already found and replaced there.
+ (install-data): Find files in $(srcdir) if not in current dir,
+ because .gmo files are taken there, right out the distribution.
+ * intl/Makefile.in (DISTFILES): Ensure an all ready stamp-cat-id
+ and cat-id-tbl.c into the distribution.
+ (stamp-cat-id): Rewrite rule so it replaces files in $(srcdir),
+ remove a useless rm and cat.
+
+ * intl/cat-compat.c, int/gettext.h, intl/po-to-tbl.sed,
+ Makefile.in: Last minutes additions, and glimpses to the future
+ gettext 0.6.1.
+ Reported by Ulrich Drepper.
+
+ * Makefile.in (install-data, uninstall): Avoid using basename.
+
+1995-06-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (dist): Comment out tupdate action for now, it
+ needs more tweeking before being distributed active.
+
+ * intl/Makefile.in (dist), Makefile.in (dist): Correct
+ missing reference to $(srcdir) on cp call, also avoid outputting
+ clutter while doing the work.
+
+ * intl/Makefile.in: Use top_srcdir for referring to $(PACKAGE).pot.
+
+ * Makefile.in (.po.gmo): Get around what seems to be an msgfmt
+ bug, which adds .mo even to FILE in `-o FILE'.
+
+ * intl/Makefile.in, Makefile.in: Adjustments to NLS, so .sed
+ scripts may now all reside in intl/.
+
+1995-06-07 François Pinard <pinard@iro.umontreal.ca>
+
+ * POTFILES: New file.
+ * Makefile.in: Use POTFILES instead of TRANSCSRCS, also use
+ top_srcdir.
+
+ * intl/linux-msg.sed, intl/po-to-tbl.sed, intl/xopen-msg.sed: New
+ files, all taken from gettext 0.6.
+
+1995-06-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * intl/*: New from GNU gettext 0.6, replacing the previous
+ version of this directory. This change should solve many problems.
+
+ Reported by Bruno Haible, Christopher Vickery, Jan Carlson,
+ Jean-Philippe Martin-Flatin, John David Anglin, Joseph E.
+ Sacco, Kaveh R. Ghazi, Kurt Jaeger, Mark W. Eichin, Marty
+ Leisner, Minh Tran-Le, Stephen Saroff, Thomas Koenig, Thomas
+ Krebs and William Bader.
+
+1995-05-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * intl/Makefile.in, Makefile.in: Many adjustments for GNU gettext.
+
+1995-05-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: New file.
+ * de.po, fr.po, pt.po, sv.po: New files, adapted from
+ the corresponding .tt files in src/.
+
+1995-05-08 François Pinard <pinard@iro.umontreal.ca>
+
+ * intl/*: New, from nlsutils.
+
+1995-01-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * src/de.tt: New file, for Swedish.
+ Reported by Jan Djarv.
+
+1994-12-10 François Pinard <pinard@iro.umontreal.ca>
+
+ * de.tt: New file, for German.
+ Reported by Ulrich Drepper.
+
+
+----- scripts/ChangeLog -----
+
+1997-04-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * Release 1.12.
+
+ * level-1, level-0: Replace --block-size by --blocking.
+
+1996-04-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.10.
+
+ * Makefile.am (EXTRA_DIST): New name for DIST_OTHER.
+
+1996-01-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (AUTOMAKE_OPTIONS): Select gnits.
+
+1996-01-08 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: New file.
+
+1995-12-31 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (check, dvi): New goals, doing nothing.
+ Reported by Cesar Romani and Ulrich Drepper.
+
+1995-06-21 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.9.
+
+ * Makefile.in: Distribute the ChangeLog, now recovered!
+ Reported by Andreas Schwab.
+
+1995-06-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Release 1.11.8.
+
+ * WARNING: New file.
+ * Makefile.in (DISTFILES): Distribute it.
+
+1995-06-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * sripts/Makefile.in (dist): Do not hide copying rule.
+
+1995-06-07 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Use subdir and distdir.
+
+1995-02-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.7.
+
+ * Makefile.in (maintainer-clean): New name for realclean.
+
+1994-12-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.6.
+
+ * ChangeLog: Replaced by a warning for now. It has
+ seemingly been overwritten by the weekly script :-(.
+
+ * Makefile.in (dist): Correct .../examples to .../scripts.
+
+1994-09-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Cleanup...
+ (check): Deleted.
+ (Makefile): Have ./config.status create this Makefile only.
+
+1994-06-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.5.
+
+ * ChangeLog: Initialized by moving entries related to
+ scripts out of this ChangeLog.
+
+1993-11-24 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * dump-remind: Send mail notification to the original recipients
+ that the dump has been continued when that is the case.
+
+1993-03-31 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * level-0, level-1 (LOGFILE): Put logfile in `log' subdirectory.
+
+1993-03-28 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * dump-remind (volno): Don't increment by one.
+
+1993-03-25 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * level-0, level-1 (TAR_PART1): Use `--block-size', not just
+ `--block', which is now ambiguous.
+
+1993-03-24 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * backup-specs (TAR): New variable.
+
+ * level-0, level-1 (TAR_PART1): Get path of GNU tar from `TAR'
+ variable, don't hardcode it.
+
+1993-03-20 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * backup-specs (SLEEP_MESSAGE): put backslashes in front of nested
+ double quotes.
+
+ * level-0, level-1 (BACKUP_DIRS): Don't put in quotes.
+ (LOGFILE): Use sed to construct name, not awk.
+
+ * dump-remind (recipients): Replaced inefficient pipeline with a
+ single, simple sed script.
+ (volno): Deal with the possibility that VOLNO_FILE may not be
+ created yet.
+
+1993-03-19 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * backup-specs (VOLNO_FILE): Removed abusive comment by Noah.
+
+1993-03-18 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * Makefile.in (AUX): Include `dump-remind' in distribution.
+
+ * backup-specs (SLEEP_MESSAGE): New variable.
+ level-0, level-1: Use it instead of external `dont_touch' file.
+
+ * level-0, level-1: Put most of the script in () and pipe
+ everything from the subshell through tee -a $LOGFILE. Since you
+ really want most of the output to go to the logfile anyway, and
+ since all those pipelines were preventing one from getting the
+ exit status of most commands, this seems like the right idea.
+
+ * level-0, level-1 (LOGFILE): Use YYYY-MM-DD (all numeric) format
+ for log file name, since that makes the file names sortable in a
+ coherent way. Suffix should always be `level-n' where n is the
+ dump level. level-0 script was just using `-full' instead.
+
+ * level-0, level-1 (DUMP_LEVEL): New variable. Set to `0' or `1'
+ in each script as appropriate.
+
+ * level-0, level-1 (HOST): Renamed to `localhost' for clarity.
+ (host): renamed to `remotehost' for clarity.
+
+ * level-0, level-1 (startdate): New variable. Use it in Subject
+ line of mailed report.
+
+ * level-0, level-1: Fixed all instances where sed is called with a
+ script on the command line to use `-e' option.
+
+ * level-0, level-1: Don't try to call logfile.sed to filter
+ LOGFILE. It's not distributed with tar and was never really used
+ anyway.
+
+ * level-0, level-1: Put quotes around most variable names (barring
+ those that are known to intentionally contain text that should be
+ expanded into multiple words, like `TAR_PART1').
+
+ * level-0, level-1: Got rid of annoying trailing backslashes in awk
+ scripts. They were gratuitous. Made them a little more readable
+ by adding some whitespace.
+
+1992-10-21 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * level-0, level-1: put curly braces around variables for clarity.
+
+ * backup-specs (DUMP_REMIND_SCRIPT): define it (but commented out
+ so that distributed dump scripts won't use it by default).
+ level-0, level-1 (TAR_PART1): use --info-script if
+ DUMP_REMIND_SCRIPT is defined.
+ dump-remind: new file (intended as an example).
+
+1992-10-15 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * level-0, level-1: remove $LOGFILE.tmp files before exiting.
+
+1992-09-24 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
+
+ * level-0, level-1 (TAR_PART1): remove --atime-preserve
+ because of a total screw.
+
+1992-09-10 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * level-0, level-1 (TAR_PART1): put --atime-preserve inside quotes.
+
+1992-09-09 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * level-0, level-1 (TAR_PART1): Use --atime-preserve.
+
+1992-07-10 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * level-0, level-1: Avoid silly Sun awk lossage.
+
+1992-04-30 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * level-1: Added `$' before VOLNO_FILE in definition of TAR_PART1.
+ Added line to remove $VOLNO_FILE from any previous dump before
+ starting.
+
+ * level-0, level-1: Change long options to use `--' instead of `+'
+ (support for `+' will go away soon)
+
+1991-10-17 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
+
+ * level-0: Repair damage from previous mod: stdin to rsh must
+ be the terminal or tar's questions lose.
+
+1991-08-31 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * level-0: Fixed several syntax errors associated with
+ stdout/stderr redirection.
+ Made sure remote host executes commands from sh where redirection
+ is necessary, since root's shell might be csh in some places and
+ the redirect syntax differs.
+
+1991-07-01 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * Fix a misplaced quote in level-0 and change some >& into
+ 2>&1.
+
+
+----- src/ChangeLog -----
+
+1997-04-25 François Pinard <pinard@iro.umontreal.ca>
+
+ * Release 1.12.
+
+ * tar.c (main): Attempt to clarify the delayed error exit message.
+ Reported by Richard Stallman.
+
+ * list.c (decode_mode): New name for demode.
+
+ * list.c (read_and): Set current_stat.st_mtime before testing it.
+ Reported by Sven Verdoolaege.
+
+1997-04-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * create.c (dump_file): Before asserting that we cannot access
+ a directory, make sure tar is not installed suid root.
+ Reported by Dietmar Braun.
+
+ * misc.c (quote_copy_string): Undo 1996-05-02 change, meant for
+ the file mangler, now obsolete. This will do neater listings.
+ Reported by Max Hailperin and Noah Friedman.
+
+ * buffer.c, incremen.c, misc.c, tar.c: Replace dangling semicolons
+ by continue; or break; depending on context.
+ Reported by Robert E. Brown.
+
+1997-04-23 François Pinard <pinard@iro.umontreal.ca>
+
+ * arith.c (add_to_tarlong_helper): Compare a superdigit against a
+ value, rather than an unsigned sum against zero.
+ Reported by Bruno Haible.
+
+ * misc.c (quote_copy_string): Replace many if's by a switch.
+
+1997-04-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11q.
+
+ * extract.c (extract_archive): Check if directory extraction was
+ attempted over an existing directory before attempting recovery,
+ so avoiding extraction loops in cases like DIR/../DIR.
+ Reported by Marc Boucher.
+
+ * delete.c (delete_archive_members): New name for junk_archive.
+ * common.h, tar.c (main): Adjusted.
+
+1997-04-20 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (usage): Update comment about --mode.
+
+1997-04-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c: Include <fnmatch.h> if necessary.
+ Reported by Bruno Haible.
+
+ * common.h: Declare write_dir_file for incremen.c.
+ Reported by Bruno Haible.
+
+ * incremen.c (get_directory_contents): Nest an assignment and test
+ within another set of aesthetical parentheses.
+ Reported by Bruno Haible.
+
+ * tar.c (check_octal): Deleted.
+ Reported by Bruno Haible.
+
+ * buffer.c (flush_archive): Add one impossible switch case.
+ * delete.c (junk_archive): Add two impossible switch cases.
+ * list.c (read_and): Add one impossible switch case.
+ * update.c (update_archive): Add two impossible switch cases.
+ Reported by Bruno Haible.
+
+ * names.c (name_gather): Explicitly declare allocated_length as
+ an int, do not imply it.
+ Reported by Bruno Haible.
+
+1997-04-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11p.
+
+ * Makefile.am (tar._o, rmt._o): Revise rules further.
+ Reported by Bruno Haible and Ken Steube.
+
+1997-04-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * arith.h: Prefer a single long over a long long, if possible.
+ Also reject long long if it is not long enough :-).
+ Reported by Bruno Haible.
+
+1997-04-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c, tar.c, update.c, common.h: Replace _COMMAND suffixed
+ constants by _SUBCOMMAND suffixed. Rename enum command by
+ enum subcommand, main_command_option by subcommand_option and
+ set_main_command_option by set_subcommand_option.
+
+ * create.c (dump_file): Remove badperror label, call WARN
+ explicitly at the two other needed places instead. Remove
+ badfile label, expand the proper code at the three other
+ needed places instead. Delete the critical_error flag, just
+ set exit_status to TAREXIT_FAILURE rather than setting this flag.
+
+1997-04-12 François Pinard <pinard@iro.umontreal.ca>
+
+ * delete.c (move_archive): Declare it void.
+ Reported by Bruno Haible and Kaveh R. Ghazi.
+
+1997-04-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11o.
+
+ * Makefile.am: Duplicate rules for the ansi2knr case.
+ Reported by Kaveh R. Ghazi and Marcus Daniels.
+
+1997-04-10 François Pinard <pinard@iro.umontreal.ca>
+
+ * common.h: Change mode_option from int to struct mode_change *.
+ * tar.c (decode_option): Use mode_compile.
+ * create.c (start_header): Use mode_adjust.
+
+1997-04-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * All: Replace all flag_ prefixed variables by _option suffixed.
+ * tar.c: Replace OPTION_ prefixed macros by _OPTION suffixed.
+
+ * buffer.c, tar.c, update.c, common.h: Replace COMMAND_ prefixed
+ macros by _COMMAND suffixed, COMMAND_NONE by UNKNOWN_COMMAND,
+ and delete TOO_MANY_COMMAND. Turn these into an enum and declare
+ main_command_option of this enum type, to replace command_mode,
+ which was an int, everywhere.
+ * tar.c (decode_options): Initialise main_command_option.
+ (set_main_command_option): New function to replace
+ SET_COMMAND_MODE. Diagnostic ambiguous command as soon as seen.
+ However, be forgiving if command has merely been repeated.
+
+ * buffer.c, tar.c, common.h: Have info_script_option be at the
+ same time a flag and the option value, no need for a separate
+ info_script variable. Rename rsh_command to rsh_command_option,
+ tape_length to tape_length_option, compress_program to
+ use_compress_program_option, volno_file to volno_file_option.
+ * tar.c (set_use_compress_program_option): New function.
+
+ * buffer.c, names.c, tar.c, common.h: Have files_from_option
+ be at the same time a flag and the option value, no need for
+ a separate namefile_name variable.
+
+ * buffer.c, create.c, tar.c, commun.h: Rename volume_label to
+ volume_label_option.
+
+ * incremen.c, tar.c, common.h: Rename gnu_dumpfile to
+ listed_incremental_option. Let it unitialised for just incremental.
+ * create.c (create_archive): No need to check both
+ incremental_option and listed_incremental_option, as the later
+ implies the former already.
+
+ * create.c, tar.c, common.h: Rename preset_owner to owner_option,
+ preset_group to group_option and preset_mode to mode_option.
+
+ * create.c, incremen.c, list.c, tar.c, commun.h: Have
+ after_date_option be a Boolean instead of a three-valued flag.
+ Rename threshold_time to newer_mdate_option, which may be looked
+ at without checking after_date_option first, as threshold_time
+ before. Make newer_cdate_option an alias for newer_mdate_option.
+
+1997-04-08 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c: Use int after extern to declare time_to_start_writing.
+ * extract.c: Use int after static to declare we_are_root.
+ Reported by Ariel Faigon.
+
+1997-04-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * list.c (read_and): Use the proper enum constants in switch,
+ instead of oldish and wrong numbers.
+ Reported by Martin Mares.
+
+1997-04-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * arith.c [SUPERDIGIT] (zerop_tarlong, lessp_tarlong,
+ clear_tarlong, add_to_tarlong, add_to_tarlong, mult_tarlong,
+ print_tarlong): Rename all functions by adding a _helper suffix.
+ * arith.h [SUPERDIGIT]: Replace function prototypes by macros,
+ each calling the function with _helper appended, and extracting
+ pointers out of the tarlong structures.
+ Reported by Andrew A. Ivanov and Kaveh R. Ghazi.
+
+ * buffer.c (child_open_for_compress): Copy all records coming out
+ of the compressor, not only the last one.
+ Reported by Alois Steindl, Mark Bynum, Martin Mares, Nelson
+ H. F. Beebe, Scott J. Kramer and Torkel Hasle.
+
+1997-03-29 François Pinard <pinard@iro.umontreal.ca>
+
+ * create.c (dump_file): Ignore unreadable directories when
+ --ignore-failed-read.
+ Reported by Ralph Schleicher.
+
+ * create.c (deal_with_sparse): Chain the last partial zero block
+ with the preceding data, do not try sparing it. This correction
+ is approximative, as the whole thing should be rethought.
+ Reported by Andreas Degert.
+
+1997-03-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * All: Rename head to current_header, hstat to current_stat, and
+ header_format to current_format.
+ * update.c (update_archive): Rename nstat to stat_data.
+ * create.c: Do not extern hstat, as common.h does it.
+ (deal_with_sparse): Get rid of amidst_data, since numbytes is
+ already usable as a flag for the same thing.
+
+1997-03-21 François Pinard <pinard@iro.umontreal.ca>
+
+ * names.c (name_gather): Do not declare static variables which
+ do not need to be. Have allocated_length represent the full
+ allocated length, instead of only the name part. It's clearer.
+ (addname): Similar cleanups.
+
+1997-03-20 François Pinard <pinard@iro.umontreal.ca>
+
+ * compare.c: Always call report_difference when there is a
+ problem, so the exit status will be set in all cases. Build the
+ message string if necessary, so avoiding stdargs/varargs.
+ (report_difference): If NULL argument, just set the exit status
+ without reporting a message. Move out the word `differs'
+ in all callers, do not insert into an English message.
+ (read_and_process): Return void, as the int result is never used.
+ Assume processors returns nonzero for success and zero for
+ failure, instead of 0 for success and -1 for error.
+ (process_rawdata, process_dumpdir): Adjusted.
+
+ * compare.c: Remove different as a global variable, it is useless.
+ (diff_sparse_files): Make different a local variable, reinitialise
+ it on each call. Otherwise, after any error elsewhere, all sparse
+ files were always and falsely reported as erroneous.
+ Reported by James E. Carpenter and Tim Towers.
+
+1997-02-25 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c: Adjust copyright years in --version output.
+
+ * create.c (dump_file): Allow saving directories even with -o.
+ Reported by Daniel Trinkle.
+
+1996-11-26 François Pinard <pinard@iro.umontreal.ca>
+
+ * compare.c (verify_volume) [FDFLUSH]: Use fsync even in that case.
+ Reported by Marty Leisner.
+
+1996-11-25 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c (new_volume): Write file name in two words.
+ * names.c (name_next): Idem.
+ * buffer.c (flush_read): Speak of record size instead of blocksize.
+ Reported by Christian Kirsch.
+
+1996-11-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * list.c (read_header): Return failure, instead of success,
+ whenever checksums do not match.
+ Reported by Marc Boucher and Marty Leisner.
+
+ * incremen.c (get_directory_contents): Use stat_data instead of
+ current_header for checking normal files. Otherwise, new or
+ modified files in old directories were not dumped, that is, if a
+ directory was older than the listed entry, it was skipped
+ completely without checking the contained files.
+ Reported by David Johnson, John David Anglin and Wolfram Wagner.
+
+ * buffer.c (open_archive): When updating the archive, initialize
+ the access variable with reading mode, not update mode.
+ Reported by Andreas Schwab.
+
+ * delete.c (junk_archive): Initially jump directly into the loop,
+ so deleting a file after a big one will not destroying the archive.
+ Reported by Akiko Matsushita, Andreas Schwab, Eric Backus, Jeff
+ Siegel, Saul Lubkin, Stuart Kemp and Yasushi Suzudo.
+
+1996-11-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * incremen.c (get_directory_contents): Compute distance using the
+ start of the proper buffer.
+ Reported by David Johnson, Donald H. Locker, John David Anglin,
+ Marc Boucher and Noah Friedman.
+
+ * tar.c (usage): Revise the mandatory/optional sentence again.
+ Reported by Karl Berry.
+
+1996-11-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.14.
+
+ * tar.c (usage): Explain the purpose of the program.
+
+ * tar.c (usage): Clarify the mandatory/optional sentence.
+ Reported by Alex Schmidt.
+
+ * system.h [HAVE_SYS_TAPE_H]: Include sys/buf.h if it exists, to
+ avoid many warnings on BSD/OS.
+ Reported by Dan Reish.
+
+1996-11-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * incremen.c (write_directory_file): Renamed from write_dir_file.
+ (get_directory_contents): Renamed from get_dir_contents.
+ * common.h: Adjusted.
+
+ * all: Cleanup around local variables, renaming them more
+ appropriately, using initializers when natural, and moving them
+ closer to the blocks where they are used.
+
+ A bit of reorganisation in the sources:
+ * common.h: New file, for holding all GNU tar specific definitions,
+ which were previously held in tar.h.
+ * tar.h: Now limited to the archive format description only.
+ * all: Include common.h instead of tar.h.
+ * delete.c: New file, holding delete code out of update.c.
+ * update.c: Now limited to appending type of commands.
+ * compare.c: New name for diffarch.c.
+ * incremen.c: New name for increm.c.
+ * names.c: Moved over all name processing from tar.c.
+ * tar.c, common.h: Adjusted.
+ * Makefile.am: Adjusted.
+
+ * system.h (lstat) [!S_ISLNK]: Define as stat.
+ * create.c, diffarch.c, increm.c: Remove similar definitions.
+
+ * tar.c: Merge --version-control into --backup, make it obsolete.
+
+1996-11-10 François Pinard <pinard@iro.umontreal.ca>
+
+ * all: Add a FIXME comment everywhere errno is modified by tar.
+
+ * buffer.c (new_volume): Return nonzero/zero for success/failure,
+ instead of zero/negative. Callers adjusted. Use xstrdup on
+ file name given by user with the answer "n", so avoiding the
+ apparently useless allocation of one extra byte. Avoid using p.
+
+ * buffer.c: Add DEBUG_FORK conditional code.
+ Reported by Thomas König and Ulrich Drepper.
+
+ * misc.c (maybe_backup_file): In the renaming message, say that
+ the previous file is being renamed, not the newly extracted one.
+
+ * buffer.c (backspace_output): Change return type to void, since
+ returned values were never used.
+ * update.c (move_arch): Idem.
+ (xdup2): New name for redirect, order of arguments was not natural.
+
+1996-11-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * all: Remove all white lines between open braces and comments.
+
+ * tar.h: Declare access_mode as an enum and as a variable.
+ Adjust declaration of open_archive.
+ * buffer.c: (open_archive, new_volume): Use access instead of
+ reading. Callers adjusted for using enum access_mode arguments.
+ (flush_archive, close_archive): Use access_mode, and cleanup.
+ * diffarch.c (verify_volume): Use access_mode.
+
+ * buffer.c (child_open_for_compress, child_open_for_uncompress):
+ Split of previous child_open_for_compress. Clean up.
+ (open_archive): Adjusted for calling the proper function above.
+
+1996-11-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.13.
+
+ * tar.c (usage): Do not tie --posix anymore to 1.12.
+
+ * extract.c (set_stat): Until we know better, for the time being,
+ limit restoring symbolic link attributes to lchown only.
+
+ * all: Mini clean up. Systematically set logical variables to
+ one instead of auto-incrementing them (PDP-11 time is over by
+ now! :-). Replace some single letter counters or cursors by
+ variables named counter or cursor. Simplify a few C constructs.
+
+ * buffer.c, tar.h: Delete read_error_flag, set but never used.
+ Rename r_error_count to read_error_count.
+
+ * create.c (clear_buffer): Use memset instead of explicit loop.
+ (zero_block_p): Renamed from zero_block, callers adjusted.
+
+1996-11-07 François Pinard <pinard@iro.umontreal.ca>
+
+ * rmt.c (private_strerror): Add const's to sys_errlist declaration.
+ Reported by Fabio d'Alessi.
+
+1996-11-06 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Add OPTION_BACKUP, OPTION_SUFFIX, OPTION_VERSION_CONTROL.
+ Renumber options from 3 instead of from 10. Declare flag_backup.
+ * tar.c: Include backupfile.h. Implement --backup, --suffix and
+ --version-control decoding. Adjust usage documentation.
+
+ * misc.c (maybe_backup_file, un_backup_file): New functions.
+ * tar.h: Adjusted.
+ * buffer.c (child_open_for_compress, open_archive, new_volume):
+ Use the new functions.
+ * extract.c (extract_archive): Idem.
+ Reported by Jeffrey Mark Siskind, Karl Berry, Karl Heuer, Marty
+ Leisner, Melissa Weisshaus and William Bader.
+
+ * misc.c (assign_string): Moved over from tar.c.
+ * tar.h: Adjusted.
+
+1996-10-28 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Declare enum read_header, for return values of read_header.
+ * diffarch.c (verify_volume): Adjusted.
+ * list.c (read_and, read_header): Adjusted.
+ * update.c (junk_archive, update_archive): Adjusted.
+ * update.c: Rename prev_status to previous_status.
+ * update.c (junk_archive): Delete found_stuff, use logical_status.
+
+1996-10-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c (new_volume, open_archive): Soften messages.
+ * create.c, extract.c: Add quotes around slashes in some messages.
+ * tar.c (usage): Added a missing equal sign after --directory.
+ Reported by Jan Djarv.
+
+1996-09-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c: Write --no-recursion instead of --no-recurse.
+ Reported by Noah Friedman.
+
+1996-09-20 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Delete label_pattern.
+ * tar.c (main): Do not compile anymore volume_label as a regexp.
+ (usage): Document --label as accepting a globbing pattern.
+ * buffer.c, tar.c: Do not include regex.h neither rx.h.
+ * buffer.c (check_label_pattern): New function.
+ (open_archive, flush_read): Use it, instead of re_match.
+
+ * tar.c (decode_options): Better space --version output.
+
+1996-09-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.12
+
+ * Makefile.am (EXTRA_PROGRAMS): Compile rmt properly, instead of
+ letting make use default .c to executable rule.
+
+ * tar.c: Include getopt.h.
+ * system.h: Don't.
+
+ * increm.c (get_dir_contents): Consider all NFS devices as equal
+ before deciding that a directory was renamed, so automount will
+ not fool GNU tar into spurious incremental redumping.
+ Reported by Frank Koenen, Giorgio Signorini, Joachim Holzfuss,
+ Konno Hiroharu, R. Kent Dybvig and Wolfram Wagner.
+
+ * tar.c (usage): Add bug report address in --help output.
+ (decode_options): Add copyright and authors in --version output.
+
+ * increm.c: New name for gnu.c.
+ * Makefile.am (tar_SOURCES): Adjusted.
+
+ * gnu.c (init_buffer, add_buffer, get_buffer, flush_buffer): Moved
+ over from misc.c. Deleted is_dot_or_dot_dot and remove_any_file.
+ * misc.c (is_dot_or_dotdot, remove_any_file): Moved over from gnu.c.
+ Deleted init_buffer, add_buffer, get_buffer and flush_buffer.
+ * tar.h: Adjusted.
+
+1996-09-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c (write_error): Obey --totals before aborting.
+ Reported by Greg Chung.
+
+ * buffer.c (read_error, write_error): Renamed from readerror and
+ writeerror.
+ * tar.c (read_name_from_file): Rename c to character.
+
+1996-09-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * arith.h (tarlong): The typedef tarlong, when an array, is now
+ wrapped inside a struct to avoid bugs in EWS 4.2 C compiler.
+ * arith.c: Adjusted.
+ Reported by Paul Eggert.
+
+ * buffer.c: Declare archive_stat statically.
+ (open_archive): Do not declare archive_stat locally.
+ (close_archive): Limit archive draining to while reading a pipe.
+ Reported by Andreas Schwab.
+
+1996-09-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * system.h: Define protected defaults for open parameter symbols.
+ [EMUL_OPEN3]: Intercept open calls and redirect them to open3.
+ * open3.c: New file, moved over from lib/. Merely include
+ system.h rather than config.h, errno.h and open3.h.
+ [EMUL_OPEN3]: The compilation of the file depends on this symbol.
+ When it was in lib/, we were using LIBOBJS to control this.
+ * Makefile.am: Adjusted.
+ * extract.c: Don't call open3.h.
+ Reported by Jim Meyering.
+
+1996-09-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (libexec_PROGRAMS): Rely on @RMT@, not rmt.
+ (bin_PROGRAMS): Do not include @RMT@.
+
+ * gnu.c (remove_any_file): Protect value of errno in case
+ of failure to remove a directory, in non-recursive mode.
+ This should correct spurious diagnostics while extracting
+ directories over already existing hierarchies.
+ Reported by Martin Mares and Marty Leisner.
+
+1996-09-04 François Pinard <pinard@iro.umontreal.ca>
+
+ * gnu.c (read_dir_file): Diagnose file names over PATH_MAX.
+ (get_dir_contents, add_dir_name): Increase namebuf many times if
+ this is needed to receive a loong file name.
+ Reported by Carsten Heyl.
+
+ * Makefile.am (tar.o, rmt.o): Special rules for defining
+ LOCALEDIR, instead of having it defined on all compiles.
+
+ * Makefile.am: Remove check related lines, moved over to tests/.
+
+1996-09-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: Use genfile in check_PROGRAMS, not noinst_PROGRAMS.
+ (check-local): Do not depend on genfile.
+
+1996-08-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (EXTRA_DIST): Do not mention ansi2knr.1 nor
+ ansi2knr.c, as Automake now handle them automatically.
+
+1996-07-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * arith.h: Include tar.h, not arith.h, so FATAL_ERROR is defined.
+ [!SUPER_DIGIT]: Declare arguments to ..._tarlong routines as
+ pointers to unsigned long and not arrays, for avoiding pointers
+ to arrays, and nevertheless have arrays passed by reference
+ rather than by value.
+ * arith.c: Adjusted function headers accordingly.
+ * buffer.c, tar.c: Removed address-of operators, using tarlongs.
+ Reported by Christian T. Dum, Jim Meyering and Kaveh R. Ghazi.
+
+ * arith.h [SUPER_DIGIT]: Avoid indirection in all macros for
+ Accumulators. This, in particular, solves a bug where the pointer
+ value itself was printed, rather than the pointed to value.
+ Reported by Drew Sullivan and Wolfram Wagner.
+
+ * Makefile.am (EXTRA_DIST): Include ansi2knr.[1c] for now.
+ Reported by Christian T. Dum, Jim Meyering and Kaveh R. Ghazi.
+
+1996-07-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.11.
+
+ * Makefile.am (check-local): Ensure relinking if the service
+ libraries where modified (waiting for Automake to do it!).
+
+1996-07-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * rmt.c (strerror): It is a macro on some systems.
+ Reported by Santiago Vila Doncel.
+
+1996-07-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.10.
+
+ * checktar.sh: Use a more regular WARNING in message.
+
+1996-07-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Declare that unquote_string as returning int, not char *.
+ * misc.c (unquote_string): New name for un_quote_string. Clean
+ up a bit, return a boolean indicator for success, not a string.
+ * gnu.c (read_dir_file), mangle.c (extract_mangle), tar.c
+ (add_exclude): Callers adjusted, so they never use a NULL return
+ as an actual string. In fact, the result of unquote_string is
+ always used, even if the quoting was improper.
+ Reported by Johan Vromans.
+
+1996-05-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Define TTY_NAME as a macro, instead of an external array.
+ * tar.c: Remove declaration of TTY_NAME.
+
+ * tar.h: Rename new_time to threshold time. Make it GLOBAL.
+ * tar.c, create.c, gnu.c, list.c: Adjusted.
+ (decode_options): Clarify -N and --newer-mtime decoding, ensure
+ one of them is called at most, otherwise it would misbehave.
+
+1996-05-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * misc.c (quote_copy_string): Ensure spaces are backslash-quoted.
+ Reported by Max Hailperin.
+
+ * list.c (decode_header): Some clean up. Recognize POSIX archive
+ headers, avoid fetching atime or ctime in this case.
+ [!S_IFBLK || !S_IFCHR]: Ensure st_rdev is cleared appropriately.
+ * tar.h: Rename head_standard to header_format, so turning an
+ int to an enum archive_format. Adjust decode_header prototype.
+ * diffarch.c, extract.c, list.c, update.c: Usages changed.
+ * create.c: Ensure oldgnu_header is only used when OLDGNU_FORMAT.
+ (Correction just starting to be made--will be comprehensive...)
+ Reported by Anders Andersson, Bdale Garbee, Chris G Demetriou and
+ David J. MacKenzie.
+
+ * buffer.c, gnu.c, rtapelib.c, tar.c: Diagnose errors on fclose.
+ Reported by Jim Meyering.
+
+1996-05-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c (close_archive): If reading and the archive is
+ finished, read until end of archive, for avoiding an error
+ message from the upstream process if we are reading from a pipe.
+ Reported by Bennett Todd, Dick Streefland, Don Bennett, Ian Lance
+ Taylor, Jean-loup Gailly and Piercarlo Grandi.
+
+ * create.c (dump_file): Add note about accuracy of st_blocks.
+ Reported by Dick Streefland.
+
+ * diffarch.c: Include <linux/fd.h> if it exists.
+ (verify_volume): fsync, than ioctl(, FDFLUSH) first.
+ Reported by Marty Leisner.
+
+1996-04-29 François Pinard <pinard@iro.umontreal.ca>
+
+ * list.c (isotime): New function.
+ (print_header) [!USE_OLD_CTIME]: Use it instead of ctime.
+ Reported by Karl Berry and Markus Kuhn.
+
+1996-04-23 François Pinard <pinard@iro.umontreal.ca>
+
+ * extract.c (set_stat): Accept a new parameter telling if this is
+ a symbolic link. In this case, and if lchown exists, use it
+ instead of chown. Callers adjusted.
+ (extract_archive): Do call set_stat over restored symbolic links.
+ Reported by Andreas Koppenhoefer, Bernard Derval, Ian Jackson,
+ Matt Power, Warren Dodge and Wolfram Gloger.
+
+ * extract.c (extr_init): If the umask was very restrictive at
+ start of tar, nevertheless ensure we create intermediate
+ directories with such permissions that we can at least add files
+ into them.
+ (extract_archive): Same, but for final directory. Ensure
+ directory attributes are restored in all cases.
+ Reported by Piercarlo Grandi.
+
+ * tar.c: Implement --owner, --group and --mode options.
+ * tar.h: Declare preset_owner, preset_group and preset_mode.
+ * create.c: Obey these variables.
+ Reported by Ken Raeburn, Richard Stallman and Stephen Gildea.
+
+ * create.c (dump_file): When wanting the length of the link
+ name, use strlen, rather then doing wrong arithmetic giving
+ the number of removed slashes at the beginning of it.
+ Reported by Brian R. Smith.
+
+ * create.c (start_header): Try removing leading slashes even for
+ long file names.
+ Reported by Art Isbell, Fritz Elfert and Robert E. Brown.
+
+ * buffer.c (new_volume): Avoid calling closeout_volume_number if
+ the --volno-file option was not specified, so avoiding crashes.
+ * tar.c (usage): Document the --volno-file option.
+ Reported by Christoph Litauer, Daniel S. Barclay, David Taylor,
+ Erik D. Frederick, Larry Creech, Loïc Prylli, Loren J. Rittle,
+ Marty Leisner, Neil Faulks, Paul Mitchell, Rocky Giannini, Roy
+ Marantz, Sylvain Rougier, Timothy J. Lee and Werner Almesberger.
+
+1996-04-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * system.h (N_): Define marking macro for delayed translations.
+ * rmt.c: Use N_ instead of _ for returned strings. It does not
+ make sense translating messages in a remote process, not knowing
+ the language in use in the local process.
+
+1996-04-18 François Pinard <pinard@iro.umontreal.ca>
+
+ Instead of -UU for removing directories, request a long option.
+ * tar.c: Implement --recursive-unlink.
+ (usage): Document --recursive-unlink.
+ (decode_options): Have --recursive-unlink imply --unlink-first.
+ * tar.h: Declare --recursive-unlink.
+ * extract.c (extract_archive): Use flag_recursive_unlink instead
+ of flag_unlink_first > 1.
+ Reported by Andreas Schwab.
+
+1996-04-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (EXTRA_DIST): New name for DIST_OTHER.
+
+ * tar.c (addname, name_gather): Zero out freshly allocated struct
+ name, to prevent garbage to get into the structure.
+ Reported by Jonathan Kamens.
+
+1996-03-28 François Pinard <pinard@iro.umontreal.ca>
+
+ * create.c (dump_file): Cast %ld argument to (long).
+ Reported by Constantin Belous and Jörgen Hägg.
+
+1996-03-21 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (main): Return int, not void.
+ Reported by Timothy J. Lee and Peter Seebach.
+
+1996-02-28 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: Use RMT instead of PROGRAMS and noinst_HEADERS
+ instead of HEADERS.
+
+1996-02-12 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: Remove CONFIG_HEADER, not required by Automake 0.29.
+
+1996-02-03 François Pinard <pinard@iro.umontreal.ca>
+
+ Ensure --totals work correctly for huge archives:
+ * arith.h, arith.c: New files.
+ * Makefile.am: Use arith.h and arith.c.
+ * tar.h: Do not declare tot_written anymore, include "arith.h".
+ * tar.c (main): Call init_total_written and print_total_written.
+ * buffer.c: Rename tot_written to total_written, make it tarlong.
+ (init_total_written, print_total_written): New routines.
+ Reported by Albert W. Dorrington, Chris F.M. Verberne, David
+ Martin, Eduardo Villasenor de Rivas, Greg Chung, Jim Meyering,
+ John R. Vanderpool, Jon Lewis, Jörg Weule, Jörgen Hägg, Rod
+ Thompson, Russell Cattelan, Ted Rule and Tor Lillqvist.
+
+ Ensure --tape-length is usable for huge media:
+ * tar.h: Declare tape_length as tarlong instead of int.
+ * tar.c (decode_option): Decode tape_length as tarlong, and use
+ its value pre-multiplied by 1024.
+ * buffer.c (flush_write): Use bytes_written and tape_length as
+ tarlongs. Declare bytes_written outside flush_write.
+ (init_total_written): Zero out bytes_written as well.
+ Reported by Dave Barr.
+
+1996-01-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * rtapelib.c (rmt_open__) [MSDOS]: Do not call setuid/setgid.
+ Reported by Yasushi Suzudo.
+
+1996-01-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (AUTOMAKE_OPTIONS): Select gnits and ansi2knr.
+
+1996-01-08 François Pinard <pinard@iro.umontreal.ca>
+
+ * create.c: Initialize linklist to NULL.
+ Reported by Bradley A. Smith.
+
+1996-01-07 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: Add parts of previous Makefile.in as FIXME comments.
+
+1996-01-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (usage): Avoid an unescaped new line.
+ Reported by Kaveh R. Ghazi and Mark Bynum.
+
+ * system.h: Declare valloc if it exists and is not #defined.
+ * create.c (start_header): Add missing DEFAULT_FORMAT case.
+ * gnu.c (read_dir_file): Use NULL instead of (char *) 0.
+
+ * Makefile.am: Install rmt in $(libexec), not in sbin.
+
+ * tar.c (decode_options): Add a semicolon so default case is
+ not completely empty, for better ANSI C compliance.
+ Reported by John David Anglin, Kaveh R. Ghazi and Mark Bynum.
+
+1996-01-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c (open_archive): Allocate real_s_name at run time
+ instead of statically, because PATH_MAX is not always constant.
+ Reported by Bruno Haible, John David Anglin, Jonathan Thornburg,
+ Kaveh R. Ghazi, Martin Bellenberg, Marty Leisner, Nelson
+ H. F. Beebe, Roland McGrath and Thomas König.
+
+ * Makefile.am (DIST_OTHER): Distribute BACKLOG.
+ Reported by Marty Leisner.
+
+1996-01-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * system.h: Include "error.h" instead of declaring error ().
+ Reported by Jim Meyering.
+
+1995-12-31 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am: New file.
+
+1995-12-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Define LOCALEDIR in DEFS.
+ * system.h [!ENABLE_NLS]: Add replacement for bindtextdomain.
+ * tar.c (main): Add call to bindtextdomain.
+ * rmt.c (main): Add calls to bindtextdomain and textdomain.
+ Reported by Ulrich Drepper.
+
+ * buffer.c, create.c, diffarch.c, gnu.c, list.c, rmt.h, system.h,
+ tar.h, update.c: Replace __P by PARAMS, to respect ANSI C.
+ * rtapelib.c, rmt.h: Replace all __rmt* symbols by rmt*__.
+
+1995-12-28 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.9.
+
+ * extract.c (extr_init): Initialize variables in any case,
+ instead of partly relying on static initializations. Remove
+ static initializations for those variables.
+
+1995-12-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * extract.c (extract_archive): On systems not having symbolic
+ links, attempt extracting symbolic links as hard links instead,
+ as POSIX suggests. Emit a diagnostic on first occurrence.
+
+ * extract.c (extract_archive): On systems not having contiguous
+ files, continue extracting them as regular files as before, but
+ emit a diagnostic on first occurrence.
+
+1995-12-23 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Declare remove_any_file.
+ * gnu.c (remove_any_file): New name for recursively_delete.
+ Add a parameter to control recursion. Inverse return value,
+ so 0 is failure. Ensure errno is always valid in this case.
+ (gnu_restore): Specify recursion when calling remove_any_file.
+ * extract.c (maybe_recoverable): New routine.
+ (extract_archive): Call maybe_recoverable rather than
+ make_directories, so deleting files is also tried. Some cleanup.
+
+ * tar.h: Declare flag_unlink_first.
+ * tar.c (decode_options): Decode --unlink-first (-U).
+ (usage): Document it.
+ * extract.c (extract_archive): With -U, call remove_any_file
+ prior to extraction for everything except directories.
+
+ Reported by Andrew J. Schorr, Andrey A. Chernov, Axel Boldt, Bo
+ Nygaard Bai, Chris F.M. Verberne, Chris G. Demetriou, Christian
+ Callsen, Daniel S. Barclay, Ian Jackson, James Stevens, Seth
+ Robertson, Tito Flagella, Warner Losh and Wolfram Wagner.
+
+1995-12-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (name_close): Specify static.
+ (main): Call name_close after create_archive.
+ * create.c (create_archive): Do not call name_close.
+
+ * tar.c: Clean out names_arg[cv] crumb.
+ (name_next): Simplify routine by merging both loops.
+ (addname): Avoid xstrdup'ing result of new_name, this corrects a
+ memory leak.
+
+ * extract.c: Normalize error message so the file is identified at
+ the beginning of it.
+
+ * tar.h (USAGE_ERROR): New macro.
+ * tar.c: Use USAGE_ERROR as far as possible. Cleanup and
+ normalization in string for usage errors. Better detection of
+ conflicting options about archive format or compression program.
+
+ * tar.c (decode_options): Decouple cases for -C and files. Count
+ number of input files. Cowardly refuse to create an empty archive
+ file, if -c is given without input file or list.
+ Reported by Karl Berry and Robert Bernstein.
+
+1995-12-21 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c: Rename a few err variables to status.
+ * extract.c: Rename a few check variables to status.
+
+ Corrections to speed-up the sizeing pass in Amanda:
+ * tar.h: Declare dev_null_output.
+ * buffer.c (open_archive): Detect when archive is /dev/null.
+ (flush_write): Avoid writing to /dev/null.
+ * create.c (dump_file): Do not open file if archive is being
+ written to /dev/null, nor read file nor restore times.
+ Reported by Greg Maples and Tor Lillqvist.
+
+ * gnu.c: Have dir_list properly initialized to NULL.
+ Reported by Paul Nordstrom and Tim Lashua.
+
+ * extract.c: Rename ourmask to newdir_umask. Rename and
+ complement notumask to current_umask.
+ * list.c (print_for_mkdir): New name for pr_mkdir.
+ * tar.h: Adjust declaration.
+ * extract.c (make_directories): New name for make_dirs. Some
+ cleanup in variable names.
+
+ * extract.c: Let newdir_umask be a global variable.
+ (make_directories): Use newdir_umask while creating intermediate
+ directories. They used to be 0777 unconditionally.
+ Reported by Bruce Evans, Harald König and James Crawford Ralston.
+
+1995-12-20 François Pinard <pinard@iro.umontreal.ca>
+
+ * create.c (finish_header): Avoid printing the header for long
+ names or links, this avoids spurious `Visible longname error's.
+
+ Reported by Arne Wichmann, Chris F.M. Verberne, Frank Koenen,
+ Franz-Werner Gergen, Ian Jackson, Jon Lewis, Mark Kollert, Paul
+ Nordstrom, Ted Rule, Thomas Priesner, Tim Rylance and Tom Tromey.
+
+1995-12-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c: Have real_s_name able to hold PATH_MAX characters,
+ not only NAME_FIELD_SIZE. It was breaking --multi-volume
+ --listed-incremental when backing up long file names.
+ Many symptoms really: a screwed-up date on the incremental data
+ file, dumping incremental which should not have been, etc.
+ * (flush_read): Avoid altering save_name pointer value, use
+ cursor instead. Also avoid the optimization of cleaning each
+ save_name only once per flush_read if it did not change: it
+ was using `save_name = real_s_name;', and since save_name may
+ be freed at any time, this is/was really running after trouble.
+
+ Reported by Alexander V. Lukyanov, Axel Habermann, Chance
+ Reschke, Claus Heine, Christian von Roques, Daniel Hagerty,
+ Daniel S. Barclay, Dirk Herr-Hoyman, Donald H. Locker, Ed Childs,
+ Heiko Schinke, Hunyue Yau, Goeran Uddeborg, Grant McDorman,
+ Joachim Seelig, Joe DeBattista, Jonathan Thornburg, Joutsiniemi
+ Tommi Il, Jürgen Lüters, Keith Young, Kelly Stephens, Kevin
+ Dalley, Konno Hiroharu, Larry Creech, Martin Mares, Michael
+ Dietrich, Michael Giddings, Michael Meissner, Michael P Urban,
+ Paul Siddall, Pierce Cantrell, Peter Fox, Robert Frey, Roderich
+ Schupp, Sam Richards, Stephen J Bevan, Torsten Lull, Wolfram
+ Gloger and Yu-Min Liang.
+
+ * system.h: Include <sys/tprintf.h> and <sys/device.h> for BSDi.
+ Reported by Chris Arthur, Dan Reish, Karl Berry and Skip Montanaro.
+
+ * rmt.c (private_strerror): New, copied from lib/error.c.
+ Remove sys_errlist declaration, and use syserror instead.
+ Reported by Chris Arthur, Coranth Gryphon, Erich Stefan Boleyn,
+ Fabio d'Alessi, Greg Hudson, Jason R. Mastaler, Skip Montanaro,
+ Thomas Krebs and Troy Rudolph.
+
+1995-12-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * extract.c (extract_archive): Unrecognized types were defaulted
+ to sparse files instead of regular files, because of an improper
+ /* Fall through. */.
+
+ * create.c, diffarch.c, extract.c, gnu.c, list.c, rtapelib.c,
+ tar.c: Drop register specifications, useless in GNU's tar, as
+ tar does not use longjmp, and GNU C has -O automagically set.
+
+ * extract.c (extract_archive): Inhibit creation of links, special
+ devices, directories, etc., when --to-stdout option is being used.
+ Reported by Donald B Gordon, Gerben Wierda, Greg Chung, Norbert
+ Kiesel and Roman Czyborra.
+
+1995-12-04 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Implement FATAL_ERROR, telling error is not recoverable.
+ * tar.c (main): Diagnose delayed error, for TAREXIT_FAILURE only.
+ * buffer.c, diffarch.c, gnu.c, list.c, tar.c, update.c: Replace
+ all `ERROR ((TAREXIT_FAILURE,' by `FATAL_ERROR ((0,'.
+ Reported by Marty Leisner.
+
+ * list.c (read_and): When telling block numbers in verbose output,
+ clearly list block numbers for NUL blocks and end of file.
+ Reported by Jörg Weule.
+
+ * tar.c (usage): Document --newer-time.
+ Reported by Greg Chung.
+
+1995-11-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * system.h: Conditionally include <sgtty.h> prior to <mtio.h>.
+ * rmt.c: Do not include <sgtty.h> anymore.
+ Reported by Harald König and Kaveh R. Ghazi.
+
+ * rtapelib.c: Remove seemingly useless include of setjmp.h.
+
+ * rtapelib.c: Try to get EOPNOTSUPP defined in all cases.
+ If needed, include net/errno.h or sys/inet.h when they exist.
+ Reported by Goeran Uddeborg, J.J. Bailey, John L. Chmielewski,
+ Peder Chr. Norgaard and Yasushi Suzudo.
+
+1995-11-29 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (decode_options): Diagnose --block-compress properly.
+ Was segment violating because falling into --blocking-factor.
+
+ * buffer.c, create.c, diffarch.c, genfile.c, gnu.c, tar.c:
+ Uniformly write nonzero instead of non-zero.
+ Reported by Karl Berry.
+
+ * system.h, buffer.c, create.c, diffarch.c, tar.c, update.c [MSDOS]:
+ Instead of __MSDOS__, all occurrences.
+ * extract.c (extract_archive) [MSDOS]: Avoid delaying restoration
+ of timestamps for directories.
+ * buffer.c (child_open_for_compress): Add a missing semi-colon.
+ * diffarch.c (diff_archive): Avoid comparing uid and gid.
+ Reported by Yasushi Suzudo.
+
+ * tar.c (usage): Correct absolute-paths to absolute-names.
+ Reported by Jonathan Kamens.
+
+ * tar.c (usage): Indicate that --exclude uses globbing, and that
+ --label uses regexps.
+ Reported by John R. Vanderpool and Matti Aarnio.
+
+ * tar.c (names_notfound): Do not report a fake namelist entry, so
+ gzipped empty archives will not produce spurious diagnostics.
+ Reported by Jonathan Kamens.
+
+1995-11-23 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (name_scan, name_match): Avoid labels and gotos.
+
+1995-11-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (DISTFILES): Distribute ChangeLog.
+
+ * ChangeLog: New, extracted from top-level ChangeLog.
+
+ * tar.c (main, decode_options): Delay request_stdin for `-f'
+ until all options processed, so we now for sure that `-' means
+ standard input, not standard output.
+
+ * tar.c (usage): Document that users should not count on
+ POSIX support yet, saying it is only partially implemented so far.
+
+1995-10-27 François Pinard <pinard@iro.umontreal.ca>
+
+ * rtapelib.c (_rmt_shutdown): Add the errno_value parameter.
+ (__rmt_open): Call shutdown if remote open fails, or else, we lose
+ file descriptors.
+ Reported by Holger Teutsch.
+
+1995-10-20 Tom Tromey <tromey@drip.colorado.edu>
+
+ * tar.c (request_stdin): New function.
+ (stdin_used_by): New variable.
+ (name_init, add_exclude_file, decode_options): Use request_stdin
+ if required.
+ (confirm): Check stdin_used_by to see if stdin in use.
+
+ * list.c (read_header): Consistently use sizeof to find size
+ of checksum field.
+
+1995-08-26 François Pinard <pinard@iro.umontreal.ca>
+
+ * names.c (uid_to_uname, gid_to_gname): Ensure that the empty
+ string is returned when not found, instead of the previous one.
+
+1995-08-06 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c (new_volume): Use stderr rather than stdlis for
+ interactions. Clarify `archive == 0' into `archive == STDIN'.
+ Reported by Scott Hunziker.
+
+1995-08-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * diffarch.c (diff_archive): When symlink differs, report the
+ file name, not the link name.
+ Reported by Dale R. Worley and Wolfram Wagner.
+
+1995-07-23 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (Makefile): Remove some useless lines.
+
+1995-06-27 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Sort out declarations a little better.
+ * tar.c (decode_options): Reorder the cases in the big switch.
+
+ * tar.h: Introduce OLDGNU_COMPATIBILITY, enum archive_format,
+ variable archive_format. Delete flag_old_archive, flag_standard.
+ * tar.c (decode_options): Initialize archive_format so that -o
+ yields V7_FORMAT, nothing yields OLDGNU_FORMAT, --posix yields
+ GNU_FORMAT, and --posix with POSIXLY_CORRECT yields POSIX_FORMAT.
+ * create.c (start_header): Use TMAGIC and TVERSION if required.
+ Replace all flag_old_archive and flag_standard appropriately.
+
+ * tar.c: Implement a --record-size option, which is an
+ alternate way of saying --blocking-factor, in bytes this time.
+
+ * tar.h, tar.c, create.c (dump_file): Implement
+ a --no-recurse option, to help using tar with find.
+ Reported by Chris G. Demetriou, Jamie Zawinski, Kimball
+ Collins, Oswald P. Backus IV and Stuart Poulin.
+
+ * tar.h, tar.c, buffer.c (child_open_for_compress):
+ Delete --block-compress, issue a warning if used. It was never
+ obeyed while outputting on disk files, where it would have been
+ useful. It was only obeyed for pipes, remotes and devices, that
+ is, exactly when it would be an error not to specify it.
+
+ Reported by Hans Guerth, James H Caldwell Jr, Jean-loup Gailly,
+ Jeffrey W. Parker, John D. Sybalsky, Kai Schlichting, Marcin
+ Matuszewski, Mike Silano, Paul O'Connor, Pete Geenhuizen and
+ Richard Stallman.
+
+ * buffer.c (open_archive): Cosmetic changes.
+
+ * buffer.c, diffarch.c, tar.h, update.c: Rename fl_read by
+ flush_read and fl_write by flush_write.
+
+1995-06-26 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (usage): Remind that `USER@' may be specified.
+ Reported by John J. Szetela and Oliver Trepte.
+
+ * tar.c (usage): Replace `modificators' by `modifiers'.
+ Reported by Alan Modra.
+
+ * extract.c (set_mode, set_stat): New functions, from
+ previous code, elsewhere. Replace various occurrences of code
+ appropriately with function calls. Ensure mode bits are properly
+ set in all circumstances. This may imply calling set_mode twice.
+ Reported by Piercarlo Grandi and Tim Magill.
+
+ * extract.c: Save the whole stat information in saved
+ directory information, instead of parts of it, all mistyped.
+ (restore_saved_dir_info): Free information as we consume it.
+ Simplify code by using set_mode and set_times. Rename routine to
+ apply_delayed_set_stat, and do some other cleanup around it.
+
+ * *.[hc]: Replace flag_confirm by flag_interactive,
+ flag_do_chown by flag_same_owner,
+ flag_exstdout by flag_to_stdout,
+ flag_follow_links by flag_dereference,
+ flag_gnudump by flag_incremental,
+ flag_ignorez by flag_ignore_zeros,
+ flag_keep by flag_keep_old_files,
+ flag_local_filesys by flag_one_file_system,
+ flag_modified by flag_touch,
+ flag_multivol by flag_multi_volume,
+ flag_namefile by flag_files_from,
+ flag_new_files by flag_after_date,
+ flag_oldarch by flag_old_archive,
+ flag_reblock by flag_read_full_records,
+ flag_run_script_at_end by flag_info_script,
+ flag_sayblock by flag_block_number,
+ flag_sorted_names by flag_same_order,
+ flag_sparse_files by flag_sparse,
+ flag_startfile by flag_starting_file,
+ flag_use_protection by flag_same_permissions,
+ OPTION_COMPRESS_PROG by OPTION_USE_COMPRESS_PROGRAM,
+ flag_volhdr by volume_label,
+ flag_compressprog by compress_program,
+ flag_rsh_command by rsh_command,
+ and flag_volno_file by volno_file.
+
+ * tar.c: Rename --modification-time by --touch, and provide a
+ warning for the old option.
+
+1995-06-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * list.c (decode_header): At extraction time, use the stored
+ uid if uname is unknown in this system, and use the stored gid if
+ gname is unknown in this system, instead. This solves a long
+ lasting bug by which restored files were all owned by root, using
+ an incomplete /etc/passwd or /etc/group file.
+ * names.c: Rename finduname to uid_to_uname and findgname to
+ gid_to_gname, exchanging the order of arguments. Use uid_t and
+ gid_t instead of int's. Use empty strings in cached_[ug]name for
+ marking there is no valid cached translation, instead of using
+ magic values for cached_[ug]id. Rename finduid to uname_to_uid
+ and findgid to gname_to_gid, adding a second argument to store the
+ result if found, and returning a success/failure indication, not
+ anymore assuming the current [ug]id by default.
+ * tar.h, create.c, list.c: Adjust prototypes and callers.
+
+ Reported by Anders Andersson, Bernard Derval, Brian Perkins,
+ Charles Fu, Daniel Trinkle, Ian Jackson, Johannes Helander,
+ Michael Lin, Richard Sims, Robert E. Brown, Tim P. Starrin and
+ Torkel Hasle.
+
+ * tar.h, create.c, list.c, names.c, tar.c:
+ Implement --numeric-owner, to replace the NONAMES define. Then,
+ ensure some reasonable values to magic and linkflags if POSIX.
+ Reported by Benedikt Stockebrand, Ian Jackson and Stephen Gildea.
+
+ * buffer.c: Delete save_block function, as well as
+ saved_block_pointer and saved_block variables. Blocks were
+ carefully saved indeed, but never consulted after the fact.
+ * tar.h: Delete save_block prototype.
+ * *.c: Delete all usages of save_block.
+
+ * rmt.c: Add static to variable declarations.
+ * list.c (read_header): Rename recsum to recorded_sum.
+
+1995-06-23 François Pinard <pinard@iro.umontreal.ca>
+
+ * *.[hc]: Rename --read-full-blocks to --read-full-records,
+ --block-size to --blocking-factor, and --record-number to
+ --block-number.
+ * tar.c (decode_options): Diagnose usage of old names.
+
+ * *.[hc]: Rename saverec to save_block, findrec to
+ find_next_block, and userec to set_next_block_after.
+ Replace endofrecs by available_space_after which does the space
+ computation instead of returning the end pointer, adjust and
+ simplify all callers, by using variable data_block systematically.
+ Also, rename union block field charptr to buffer.
+
+1995-06-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * *.[hc]: Exchange "record" and "block" almost everywhere and
+ whenever appropriate, to follow the terminology used in
+ P1003.1-1990, and so removing a lot of confusion in sources.
+
+ * tar.h: Prefer naming constants and fields per P1003-1.1990 as
+ far as possible. Rename those remaining LF_xxx to GNUTYPE_xxx.
+ * *.c: Adjusted accordingly.
+
+ * tar.h: Clean up the header structure. Make very clear what is
+ specified by POSIX, and what is GNU format, and what is extended
+ header for sparse files. Use xxx_FIELD_SIZE instead of NAMSIZ,
+ TUNMLEN and TGNMLEN. Dismangle some other names, on the way...
+ * *.c: Adjusted accordingly.
+
+ * tar.h: Do not declare baserec, declare current_block_ordinal.
+ * buffer.c (current_block_ordinal): New function.
+ Rename baserec to record_start_block, and make it static.
+ * list.c: Use current_block_ordinal, avoid baserec computations.
+ * buffer.c, list.c: Get rid of saved_recno and annofile.
+
+ * buffer.c, diffarch.c: Move no_op and wantbytes from
+ buffer.c to diffarch.c. Correct prototypes so first arg is long.
+ * tar.h: Do not declare no_op nor wantbytes, anymore.
+
+ * tar.h, buffer.c: Move ar_block, ar_record and ar_last
+ from tar.h to buffer.c, renaming them to record_start,
+ current_block, record_end respectively.
+ * update.c: Add temporary extern declaration for record_start,
+ current_block and record_end.
+
+ * tar.h, buffer.c: Move ar_reading from tar.h to buffer.c,
+ renaming it to reading_archive.
+ * diffarch.c: Add temporary extern declaration for
+ reading_archive.
+
+ * buffer.c, create.c, diffarch.c, extract.c, gnu.c,
+ list.c, names.c, rmt.c, rmt.h, rtapelib.c,
+ tar.c, update.c: Replace many #ifdef's by #if's, and
+ #ifndef's by #if !'s.
+
+ * buffer.c (redirect): New name for dupto. Callers changed.
+
+ * create.c (dump_file), extract.c (extract_archive,
+ extract_sparse_file), tar.h: Remove crumb about ending_blanks
+ and end_nulls.
+
+ * Makefile.in (all): Do not prepare genfile by default, as it
+ is only needed for checking.
+
+ * tar.c (decode_options): Diagnose lacking arguments to old
+ options.
+ Reported by Aage Robeck, Alan Cox, Benny Holmgren, Bruno Haible,
+ Daniel Quinlan, Michael Schmidt, Richard J. Kettlewell and Robert
+ Leslie.
+
+1995-06-21 François Pinard <pinard@iro.umontreal.ca>
+
+ * rtapelib.c (__rmt_open): Avoid dereferencing remote_user
+ when NULL.
+
+ Reported by Alois Steindl, Amos Yahil, Anders Liljeborg, Andre
+ Novaes Cunha, Andreas Haumer, Andreas Reuter, Andy Gay, Bdale
+ Garbee, Bradley A. Smith, Brett Gaines, Bruce Jerrick, Calvin
+ Cliff, Cameron Elliott, Charles Lopes, Charles M. Hannum, Chris
+ Metcalf, Christophe Colle, Christopher T. Johnson, Dale Wiles,
+ David Shaw, Dimitri Bougoulias, Daniel Hagerty, Dave Gregorich,
+ David Mansfield, David Nugent, David Shaw, David Steiner,
+ Douglas Scott, Dunstan Vavasour, Edgar Taube, Eduardo Kortright,
+ Elmer Fittery, Eric Benson, Eric M. Boehm, Gerd Knorr, Graham
+ Whitted, Harald Milz, Heiko Schlichting, James V. Di Toro III,
+ Jan Carlson, Janne Snabb, Jeff Sorensen, Jens Henrik Jensen,
+ Jim Clausing, John J. Szetela, John R. Vanderpool, Jurgen Botz,
+ Karl Berry, Karlos Z. Smith, Karsten Thygesen, Koji Kishi,
+ Luke Mewburn, Manuel Munier, Marc Ewing, Matthew J. D'Errico,
+ Martin Goik, Maxime Taksar, maximum entropy, Michael Hayes,
+ Michael Schwingen, Michael Smolsky, Michael Kaufman, Mike Walker,
+ Minh Tran-Le, Mitsuaki Masuhara, Nelson H. F. Beebe, Noel Cragg,
+ Olaf Wucknitz, Oliver Trepte, Olivier Roussel, Patrick Fulconis,
+ Paul Kanz, Paul Nordstrom, Pekka Janhunen, Peter Carah, Peter
+ Kutschera, Phil Hands, Randy Bias, Reuben J. Ravago, Ricardo
+ Marek, Robert Anthony Nader, Rod Buchanan, Roderich Schupp,
+ Russell Cattelan, Scott J. Kramer, Scott L. Burson, Simon
+ Wright, Sisira Jayasinghe, Steffen Stempel, Thomas M. Browder
+ Jr., Thomas Waas, Tim Bradshaw, Tim Lashua, Timothy J. Lee, Tom
+ Popovitch, Toshiaki Nishi, Victor J. Griswold, Wayne Christopher,
+ William J. Eaton, Wlodzimierz Jan Martin, Wolfgang Rupprecht
+ and Wolfram Wagner.
+
+ * tar.h: Remove external prototypes related to rtapelib.c, as
+ those are already declared in rmt.h.
+
+1995-06-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c (xclose): New, from port.c (ck_close).
+ Replace ck_close by xclose in all modules.
+ * port.c: Remove ck_close.
+
+ * port.c: Remove ck_malloc, because xmalloc can be used
+ instead, now that it protects against malloc(0) returning NULL.
+ * gnu.c (gnu_restore), list.c (read_header): Replace
+ ck_malloc with xmalloc. In gnu_restore, remove skipping code in
+ case of failed allocation, because tar already aborted in xmalloc.
+ * tar.h: Delete ck_malloc declaration.
+
+ * port.c: Remove mknod, link, chown and geteuid, which
+ normally exist on Unix. To be reinserted later, as needed.
+ Reported by Jyh-Shyang Wang, Nelson H. F. Beebe, Philippe Defert
+ and Serge Granik.
+
+ * tar.c: Declare TTY_NAME, moved over from port.c.
+
+ * extract.c (extract_archive), tar.c (decode_options):
+ Clean out old NO_OPEN3 code.
+ * Makefile.in: Adjusted.
+
+ * buffer.c (child_open): In-line previous ck_pipe code.
+ * tar.h: Delete ck_pipe declaration.
+ * port.c: Delete ck_pipe function.
+
+ * misc.c: New, reorganizing remaining code from port.c.
+ * port.c: Deleted.
+ * Makefile.in: Adjusted.
+
+ * misc.c (un_quote_string): If `\' ends a string to unquote,
+ just pass it undisturbed.
+ From Robert Lipe.
+
+ * system.h: Replace many #ifdef by #if, #ifndef by #if !.
+
+1995-06-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Release 1.11.8.
+
+ * Makefile.in (mostlyclean): Remove also _*.c and _*.o.
+
+ * create.c (dump_file), gnu.c (get_dir_contents): Cast
+ (int) explicitely for test.
+
+ * Makefile.in ($(OBJECTS)): Depend on ../intl/libgettext.h
+ instead of ../intl/libintl.h, which does not always exist.
+
+ * genfile.c: Define EXIT_SUCCESS and EXIT_FAILURE if not.
+ * tar.c (main): Use TAREXIT_SUCCESS instead of EXIT_SUCCESS.
+
+ * tar.h: Use off_t instead of long for the second argument in
+ __rmt_lseek declaration.
+ * system.h: Remove typedef of off_t, because AC_TYPE_OFF_T
+ takes care of it now.
+ Reported by Coranth Gryphon, Jim Blandy and Thomas Krebs.
+
+1995-06-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * checktar.sh: Send a message saying that it is still useless.
+
+1995-06-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h, tar.c (decode_options), extract.c
+ (extract_archive), diffarch.c (diff_archive), create.c
+ (dump_file, start_header), tar.c (decode_options): Replace
+ flag_absolute_paths by flag_absolute_names.
+ * tar.c (decode_options): Implement OBSOLETE_ABSOLUTE_NAMES for
+ reporting --absolute-paths as obsolete.
+
+ * system.h: Conditionnaly include <locale.h> and define
+ setlocale to void independently of ENABLE_NLS.
+ Reported by Ulrich Drepper.
+
+1995-06-10 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (long_options): Use no_argument and require_argument,
+ instead of constants. Have long option names translated to short
+ options whenever possible, rather than setting flags directly:
+ easing option management is worth a few extra nanoseconds.
+
+ * tar.c (long_options): Add --gunzip as meaning -z.
+ Reported by Bruno Haible.
+
+1995-06-07 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Use subdir and distdir.
+
+ * system.h [NLS]: Simplify by merely including <libintl.h>.
+ Also, define setlocale to empty only if the setlocale function is
+ not known, instead of when <locale.h> is missing.
+ * Makefile.in (INCLUDES): Use ../intl in compilations,
+ taking care of the fact libintl.h might have been symlinked there.
+
+1995-06-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c, tar.h: Rename TAR_EXTERN to GLOBAL.
+
+ * tar.h: Delete COMMAND_VERSION.
+ * tar.c: Replace OPTION_HELP and OPTION_VERSION commands by
+ show_help and show_version variables, so `--version --create' will
+ not diagnose `Too many commands'. Adjust things so this works.
+ Reported by Marty Leisner.
+
+1995-06-04 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (check): New goal.
+ * checktar.sh: New script.
+ * genfile.c: New file.
+ * Makefile.in (all): Prepare genfile.
+ * Makefile.in: Distribute checktar.sh and genfile.c.
+
+1995-06-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Adjust so extracted doc/header.texi is neater.
+
+1995-05-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (name_match): Use %s for printing directory, not %d.
+ Reported by Marty Leisner.
+
+ * tar.c (name_gather, addname): chdir_name receives string
+ pointers which might later be overwritten, but nevertheless saved
+ into structures, so, use xstrdup for the time being.
+ Reported by Michael Holmes.
+
+ * tar.c (name_next, name_from_list): Abort when chdir fails.
+ Reported by Ian Jackson and Marty Leisner.
+
+1995-05-28 François Pinard <pinard@iro.umontreal.ca>
+
+ * rmt.h: Declare second argument of __rmt_lseek to be off_t
+ instead of long, so it is the same as in rmt.c.
+ Reported by Chris Arthur.
+
+ * buffer.c (close_archive): Compensate for the addition of 2
+ to ar_block at open_archive time, for when -M used, just before
+ calling free.
+ Reported by Bruno Haible, Clinton Carr, Hernan Prieto Schmidt,
+ Kevin Dalley, Loren J. Rittle and Marty Leisner.
+
+ * rmt.c: Replace SSIZE by STRING_SIZE, avoiding a conflict
+ with some header files.
+ Reported by Kaveh R. Ghazi and William Bader.
+
+ * tar.c: Use DEVICE_PREFIX instead of DEVICE_PREXIX, and
+ WITH_REGEX instead of WITH_REGEC.
+ Reported by Bruno Haible.
+
+1995-05-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.7.
+
+ * Makefile.in (tar): Have $(OBJECTS) depend on system.h.
+
+ * system.h: Many adjustements for GNU gettext.
+
+1995-05-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Clean glocale out.
+
+1995-05-08 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Use libintl.a while linking.
+ * system.h: Include <libintl.h> unconditionally, instead only
+ if WITH_CATALOG. Let <libintl.h> define _() appropriately.
+ * tar.c (main): Call textdomain.
+
+1995-05-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * system.h, gnu.c, list.c, port.c: Avoid
+ superfluous parentheses in macro definitions.
+ * port.c: Capitalize macro arguments.
+ * buffer.c, create.c, diffarch.c, tar.c: Use comma
+ operator when assignment in test.
+
+1995-04-27 François Pinard <pinard@iro.umontreal.ca>
+
+ * port.c (link): Use WARN to report the message.
+ Reported by Sherwood Botsford.
+
+1995-03-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Remove GLOCALE, add LINGUAS, use fp_WITH_CATALOGS.
+ * system.h: Use WITH_CATALOGS to define _() differently.
+
+1995-03-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * rtapelib.c (__rmt_open): Close the unused side of each
+ pipe, instead of the useful one, prior to processing.
+ Reported by Charles Lopes and Minh Tran-Le.
+
+1995-02-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Replace `date' by `echo timestamp'.
+
+1995-02-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Support ID files. Do not distribute TAGS.
+
+1995-02-13 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Use top_srcdir.
+
+1995-02-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * gnu.c (is_dot_or_dotdot): Through NFS, readdir might deliver
+ empty filenames under old Solaris 2.4, causing endless loops in
+ tar. As a workaround, avoid `' as done already for `.' and `..'.
+ Reported by Jan Carlson.
+
+1995-02-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (maintainer-clean): New name for realclean.
+
+1995-01-04 François Pinard <pinard@iro.umontreal.ca>
+
+ * extract.c (make_dirs) [MSDOS]: Correct for Turbo C, which may
+ return EACCES instead of EEXIST on mkdir.
+ Reported by Jeffrey Goldberg.
+
+ * tar.c (usage) [MSDOS]: Do not tell about -N and related.
+ (decode_options) [MSDOS]: Be blind to -N and related.
+ Reported by Jeffrey Goldberg.
+
+ * rmt.h (_remdev): A filename is not remote if the colon is
+ preceeded by a slash, to take care of `/:/' which is a shorthand
+ for `/.../<CELL-NAME>/fs' on OSF's Distributing Computing
+ Environment (DCE) and Distributed File System (DFS).
+ Reported by Travis L. Priest.
+
+1995-01-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (decode_options): Renamed from options. Convert
+ oldish-style non-dashed options to modern writing before
+ performing option decoding. Diagnose when modern options are met
+ before old style options are fully converted. This allows
+ mixing of option styles on a single call. Avoid getoldopt and
+ use getopt_long instead.
+ * getoldopt.c: Deleted.
+ * tar.h: Prototype deleted.
+ * Makefile.in: Adjusted.
+ Reported by Bruno Haible, Les Mikesell, Patrick Timmons and Saul
+ Lubkin.
+
+1995-01-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * system.h: New file, split out of tar.h.
+ * buffer.c, create.c, diffarch.c, extract.c,
+ getoldopt.c, gnu.c, list.c, mangle.c, names.c,
+ port.c, tar.c, update.c: Include "system.h", and move
+ the inclusion of "tar.h" down after system dependent definitions.
+ * Makefile.in: Distribute system.h.
+
+ * rmt.c: Include "system.h", and simplify accordingly.
+ * rtapelib.c: Include "system.h", and simplify accordingly.
+ * rmt.h: Simplify according to the inclusion of "system.h".
+
+ * system.h: Include conditionnaly <sys/gentape.h>,
+ <sys/tape.h>, <sys/mtio.h>, <sys/ioctl.h> and <sys/io/trioctl.h>.
+ * buffer.c, diffarch.c, rmt.c, rtapelib.c,
+ update.c: Simplify accordingly.
+
+ * system.h: If it exists, include <sys/ioccom.h> prior to
+ <sys/mtio.h>, to account for problems when GNU libc 1.0x is
+ installed over SunOS 4.1.3: GNU libc does not provide sys/mtio.h,
+ so it is taken from Sun header files which use things like _IOW,
+ which GNU libc despises, sys/ioccom.h then provides definitions.
+ Reported by Joseph E. Sacco.
+
+1994-12-27 François Pinard <pinard@iro.umontreal.ca>
+
+ * rmt.h: Ensure strrchr is defined to rindex in some cases.
+ Reported by Karl Vogel.
+
+1994-12-18 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Include <ctype.c> and declare ISASCII.
+ * gnu.c: Adjust, declare and use ISDIGIT and ISSPACE.
+ * list.c: Adjust, declare and use ISODIGIT and ISSPACE.
+ * port.c: Adjust, declare and use ISPRINT.
+ Reported by Bruno Haible, Konno Hiroharu and Max Hailperin.
+
+1994-12-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c, tar.c [WITH_REGEX]: Check it.
+
+1994-12-03 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.6.
+
+ * rmt.c: Adjust for localization, by including <locale.h> and
+ <libintl.h>, by defining _(), by defining and calling setlocale,
+ and by defining and initializing program_name.
+ * Makefile.in: Use locale.o and libtar.a with rmt.
+
+ * Makefile.in: Ensure INSTALL_DATA is defined.
+
+ * Makefile.in, tar.h, tar.c:
+ Localize, adapting from how it is done in sharutils.
+
+ * Makefile.in, tar.c: Rename PRODUCT to PACKAGE.
+
+1994-11-29 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c (backspace_output): Change cur from long to off_t.
+ * diffarch.c (diff_archive): Idem for offset.
+ * extract.c (extract_archive): Idem for offset.
+ * rmt.c: Idem for lseek ().
+ (main): For case 'L', use atol instead of atoi, and cast the
+ result to (off_t) rather than (long).
+ * rtapelib.c (__rmt_lseek): Idem of offset argument.
+ * tar.h: Change offset of sp_array from int to off_t.
+ * update.c (move_arch): Change cur from long to off_t.
+ Reported by David J. MacKenzie.
+
+1994-11-26 François Pinard <pinard@iro.umontreal.ca>
+
+ * rmt.h, tar.h, buffer.c, create.c,
+ diffarch.c, extract.c, gnu.c, list.c,
+ rtapelib.c, update.c: Rename _ to __P.
+ * tar.h, rmt.h: Declare _ as a macro returning its
+ argument, or else, include <libintl.h> and declare _ as gettext.
+ * tar.c: Possibly include <locale.h> and call setlocale.
+ * rmt.c, buffer.c, create.c, diffarch.c,
+ extract.c, getoldopt.c, gnu.c, list.c,
+ mangle.c, port.c, rtapelib.c, tar.c,
+ update.c: Use _ macro over all localizable strings.
+
+ * rtapelib.c: Declare prototype for xstrdup. Do not declare
+ strstr, which is not needed.
+
+1994-11-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Clean up, following those of GNU m4. I will
+ not detail all the changes here.
+ * tar.c: Use PRODUCT and VERSION instead of version_string.
+
+1994-10-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h [__STDC__]: Use #if instead of #ifdef.
+
+1994-10-27 François Pinard <pinard@iro.umontreal.ca>
+
+ * rmt.h, tar.h, buffer.c, create.c, diffarch.c,
+ extract.c, gnu.c, list.c, mangle.c, tar.c,
+ update.c: Rename all f_* variables to flag_*.
+
+ * tar.h, buffer.c, tar.c, update.c: Rename cmd_mode into command_mode.
+ * tar.c (SET_COMMAND_MODE): New macro, use it.
+
+ * port.c (quote_copy_string): Prevent sign extension of
+ character while copying it to an int.
+ * (un_quote_string): Increment to_there pointer in all cases.
+ Reported by Konno Hiroharu, Mats Lofkvist, Max Hailperin and
+ Ryutaro Susukita.
+
+1994-10-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * rmt.c, rtapelib.c, tar.h: Get rid of CONFIG_BROKETS.
+
+1994-10-04 François Pinard <pinard@iro.umontreal.ca>
+
+ * diffarch.c (fill_in_sparse_array): Add a cast for Pyramid's
+ dumb compiler. Later remove the cast and compare to 0 instead.
+ * extract.c (extract_archive): Idem.
+ Reported by Karl Vogel and Kaveh R. Ghazi.
+
+1994-09-27 François Pinard <pinard@iro.umontreal.ca>
+
+ * diffarch.c: Normalize capitalization in diagnostics.
+
+1994-09-26 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (name_next, name_match): Abort tar if directory cannot
+ be changed, instead of going on. This is not an innocuous error.
+ Reported by Marty Leisner.
+
+1994-09-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * rtapelib.c: Include "rmt.h" only once <sys/types.h> has been
+ included, because off_t might not be defined otherwise.
+ Reported by James W. McKelvey, John L. Chmielewski, Karl
+ Vogel, Kaveh R. Ghazi an and Jim Meyering and Tilman Schmidt.
+
+1994-09-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in: Cleanup...
+ (DISTFILES): Distribute TAGS.
+ (ansi2knr): Use $(LIBS).
+ (TAGS): Make TAGS in $(srcdir) only.
+ (distclean): Do not remove TAGS.
+ (realclean): Remove TAGS.
+ (Makefile): Have ./config.status create this Makefile only.
+
+1994-09-13 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c: Remove the presetting of stdlis, because stdout is
+ not a constant in GNU libc.
+ Reported by Joseph E. Sacco and Thomas Bushnell n/BSG.
+
+ * buffer.c (new_volume): Pass an otherwise unused argument to
+ wait, do not use NULL.
+ Reported by Thomas Bushnell n/BSG.
+
+1994-09-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.in (TAGS): Remove -t on etags call. It has been
+ the default behavior for a few releases of Emacs and it seems that
+ option -t is now disappearing (from Emacs 19.25, at least).
+ Reported by Goeran Uddeborg.
+
+1994-09-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * gnu.c (get_dir_contents): Do not set dp->allnew if dp is not
+ set itself.
+ Reported by Piercarlo Grandi.
+
+ * extract.c (extract_archive): Issue diagnostic or verbose
+ messages to msg_file, instead of stdout.
+ Reported by Piercarlo Grandi.
+
+1994-08-23 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Do not declare alloca if already defined, so HP's
+ +Olibcalls compiler option works.
+ Reported by John David Anglin.
+
+ * rtapelib.c (__rmt_open): Use REMOTE_SHELL only if defined.
+ Otherwise, if the command argument has been specified and
+ REMOTE_SHELL is not defined, immediately return an error.
+ Reported by Bruno Haible, Kaveh R. Ghazi, Marty Leisner,
+ Torkel Hasle and William Bader.
+
+ Because --rsh-command may always be given, even if no remote shell
+ was found at configure time, remote capabilities are always
+ compiled. This also solve other problems related to RTAPELIB.
+ * Makefile.in: Always compile $Urtapelib.o.
+ * buffer.c (child_open): Always test _remdev, do not depend
+ anymore on HAVE_RTAPELIB.
+ * rmt.h [!HAVE_RTAPELIB]: Remove some code.
+ Reported by Andreas Schwab and Vic Abell.
+
+ * rtapelib.c: Remove unused COMPAT (mis)feature. Remove most
+ length limitations for remote host name, remote user name and
+ remote device name. Duplicate path, and free it in all cases.
+ * (_rmt_rexec): The `user' parameter may never by the empty
+ string. Remove code for that case.
+
+1994-08-22 François Pinard <pinard@iro.umontreal.ca>
+
+ Little cleanup in installation:
+ * Makefile.in: Remove rule for ../lib/libtar.a.
+
+1994-08-21 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.5.
+
+ * Makefile.in: Correct for when a different build directory.
+
+ * tar.h: Replace W* definitions. Adapted from make 3.71.
+ * buffer.c (close_archive): Replace WIFCOREDUMPED by
+ WCOREDUMP. Previous WIFSIGNALED definition was excluding SIGSTOP,
+ new definition do not exclude it anymore. We'll see.
+ Reported by Demizu Noritoshi, Greg Black, Kaveh R. Ghazi,
+ Robert E. Brown and Russ Evans.
+
+1994-08-20 François Pinard <pinard@iro.umontreal.ca>
+
+ This might (?) solve the dirent problems on NeXT's and Apollo's:
+ * tar.h: Change includes and defines from older AC_DIR_HEADER
+ style to newer and clearer AC_HEADER_DIRENT style.
+ * create.c, gnu.c: Replace NLENGTH by NAMLEN.
+ Reported by Drew Trieger, Hugh Secker-Walker, James W. McKelvey,
+ Robert E. Brown and Thomas Krebs.
+
+1994-08-17 François Pinard <pinard@iro.umontreal.ca>
+
+ Remove some shadowings.
+ * update.c (update_archive): Rename head_standard to unused.
+ * buffer.c (open_archive): Rename head to label.
+ (fl_read): Rename head to cursor.
+
+ * gnu.c (dirent_cmp): Use (char *const *), not (const char **)
+ for not loosing the const specifier while casting.
+
+ * mangle.c (extract_mangle): Remove unused argument.
+ * tar.h: Adjust prototype.
+ * extract.c (extract_archive): Caller changed.
+
+ * rtapelib.c (__rmt_open): Remove useless mode parameter.
+ * rmt.h, tar.h: Adjust prototype.
+ * rmt.h: Adjust macros calling __rmt_open.
+ * create.c (deal_with_sparse): Remove unused argument.
+ * create.c (dump_file): Caller changed.
+ Reported by Greg Black.
+
+ * Makefile.in: Avoid $U in defining RTAPELIB. Remove both
+ rtapelib.o and _urtapelib.o explicit rules, not needed anymore.
+ * rmt.h, buffer.c [HAVE_RTAPELIB]: Instead of !NO_REMOTE.
+ Reported by Andreas Schwab.
+
+ * Makefile.in: Correct a typo in $Ubuffer.o dependencies.
+ Reported by Andreas Schwab.
+
+ * rtapelib.c (__rmt_ioctl): Compile the MTIOCGET case only if
+ this symbol is defined. This also solves a missing mt_type field
+ on NS32016 running SysVr2.2.
+ Reported by Greg Black.
+
+ * rtapelib.c (__rmt_ioctl) : Conditionnalize only the MTIOCTOP
+ case, not the whole routine, with the MTIOCTOP symbol. In case of
+ unrecognized operation, return EOPNOTSUPP instead of EINVAL.
+ * rmt.h: Always provide a prototype for __rmt_ioctl. Delete
+ the RMTIOCTL machinery.
+
+1994-08-16 François Pinard <pinard@iro.umontreal.ca>
+
+ * rmt.c, buffer.c: Use a more uniform way of including
+ <sys/mtio.h> or its alternates.
+ Reported by Daniel R. Guilderson and Kaveh R. Ghazi.
+
+ * Makefile.in: Split rule for $Urtapelib.o into one rule for
+ rtapelib.o and one rule for _rtapelib.o, taking care of the fact
+ that rtapelib.c is in $(srcdir) while _rtapelib.c is in current
+ directory.
+ Reported by Andreas Schwab, Kaveh R. Ghazi, Minh Tran-Le and
+ Per Foreby.
+
+ * rmt.c (string_error): Correct DEBUG2 into DEBUG1, and strint
+ into string.
+ Reported by Anders Andersson, Bruno Haible, Thomas Krebs and
+ Thomas König.
+
+ * Makefile.in: Add $U's to rtapelib and rmt specific rules.
+ Reported by Thomas König.
+
+1994-08-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.4.
+
+ * rmt.c (numeric_error): Renamed from error.
+ (string_error): New, to replace ERROR ((...)), unavailable in rmt.c.
+
+ * rmt.c (checkbuf): Do not accept, nor return record. Use the
+ global instead. This will get rid of useless shadowings.
+
+ * rmt.h: Give prototypes for __rmt_* routines.
+ * rtapelib.c: Include "rmt.h".
+ * update.c (move_arch): Cast last rmtioctl argument to char *.
+ * buffer.c (backspace_output): Idem.
+ * diffarch.c (verify_volume): Idem.
+
+ * Makefile.in (rmt): Declare dependencies over rmt.h.
+
+1994-08-14 François Pinard <pinard@iro.umontreal.ca>
+
+ * rtapelib.c: Use MTIO_CHECK_FIELD instead of mt_type.
+ Reported by Ben A. Mesander.
+
+1994-08-13 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Include <sys/wait.h> if it exists, whether POSIX or not.
+ Check if WIFSTOPPED is defined, to decide if defining others WIF*.
+ Reported by Bruno Haible.
+
+1994-08-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * extract.c (extract_archive) [O_CTG]: Declare longname variable.
+ Initialize it as NULL. This dirty kludge will allow the module to
+ compile on Masscomp's, for the time being.
+ Reported by Ben A. Mesander.
+
+ * tar.h, rtapelib.c: Declare strstr if we replaced it.
+ Reported by Ben A. Mesander, Christian T. Dum and Kaveh R. Ghazi.
+
+1994-08-10 François Pinard <pinard@iro.umontreal.ca>
+
+ * create.c (dump_file): Do not test only for hpux, but also
+ for __hpux. I added __hpux__ too, as done in tar.h.
+ Reported by Richard Lloyd.
+
+ * tar.h: Do not include <sys/mknod.h> anymore for HP-UX from
+ HP-UX 8 and after, for which definitions are in <sys/sysmacros.h>,
+ and reorganize the tests in this area.
+ Reported by Christian T. Dum, Dimitris Fousekis, Kimmy Posey,
+ Michael Maass, Richard Lloyd and Thomas König.
+
+1994-08-09 François Pinard <pinard@iro.umontreal.ca>
+
+ These changes for const-cleaning gnu.c and tar.c:
+ * tar.c (read_name_from_file): Work directly on global
+ variables instead of accepting parameters. Return success or
+ failure as an int instead of the relocated name_buffer.
+ (name_next): Caller changed, internal clean-up of the function.
+ Remove trailing slashes on the command call too, not only when
+ reading from a file through -T option.
+ * gnu.c: Add const to name and dir_text in struct dirname.
+ Reported by Ben A. Mesander, Bruno Haible, Christian T. Dum,
+ Dean Gaudet, James W. McKelvey, Richard Lloyd and Robert E. Brown.
+
+1994-08-08 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (name_next, name_gather, addname): Use strcmp for
+ checking for "-C", instead of decomposed tests, just for clarity.
+
+ * Makefile.in (RSH): Define from configuration.
+ (rtapelib.o): Define REMOTE_SHELL from $(RSH) while compiling.
+ * rtapelib.c (__rmt_open): If command not given, use
+ REMOTE_SHELL, instead of cascading tries of filenames.
+ Reported by Bruno Haible.
+
+ * tar.c: Include <fnmatch.h> if FNM_LEADING_DIR is not
+ defined, instead of checking for FNM_PATHNAME, because some
+ <unistd.h> define the later without defining the former.
+ Reported by Thomas König.
+
+ * create.c (dump_file): Cast alloca results, for those
+ compilers not processing void * properly.
+ Reported by Kaveh R. Ghazi.
+
+ * Makefile.in: Get prefix and exec_prefix from configure.
+ Reported by Andreas Schwab, Christian T. Dum and Dean Gaudet.
+
+ * src/port.c: Delete mkdir (and rmdir), rename, strstr and
+ ftruncate replacements.
+ Reported by Kaveh R. Ghazi (for memset and strstr).
+ Reported by Bruno Haible (for mkdir and rename).
+
+1994-08-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Replace msg_file by stdlis.
+ * buffer.c, gnu.c, list.c, diffarch.c: Idem.
+
+ * tar.c (main): Print version on stdout, not stderr.
+
+ * tar.h: Unconditionnaly insert the pad. Why play the game of
+ forcing the compiler to do it for us? (Hum! I'm not so sure.)
+ Reported by Bruno Haible.
+
+ * list.c (read_header): Initialize signed_sum to 0. Use this
+ opportunity for slightly reorganizing the code around.
+ Reported by Anders Andersson, Andrey A. Chernov, Bruno Haible
+ and Chris Ransom.
+
+ * tar.c: Declare name_buffer_length as size_t instead of int.
+ Reported by Andreas Schwab, J.T. Conklin, Kaveh R. Ghazi and
+ Robert E. Brown.
+
+ * rmt.h: Have the NO_REMOTE case be a particular case of the
+ other, for rmtopen and rmtcreat were not transmitting the proper
+ number of parameters to open and creat (since 26 July 1994).
+ Reported by Andreas Schwab.
+
+ * extract.c (extract_archive): Delay changing owner to after
+ doing utime, for keeping long enough the permission of utime'ing.
+ (extract_archive, restore_saved_dir_info): Idem for directories.
+ Reported by Jonathan I. Kamens.
+
+ * tar.h: Change malloc_dbg to dmalloc, mutatis mutandis.
+
+ * tar.h: Undefine many macros if stat macros found to be
+ broken. Define mkfifo only if configure did not find it.
+ Include <sys/param.h> if not _POSIX_SOURCE, then <unistd.h> if
+ we have it, than "pathmax.h". Move _POSIX_VERSION dependent
+ code further down. Do not declare getcwd if we do not have it.
+ * tar.c: Do not include <unistd.h>, now in "tar.h".
+ Reported by Bernard Chen, Jean-Michel Soenen, John L.
+ Chmielewski and Kaveh R. Ghazi.
+
+ * tar.h: Define DEV_BSIZE, ST_BLKSIZE and ST_NBLOCKS,
+ borrowing this code from both fileutils-3.9's "lib/system.h" and
+ textutils-1.9's "system.h".
+ * create.c (dump_file): Straighten the test for sparseness,
+ which was requiring one block too much, most probably for trying
+ to get around DEV_BSIZE/st_blksize confusion. Use ST_NBLOCKS,
+ instead of computing a variable block_size and doing specific
+ tests for HP-UX or Linux. Also rewrite the test so it works
+ when ST_NBLOCKS is unsigned.
+ Reported by Bruno Haible, Dean Gaudet, Dick Streefland, Harald
+ König, Jim Meyering, Kai Petzke, Kaveh R. Ghazi and Torkel Hasle.
+
+1994-08-04 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c: Do not include <unistd.h> if we do not have it.
+ Reported by Kaveh R. Ghazi.
+
+ * Makefile.in (RTAPELIB): Prefix by $U for unprotoization.
+ Reported by Kaveh R. Ghazi and Christian T. Dum.
+
+ * port.c: Remove many static specifiers.
+ Reported by Demizu Noritoshi, Kaveh R. Ghazi and William Bader.
+
+ * rtapelib.c (__rmt_open): Replace system by remote, twice.
+ Reported by Ben A. Mesander, Christian T. Dum, Demizu Noritoshi
+ and Kaveh R. Ghazi.
+
+ * tar.c (addname): Replace a forgotten EX_SYSTEM by
+ TAREXIT_FAILURE.
+ Reported by Demizu Noritoshi, James W. McKelvey, Kaveh R.
+ Ghazi and Robert E. Brown.
+
+1994-08-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.3.
+
+ * tar.c (assign_string): New routines.
+ * create.c (dump_file, start_header), extract.c
+ (extract_archive), list.c (list_archive, read_header),
+ buffer.c (open_archive), diffarch.c (diff_archive): Use
+ assign_string for setting these variables to a string value or
+ NULL.
+ * buffer.c (open_archive): Sets current_file_name,
+ current_link_name and save_name to NULL.
+ (close_archive): Free each of them if not NULL.
+ (fl_write): Take a copy of save_name into cursor, and advance the
+ cursor instead, because save_name should stay free-able.
+ Reported by Dave Gentzel, Harald Anlauf, Mark Clements, Robert
+ Weissenfels, Ronald van Loon, Tsutomu Yamada and Vic Abell.
+
+ * extract.c (extract_archive): Use xstrdup, for clarity.
+ * gnu.c (add_dir): Idem.
+
+ * list.c (print_header): Correct a little bug by which
+ non-symbolic links were not printed properly quoted.
+
+ * diffarch.c (diff_archive): Allocate tmpbuf to the proper
+ size. NAMSIZ + 2 is not necessarily enough.
+
+1994-08-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Refresh str*/mem* configured declarations. Among
+ other things, this will solve previously missing #undef's.
+ * rmt.h: Revise strchr configured declaration.
+ * *.c: Replace bzero by memset, bcopy by memcpy, bcmp by
+ memcmp, index by strchr and rindex by strrchr.
+ * port.c: Delete functions bzero and bcmp, said to not exist
+ on Minix. AC_MINIX in configure.in should guarantee POSIX things.
+ Reported by Drew Trieger, Hugh Secker-Walker and Vic Abell.
+
+ * tar.h, tar.c, buffer.c, update.c: Change CMD_* to COMMAND_*.
+
+ * buffer.c (open_archive): Use strcmp to compare archive name
+ to `-', instead of doing it explicitely. Just for clarity.
+
+ * tar.h, tar.c, buffer.c: Replace ar_files by
+ archive_name_array, n_ar_files by archive_names and ar_files_len
+ by allocated_archive_names. Replace the index cur_ar_file by
+ archive_name_cursor, which is a cursor in archive_name_array.
+
+ * tar.c (main): Move the initialization of
+ archive_name_array at beginning, taken from options routine.
+ Free it at end of main.
+ (options): Use xrealloc instead of ck_realloc for archive_name,
+ for the already saved names to be preserved.
+ Reported by Per Bojsen.
+
+ * tar.h, tar.c: Replace name_file by namefile_name.
+ * tar.c: Replace n_ind by name_array, n_indused by names,
+ n_indalloc by allocated_names, and n_indscan by name_index.
+ Replace namef by name_file, n_argv by names_argv and n_argc by
+ names_argc.
+ (main): Make an initial allocation for name_array at beginning,
+ moved out from name_add, free it at end of main.
+
+ * buffer.c (close_archive): Free ar_block at end.
+
+1994-07-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h [WITH_MALLOC_DBG]: Include "malloc_dbg.h".
+
+ * create.c (create_archive): Do not attempt creating a
+ directory summary file if -G, since -G sets gnu_dumpfile to 0.
+ Reported by Alexander Dupuy.
+
+ * create.c (dump_file): Avoid a NULL dereference with -G when
+ trying to dump an empty directory.
+ * gnu.c (add_dir_name): Same thing.
+ Reported by Rainer Orth.
+
+ Correction for the improper `data differs' diagnostic given when
+ the continuation of a multi-volume was compared.
+ * diffarch.c (diff_archive): If multi-volume, update save_name
+ and save_totsize before calling wantbytes.
+ * buffer.c (wantbytes): If multi-volume, update save_sizeleft.
+ Reported by Andreas Schwab, Denis Fortin, François Pinard,
+ Hiroyuki Bessho, Olaf Schlueter, Simon Wright and Saul Lubkin.
+
+1994-07-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c (options): Implement DEVICE_PREFIX and DENSITY_LETTER.
+ Reported by Danny R. Johnston.
+
+ * gnu.c (gnu_restore): Use CURRENT_FILE_NAME abbreviation.
+ * extract.c (extract_archive): Idem.
+ Reported by Timothy Fossum.
+
+1994-07-29 François Pinard <pinard@iro.umontreal.ca>
+
+ * create.c (dump_file): Abort if no memory for a possible
+ link, remove related bogus code, and the variable nolinks.
+ Reported by Andreas Schwab.
+
+ * create.c (dump_file): Detect file sparseness correctly for
+ Linux ext2 filesystem.
+ Reported by Kai Petzke.
+
+ * port.c (link) [!MSDOS]: Do not call setmode.
+ Reported by Richard Deal.
+
+ Reorganization for `tar -d' to provide a different exit status.
+ * tar.h: Replace errors by exit_status. Declare TAREXIT_*.
+ * buffer.c (child_open): Exit with exit_status.
+ * tar.c (main): Initialize exit_status to TAREXIT_SUCCESS, and
+ exit with exit_status.
+ * buffer.c, diffarch.c, gnu.c, list.c, port.c,
+ rmt.c, tar.c, update.c: Replace EXIT_FAILURE by
+ TAREXIT_FAILURE, and EXIT_SUCCESS by TAREXIT_SUCCESS.
+ * tar.h (ERROR), create.c (dump_file): Set exit_status to
+ TAREXIT_FAILURE instead of increasing errors.
+ * diffarch.c (sigh, diff_sparse_files): On differences, set
+ exit_status to TAREXIT_DIFFERS if nothing more serious already.
+ Reported by Tilman Schmidt.
+
+ * rmt.c: Define EXIT_FAILURE and EXIT_SUCCESS if not already.
+ * rtapelib.c: Define EXIT_ON_EXEC_ERROR to 128 and use it.
+
+1994-07-27 François Pinard <pinard@iro.umontreal.ca>
+
+ * diffarch.c (sigh): Increment errors, so a difference will
+ yield a non-zero exit status at end.
+ Reported by Nick Holloway.
+
+ * tar.h: Rename TARERROR to WARN, then add ERROR which is similar,
+ but increments the errors counter.
+ * *.c: Replace all TARERROR by WARN or ERROR, deciding for each
+ case. Many errors were not reflected in exit status.
+
+ Reported by Carl Streeter, Esa Karell, George Chyu, Ian Jackson,
+ Judy Ricker, Massimo Dal Zotto, Roland McGrath, Tilman Schmidt
+ and Torkel Hasle.
+
+ * buffer.c (child_open): Exit with EXIT_FAILURE if any error.
+
+ * rtapelib.c: Use error for reporting errors.
+ (do_command): New name for command.
+ (get_status): New name for status.
+
+ * buffer.c: Remove definition of MAGIC_STAT.
+ (close_archive): Do not check MAGIC_STAT for an exit value, since
+ this value is never returned.
+
+ * *.c: Use TARERROR or exit with EXIT_FAILURE, instead of various
+ esoteric statuses. Normalize using TARERROR with an exit status,
+ instead of calling TARERROR with 0 first, then _exit. On exit
+ calls, use EXIT_SUCCESS instead of 0.
+ * tar.c: Do not use the exit status anymore for outputting an
+ error counter value. Wrap around was creating spurious success.
+ * tar.h: Remove EX_* definitions for tar exit statuses.
+ Reported by Bob Mende and Torbjorn Granlund.
+
+1994-07-26 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Add f_rsh_command variable.
+ * tar.c: Add and process --rsh-command option.
+ * buffer.c (open_archive, child_open, new_volume): Pass
+ f_rsh_command to rmtopen and rmtcreat calls.
+ * rmt.h (rmtopen, rmtcreat): Pass a supplementary argument.
+ * rtapelib.c (__rmt_open): Accept and process a command
+ argument, to replace rsh.
+ Reported by Jonathan I. Kamens.
+
+ * tar.h: Instead of including <sys/file.h> with BSD42 or
+ <fcntl.h> for V7, merely include <fcntl.h> if it exists,
+ otherwise <sys/file.h>.
+ * buffer.c, diffarch.c, extract.c, list.c,
+ port.c, update.c: Do not include <fcntl.h> or
+ <sys/file.h>, because they are indirectly included through
+ "tar.h".
+
+ * create.c (dump_file): Remove the BSD42 conditional. If not
+ f_sparse_files, initialize upperbound as when not BSD42.
+ Reported by Alan Bawden, Claude Scarpelli, Laurent
+ Sainte-Marthe, Noah Friedman, Reuben Sumner, Tom Quinn and
+ William Bader.
+
+1994-07-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Merely define valloc as being malloc if valloc does
+ not exist.
+ * port.h: Remove valloc, which was only a dummy for malloc.
+ Reported by Cliff Krumvieda, Francois Pinard, Henrik Bakman,
+ J.T. Conklin, Nelson H.F. Beebe and Tilman Schmidt.
+
+1994-07-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * create.c (start_header): Cast NAMSIZ to size_t before
+ comparing it to strlen result.
+ Reported by Mark Frost.
+
+ * tar.c (main): Zero out label_pattern before compiling in
+ regular expressions, instead of using uninitialized memory.
+ Reported by Holger Teutsch.
+
+ * tar.c [!FNM_PATHNAME]: Include fnmatch.h only if unistd.h fails
+ to define this symbol.
+ Reported by Alan Modra, Christian T. Dum, Eddy ?, John
+ Oleynick and Richard Lloyd.
+
+ * buffer.c, diffarch.c, rtapelib.c, update.c:
+ Include <sys/io/trioctl.h> before <sys/mtio.h>, if it exists.
+ Reported by Kaveh R. Ghazi.
+
+ * tar.c (options): Use defined OPTION_* constants instead of
+ anonymous numbers for long options not having a short option form.
+
+ * rmt.h [!MTIOCTOP]: Do not define RMTIOCTL, so __rmt_ioctl
+ will not be called if it has not been compiled in rtapelib.c.
+
+ * tar.h: Add CMD_TOO_MANY.
+ * tar.c (main): Use CMD_TOO_MANY, and get rid of badopt label.
+ Reported by David J. MacKenzie.
+
+ * tar.c (usage): New name for describe(). Rewritten with
+ better help formatting and more logical grouping of options.
+ Accepts an exit status argument. Callers adapted.
+ Reported by Richard O'Neill.
+
+1994-07-20 François Pinard <pinard@iro.umontreal.ca>
+
+ * port.c (rename): Constify the arguments.
+ Reported by Elmar Heeb, Jeff Prothero and John Clark.
+
+ * tar.c (main): Declare version_string locally.
+ * version.c: Deleted.
+ * Makefile.in: Adjusted.
+
+1994-07-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.h: Merge "port.h" towards the beginning of tar.h.
+ Include <stdio.h> and <errno.h>, and define errno if needed.
+ * *.c: Do not include "port.h" anymore after "tar.h", do not
+ include <stdio.h>, <errno.h> nor <sys/types.h>. Also move
+ "tar.h" as the first file included in every module. This
+ would solve, among other things, the problem of RE_DUP_MAX
+ being redefined by <limits.h>, when included after "regex.h".
+ * port.h: Deleted.
+ * Makefile.in: Adjusted.
+ Reported by Alan Modra, Christian T. Dum, Dimitris Fousekis,
+ John David Anglin, Matthew Braun, Michael Maass, Richard Lloyd
+ and Stefan Skoglund.
+
+ * create.c (dump_file): Do not cast alloca result to (char *).
+ The problem reported was that alloca result was seen as int, but
+ with the changes just made, alloca should be properly declared.
+ Reported by Bryant Fujimoto and Michael Kubik.
+
+1994-07-06 François Pinard <pinard@iro.umontreal.ca>
+
+ * create.c, extract.c [HAVE_UTIME_H]: Instead of _POSIX_VERSION,
+ for choosing to include <utime.h>.
+ Reported by Carl Swanson and Thomas Krebs.
+
+1994-07-05 François Pinard <pinard@iro.umontreal.ca>
+
+ * tar.c: Replace DEF_AR_FILE with DEFAULT_ARCHIVE, replace
+ DEFBLOCKING with DEFAULT_BLOCKING.
+
+ * rtapelib.c: Replace "??'" by "?? '" at two places in a
+ comment, so avoiding Pyramid's DC/OSx compiler to complain about
+ ANSI trigraph sequences. Even comments can trigger bugs, now!
+ Reported by Mark Frost.
+
+ * tar.h: Declare valloc.
+ * buffer.c, diffarch.c: Remove declaration for valloc.
+
+ * testpad.c: Deleted.
+ * tar.h: Do not include "testpad.h" anymore.
+ * Makefile.in: Delete testpad matters.
+
+ * buffer.c (new_volume): Inside case 'n', strcpy into r then
+ assign r to p, instead of strcpy'ing directly into p, for making
+ the module const clean.
+
+1994-07-03 François Pinard <pinard@iro.umontreal.ca>
+
+ Rename a few variables to avoid shadowing variables or functions:
+ * list.c (print_header): Change name to quoted_name.
+ * buffer.c (child_open): Change pipe to local_pipe.
+ * extract.c (extract_archive): Change namelen to namelen_bis.
+ * rtapelib.c (__rmt_open): Change system to remote.
+
+ * tar.c (options): Add two missing arguments to getoldopt
+ call, NULL is not necessarily implied on all systems.
+
+ * list.c (print_header): Add a few missing long specification
+ in formats.
+ * diffarch.c (compare_chunk, diff_sparse_files): Idem.
+ * port.c (msg, msg_perror): Idem.
+
+ * tar.h: Include prototypes for all functions which call from
+ one module to another. Declare voidstar (use it everywhere
+ instead of PTR). Move in the include <sys/stat.h> from
+ <port.h>, and the include of option.h from tar.c and
+ getoldopt.c, waiting for a better solution for all these things.
+ * port.c: Removed PTR declaration and including <sys/stat.h>.
+ * getoldopt.c, tar.c: Remove including "option.h".
+
+1994-07-02 François Pinard <pinard@iro.umontreal.ca>
+
+ * *: Protoized all function headers. Added static to
+ functions which can take it. Add many const specifiers. Remove
+ unused variables.
+
+ * port.c (xmalloc): Delete function, do not mask the true one.
+ * port.c (ck_malloc): Use xmalloc, waiting for annihilation.
+ * port.c (ck_realloc): Use xrealloc, waiting for annihilation.
+ * *: Begin switching from ck_malloc (or even pure malloc) to
+ xmalloc. Same for ck_realloc (pure realloc) to xrealloc.
+ Doing this correctly is a delicate matter, which I'll continue
+ without reporting it anymore, while doing other modifications.
+
+ * *: Replace msg and msg_perror calls by TARERROR macro calls.
+ Capitalize first word of all error messages, remove ending
+ punctuation or newline. Systematically avoid contractions for
+ `Cannot' and `Could not'. Always write `WARNING:' all in capitals.
+ * tar.h: Declare TARERROR as calling error(). Rename
+ variable tar to program_name.
+ * tar.c (main, options), buffer.c (child_open), port.c
+ (msg, msg_perror), gnu.c (gnu_restore): Rename variable tar to
+ program_name.
+ * gnu.c (gnu_restore): Remove a spurious repetition of
+ program_name in error message.
+
+1994-07-01 François Pinard <pinard@iro.umontreal.ca>
+
+ * buffer.c, create.c extract.c, gnu.c, list.c,
+ names.c, rmt.c, tar.c, update.c: Remove all (void)
+ prefixes to function calls. There are limits to lint clutter.
+
+1994-06-30 François Pinard <pinard@iro.umontreal.ca>
+
+ * port.h: Remove definition of const. Let configure do it.
+
+ * tar.h, rmt.c, rtapelib.c, version.c, testpad.c: Add a block
+ for including <config.h> or "config.h". If "tar.h" was included
+ everywhere, the block will only be needed there.
+
+ * *.[ch]: Reindented to GNU standards (they were not far).
+ Got rid of all `* ' left prefixes in comments and refilled them.
+ There is still a lot of cosmetic changes needed everywhere.
+ I will not report them any more, doing them along the way of
+ other things in the future.
+
+ * Makefile.in: New file.
+
+ * Split distribution into a few subdirectories, for easing
+ maintainance.
+
+ * Taking over maintenance duties.
+
+1993-08-31 David J. MacKenzie <djm@goldman.gnu.ai.mit.edu>
+
+ * rmt.c [M_UNIX]: Include sys/tape.h instead of sys/mtio.h.
+ Reported by Drew Sullivan and William Bader.
+
+1993-07-29 David J. MacKenzie <djm@wookumz.gnu.ai.mit.edu>
+
+ * Makefile.in (config.status): Run config.status --recheck, not
+ configure, to get the right args passed.
+
+1993-07-19 David J. MacKenzie <djm@churchy.gnu.ai.mit.edu>
+
+ * Makefile.in (libdir): Use standard GNU value --
+ $(exec_prefix)/lib, not /etc.
+
+1993-07-08 David J. MacKenzie <djm@goldman.gnu.ai.mit.edu>
+
+ * Makefile.in (installdirs, configure, config.status,
+ Makefile): New targets.
+
+1993-06-14 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * Makefile.in (.c.o): Put -I. before -I$(srcdir), and make
+ $(CFLAGS) last.
+
+1993-05-22 The King <elvis@graceland.gnu.ai.mit.edu>
+
+ * extract.c (extract_archive, restore_saved_dir_info): Print
+ mode in octal, not in decimal.
+ Reported by Scott S. Bertilson.
+
+1993-03-26 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * configure.in: Better way of detecting HP-UX.
+ Reported by Noah Friedman.
+
+1993-03-25 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * version.c: Released version 1.11.2.
+
+ * Makefile.in (dist): Do the link differently; some of the
+ files have changed filesystems which makes it more complex.
+
+ * Makefile.in (dist, shar): Use gzip instead of compress.
+
+ * create.c (dump_file): Test for curdev == -1, not curdev < 0.
+ Some losing NFS systems give negative device numbers sometimes.
+ Reported by Thorbjxrn Willoch.
+
+1993-03-19 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * buffer.c (new_volume): Write the global volume number to the
+ volno file before running the info script, so that the script
+ can look at it.
+
+1993-03-17 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * tar.c (describe, long_options): Changed --compress-block to
+ --block-compress.
+ (options): Fixed f_compress_block sanity check error message
+ to give the correct name of the option.
+
+1993-03-16 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * extract.c (extract_archive): case LF_DIR: Do chown when
+ necessary. Don't bother jumping to set_filestat for
+ f_modified; repeat the chmod code here. Replace `break',
+ deleted on 2 September 1992.
+
+ * tar.c (describe, long_options, options): Added gzip options
+ and use-compress-program option.
+ * tar.h: Added new compression options.
+ * buffer.c (child_open, open_archive): Use new compression options.
+
+ * create.c (start_header): Only mask off high bits when
+ creating old-style archives.
+ * list.c (decode_header): Mask off potentially misleading
+ high bits from the mode when reading headers.
+ Reported by Paul Eggert.
+
+1993-03-15 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * extract.c (extract_archive): Put arguments in the right
+ order for error message.
+ Reported by Bruno Haible.
+
+ * create.c (deal_with_sparse): If the last byte was null, we
+ didn't write it out.
+
+ * gnu.c, create.c, extract.c, diffarch.c, list.c:
+ Replace malloc calls with ck_malloc and realloc with ck_realloc.
+ Reported by Jonathan Kamens.
+
+ * tar.c (describe): Improve doc for -L.
+
+ * tar.c (name_next): Don't apply exclusion to explicitly named
+ files.
+
+ * tar.c (long_options, describe): Added new-volume-script as
+ an alias for info-script.
+
+ * extract.c (extract_archive): LF_DUMPDIR case; misplaced paren.
+
+ * extract.c (extract_archive): extract_file case, first if,
+ include space for null in namelen computation.
+
+ * extract.c (extract_sparse_file): Use value returned by write
+ to properly create error message.
+
+ * create.c (create_archive): Don't assume we have anything to
+ dump.
+
+ * buffer.c (open_archive): Set current_file_name for the
+ volume header so that verbose listings work properly.
+
+ * Makefile.in (realclean): Added getdate.c.
+
+ * create.c (deal_with_sparse): If exactly 26 elements in
+ sparsearray, only 25 were written.
+ Reported by Jim Murray.
+
+ * create.c (deal_with_sparse): If the file ends with a zero
+ block, the last byte was not written. This is fixed in create
+ rather than extract: if amidst_data is not set at EOF, put out a
+ block with just the last byte of the file.
+ Reported by Jim Murray.
+
+1993-01-14 David J. MacKenzie <djm@kropotkin.gnu.ai.mit.edu>
+
+ * tar.c: Include fnmatch.h after port.h to make sure we get our FNM_*
+ (e.g. on HPUX 8).
+
+1992-11-24 David J. MacKenzie <djm@goldman.gnu.ai.mit.edu>
+
+ * tar.c (addname), gnu.c (read_dir_file) [HAVE_GETCWD]: Instead of USG.
+
+ * port.h, rmt.h [HAVE_STRING_H]: Instead of USG.
+
+ * port.h: Add dir header decls.
+ * create.c, gnu.c: Use SYSNDIR, SYSDIR, and NDIR
+ instead of BSD42 and USG. Rename DP_NAMELEN to NLENGTH.
+ Use `struct dirent' instead of `struct direct'.
+ * create.c, gnu.c, tar.c: Remove dir header decls.
+
+1992-11-18 David J. MacKenzie <djm@goldman.gnu.ai.mit.edu>
+
+ * tar.c: Change FNM_TARPATH to FNM_LEADING_DIR to match change
+ in fnmatch.[ch].
+
+1992-10-02 David J. MacKenzie <djm@goldman.gnu.ai.mit.edu>
+
+ * tar.c (describe): Fix some tab alignments.
+
+ * Makefile.in (SRC3): Add getdate.c, for systems without bison/yacc
+ (like MS-DOS).
+
+ * diffarch.c (diff_sparse_files): Add missing arg to fprintf calls.
+
+ * extract.c (extract_archive, restore_saved_dir_info),
+ buffer.c (child_open), list.c (decode_header, print_header):
+ Delete unused vars.
+
+ * port.c [__MSDOS__]: Have strstr, rename, and mkdir. Don't
+ define ck_pipe.
+
+ * buffer.c, tar.c (init_volume_number, closeout_volume_number),
+ create.c (write_long): Declare as void, not int, since they
+ don't return a value.
+
+1992-09-22 Michael I Bushnell <mib@wookumz.gnu.ai.mit.edu>
+
+ * buffer.c (close_archive): Removed leftover `break' from when
+ this was a switch.
+
+1992-09-22 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * create.c, port.h: indented #pragma directives with 1 space.
+
+1992-09-18 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * All source files: re indented using GNU indent.
+
+ * rtapelib.c (__rmt_read): Only read the amount left in the
+ buffer; otherwise a broken rmt server (which puts too much
+ data out) could overwrite past our buffer.
+
+1992-09-17 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * configure.in: Check for getpwuid and getgrgid.
+ Reported by J.T. Conklin.
+
+ * create.c: Throughout, use struct utimbuf rather than array
+ of longs.
+ Reported by J.T. Conklin and Michael Ellis.
+
+ * Makefile.in (SRC3, AUX): Move alloca.c to SRC3.
+ (OBJ3): Add @ALLOCA@.
+
+ * Makefile.in (getdate.c): Look in srcdir for getdate.y.
+
+ * buffer.c (close_archive): We can't check WTERMSIG
+ meaningfully unless we already know tha WIFSIGNALED is true.
+ (There is no guarantee it WTERMSIG will return zero when
+ WIFSIGNALED is false.)
+ * port.c (rmdir, mkdir): Check WIFSIGNALED rather than
+ WTERMSIG.
+
+ * Makefile.in (getdate.c): Use $(YACC) instead of `yacc'.
+
+1992-09-15 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * version.c: Released version 1.11.1.
+
+ * Makefile (AUX): Added NEWS.
+
+ * Makefile.in (rmt): Added $(LIBS).
+
+ * mangle.c (extract_mangle): Null terminate link name for
+ losing archives missing it.
+
+ * configure.in: Added tests for libraries needed on Solaris.
+
+ * Makefile.in: added target and rule for getdate.c: getdate.y;
+ some makes don't have one built in.
+
+1992-09-14 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * tar.c (options, main): Advise use of --help rather than
+ +help.
+ Reported by J.T. Conklin.
+
+ * create.c (write_long): Using hstat here is a Bad Idea, and
+ totally unnecessary at that.
+
+ * list.c (read_header): Compute both signed and normal
+ checksums.
+ Reported by Robert E. Brown.
+
+ * diffarch.c, buffer.c: Declare valloc as void* rather than
+ char*.
+ Reported by Robert E. Brown.
+
+ * Makefile.in: Don't install info files.
+
+ * port.h: Undefine index and rindex if necessary; some
+ string.h's define them for us.
+
+ * tar.c (addname): Missing braces after if.
+ * gnu.c (read_dir_file): Missing braces after if.
+
+ * names.c: Add include of <stdio.h>,
+
+ * create.c (start_header): Set current_file_name so that
+ print_header, used for verbose create, works properly.
+ (dump_file): Set current_link_name when setting up symlink
+ and hardlink records.
+ Reported by Robert Crowe.
+
+ * configure.in: Define BSD in the presence of /sdmach or
+ /../../mach.
+ Reported by Robert E. Brown.
+
+ * configure.in: Check for malloc was scrambled.
+
+1992-09-11 David J. MacKenzie <djm@nutrimat.gnu.ai.mit.edu>
+
+ * fnmatch.[ch]: New files.
+ * wildmat.c: File removed.
+ * tar.c: Include fnmatch.h and use fnmatch instead of wildmat.
+ * Makefile.in, makefile.pc: Replace wildmat.o(bj) with fnmatch.
+
+1992-09-10 David J. MacKenzie <djm@nutrimat.gnu.ai.mit.edu>
+
+ * buffer.c, tar.c: Remove redundant decls of getenv, rindex.
+
+ * Makefile.in: Add uninstall target.
+ Define libdir instead of hardcoding /etc for installing rmt.
+
+1992-09-10 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * list.c (read_header): On second thought, that doesn't work
+ either, so just store the names in malloced areas. Sigh.
+
+ * NEWS: New file.
+ * README: Removed things that belong in NEWS; point to it.
+
+ * list.c (read_header): current_file_name and
+ current_link_name need to be set to the arrays in head rather
+ than header; header is the actual read buffer and will change.
+
+ * extract.c (extract_archive):
+ * buffer.c (new_volume): `#' directives need to start in
+ column 1.
+ Reported by J.T. Conklin.
+
+1992-09-09 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * version.c: Release of version 1.11.
+
+ * Makefile.in (AUX): Add getpagesize.h.
+ (AUX): Comment out manuals.
+ (all): Comment out dependency on tar.info.
+
+ * Makefile, configure.in: Arrange to use local malloc on HP-UX.
+
+ * port.h Use the canonical Autoconf chunk for alloca instead
+ of just looking for gcc.
+
+1992-09-09 Noah Friedman <friedman@nutrimat.gnu.ai.mit.edu>
+
+ * port.h: If compiling with gcc, use __builtin_alloca.
+
+1992-09-08 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * extract.c: Removed long name support from here.
+ * list.c (read_header): Understand and skip longname/longlink
+ headers here. Names for current file are stored in new global
+ variables. All source files except create.c changed to refer
+ to current_file_name and current_link_name instead of fields
+ directly from the current header.
+
+1992-09-03 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * create.c (write_long): New function.
+ (dump_file): When writing link records or symlink records, use
+ new write_long function instead of mangling when the link
+ target is too long.
+ (start_header): Use write_long instead of mangling for long
+ names.
+ * extract.c (saverec): Recognize LF_LONGNAME and LF_LONGLINK.
+ (saverec): Throughout, use longname and longlink if they are set.
+
+1992-09-02 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * mangle.c: This is now deprecated; retain extract_mangle for
+ backward compatibility.
+
+ * list.c (print_header): Prevent printing 0 when the gid or uid is
+ null.
+ Reported by Chris Arthur.
+
+ * list.c (decode_header): Use the gid field when the gid is empty,
+ and similarly for uid.
+ Reported by Chris Arthur.
+
+ * extract.c: saved_dir_info, saved_dir_info_head: new type and
+ var.
+ (extract_archive): When extracting directories, now save info
+ in saved_dir_info_head.
+ (restore_saved_dir_info): New function.
+ * list.c (read_and): Call restore_saved_dir_info at the end of
+ the run.
+ Reported by Chris Arthur.
+
+1992-08-31 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * create.c (create_archive): If there are no names specified,
+ write nothing on the archive instead of dumping ".".
+
+ * buffer.c (open_archive): Useful error message.
+
+ * tar.c, tar.h: Recognize f_atime_preserve.
+ * create.c (dump_file): Implement f_atime_preserve.
+
+ * rmt.h (_remdev): Don't require /dev/ to be in remote archive
+ names; obey new force-local flag.
+ * tar.c, tar.h: Implement new force-local flag.
+ Reported by Roland Schemers III.
+
+ * tar.c (describe): same-owner and same-order were confused.
+
+ * create.c (dump_file): Check for toplevel had sense reversed.
+
+ * buffer.c (new_archive): Don't free old_name...when these
+ come from the command line, they aren't malloced, and it isn't
+ important to save this trivial amount of memory.
+
+ * tar.h: replace ar_file with ar_files, n_ar_files,
+ cur_ar_files.
+ * buffer.c (open_archive): multi-volume compressed archives
+ never worked; give an appropriate error. Change open of
+ ar_file to open of ar_files[0].
+ (writeerror, readerror, flush_archive): use
+ ar_files[cur_ar_file] instead of ar_file.
+ (new_archive): Necessary changes to support ar_files.
+ * tar.c (options): handle multiple tape drive arguments.
+
+1992-08-28 Michael I Bushnell <mib@wookumz.gnu.ai.mit.edu>
+
+ * list.c (decode_header), create.c (start_header), tar.h (TMAGIC):
+ Undo djm's changes below; tar does not support the final
+ Posix.1 format; it's bad to make it look like it does.
+
+1992-07-19 David J. MacKenzie <djm@nutrimat.gnu.ai.mit.edu>
+
+ * port.h: Try to prevent redefining major.
+ * port.c [minix]: Implies HAVE_BZERO. Fix a typo.
+
+ * list.c (decode_header): Recognize the final POSIX.1 magic as
+ well as the early draft magic for ustar.
+ * create.c (start_header): Create a final POSIX.1 magic string
+ instead of an early draft string for ustar.
+ * tar.h (TMAGIC): Remove the trailing blanks.
+
+ * rmt.c, rtapelib.c: Use POSIX and STDC headers if available.
+ * rmt.h: Declare the external functions defined in rtapelib.c.
+
+1992-07-14 David J. MacKenzie <djm@apple-gunkies.gnu.ai.mit.edu>
+
+ * pathmax.h: New file.
+ * port.h: Include it.
+ * create.c (create_archive): Allocate PATH_MAX instead of
+ NAME_MAX for temporary buffer so we don't have to figure out
+ what NAME_MAX is (portably).
+
+1992-07-10 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * gnu.c (collect_and_sort_names): write_dir_file has no argument.
+
+1992-07-06 David J. MacKenzie <djm@nutrimat.gnu.ai.mit.edu>
+
+ * port.c (rename): If unlinking the source at the end fails,
+ unlink the destination instead to avoid leaving a mess.
+
+1992-07-03 David J. MacKenzie <djm@nutrimat.gnu.ai.mit.edu>
+
+ * buffer.c, diffarch.c, update.c, rtapelib.c [HAVE_SYS_MTIO_H]:
+ Instead of NO_MTIO.
+
+ * port.c, tar.h [HAVE_FOO]: Instead of FOO_MISSING.
+
+1992-06-23 David J. MacKenzie <djm@goldman.gnu.ai.mit.edu>
+
+ * rmt.c: Add #ifdefs to work on ISC.
+
+1992-05-20 David J. MacKenzie <djm@churchy.gnu.ai.mit.edu>
+
+ * port.h: Define major, minor, makedev if the system doesn't.
+
+1992-05-13 Michael I Bushnell <mib@apple-gunkies.gnu.ai.mit.edu>
+
+ * gnu.c (add_dir_name): Store legitimate value into
+ dir_contents when get_dir_contents returns NULL.
+
+1992-05-07 Michael I Bushnell <mib@apple-gunkies.gnu.ai.mit.edu>
+
+ * gnu.c (add_dir_name): Check for return of NULL from
+ get_dir_contents; see djm's change of Fri Jul 26 01:12:58 1991.
+
+1992-05-04 David J. MacKenzie <djm@churchy.gnu.ai.mit.edu>
+
+ * tar.h: Make comments for option names say -- instead of +.
+
+1992-04-29 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * tar.c, tar.t: Added +volno-file option.
+ buffer.c (init_volume_number, closeout_volume_number): New functions.
+ tar.c (main): Call new functions in the right place.
+
+ * buffer.c (fl_write, fl_read): Mod to allow losing tape
+ drives which use short counts to indicate end of tape
+ correctly handle the multi-tape stuff. The read half won't
+ co-exist with f_reblock; there's no way to fix that, of
+ course.
+
+ * tar.c, tar.h: Added new option +show-omitted-dirs.
+ list.c (read_and): Implemented show-omitted-dirs.
+ Reported by Karl Berry.
+
+ * tar.c, tar.h: Added new option +checkpoint.
+ buffer.c (fl_read, fl_write): Implemented +checkpoint lazily.
+
+ * create.c (dump_file): Added toplevel argument; some devices
+ can be negative, so the old method was bogus. All callers
+ changed.
+ Reported by Max Hailperin.
+
+ * tar.c, tar.h: Added new option +ignore-failed-read.
+ create.c (dump_file): Implemented +ignore-failed-read.
+ Reported by Bob Mende Pie.
+
+ * create.c (finish_sparse_file): Commented out debugging printf.
+
+ * tar.c, tar.h: Added new option +remove-files to delete files
+ after they are added to the archive.
+ create.c (dump_file): Implemented +remove-files for
+ everything but directories. I don't think they need it.
+
+1992-04-28 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * create.c: (dump_file): save_name needs to be set equal to p,
+ not something inside the header, because the header changes at
+ the first buffer flush.
+
+1992-04-24 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * create.c: Djm incorrectly moved the include of port.h to
+ precede the include of sys/file.h; restored.
+
+ * tar.c (main): Cases CMD_EXTRACT and CMD_LIST: declare error
+ string with const.
+
+ * gnu.c (collect_and_sort_names): Leave if around
+ write_dir_file in place.
+
+1992-04-22 David J. MacKenzie <djm@churchy.gnu.ai.mit.edu>
+
+ * rtapelib.c: SIGTYPE -> RETSIGTYPE.
+
+1992-03-09 David J. MacKenzie <djm@nutrimat.gnu.ai.mit.edu>
+
+ * rtapelib.c: Reformat and make comments more complete.
+ Rename a few variables for clarity.
+
+1992-03-05 David J. MacKenzie <djm@nutrimat.gnu.ai.mit.edu>
+
+ * tar.c (describe): Document long options as starting with --.
+
+1992-01-23 David J. MacKenzie <djm@wookumz.gnu.ai.mit.edu>
+
+ * tar.c (options): Check get_date return value for error indication.
+
+1991-12-24 David J. MacKenzie <djm@wookumz.gnu.ai.mit.edu>
+
+ * tar.c, gnu.c, extract.c, create.c, port.h, rmt.h [HAVE_UNISTD_H,
+ _POSIX_VERSION]: Instead of POSIX ifdefs.
+
+1991-12-20 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * testpad.c (main): flush stderr so perror and fprintf
+ cooperate right.
+
+1991-12-18 David J. MacKenzie <djm@wookumz.gnu.ai.mit.edu>
+
+ * port.h [MAJOR_IN_MKDEV, MAJOR_IN_SYSMACROS]: To find where to
+ get major, minor and makedev.
+ * create.c, list.c, update.c: Don't check USG to include
+ sys/sysmacros.h.
+
+1991-12-12 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * mangle.c (extract_mangle): Correctly null terminate name of
+ link target.
+
+1991-11-21 Michael I Bushnell <mib@nutrimat>
+
+ * create.c (dump_file, at start of ISREG output loop): use
+ filename from header instead of real name to make sure that we
+ get the mangled version and not one that is too long and
+ overflows buffers.
+
+1991-11-16 David J. MacKenzie <djm@wookumz.gnu.ai.mit.edu>
+
+ * tar.h: Use new criteria for STDC version of msg.
+
+1991-11-02 David J. MacKenzie <djm@wookumz.gnu.ai.mit.edu>
+
+ * create.c, gnu.c, tar.c [USG]: Use DIRENT instead of NDIR to select
+ between dirent.h and ndir.h.
+
+ * port.c [FOO_MISSING]: Instead of WANT_FOO, to make sharing code
+ and configure script with other utilities easier.
+ [VPRINTF_MISSING, DOPRNT_MISSING]: Instead of FOO_MSG, to select
+ error reporting routines.
+
+1991-08-29 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * tar.c (long_options). Fixed info-script long option.
+ Reported by Eric Norum.
+
+1991-08-26 David J. MacKenzie <djm@pogo.gnu.ai.mit.edu>
+
+ * configure, Makefile.in: Only put $< in Makefiles if VPATH
+ is being used, because older makes don't understand it.
+
+1991-08-19 David J. MacKenzie <djm@wookumz.gnu.ai.mit.edu>
+
+ * create.c: Indent '#pragma alloca' so non-ANSI compilers
+ don't choke on it.
+
+1991-08-14 David J. MacKenzie <djm@geech.gnu.ai.mit.edu>
+
+ * list.c (UGSWIDTH): Increase from 11 (sort of like Unix tar) to
+ 18, so that with normal user and group names of <= 8 chars,
+ the columns never shift in a tar -t listing.
+
+1991-08-02 David J. MacKenzie <djm@apple-gunkies>
+
+ * Makefile.in (dist): Include texinfo.tex and tar.info*.
+ (install): Install tar.info*.
+ * configure: Set INSTALLDATA.
+
+ * configure: Create config.status. Remove it and Makefile if
+ interrupted while creating them.
+
+ * configure: Check for +srcdir etc. arg and look for
+ Makefile.in in that directory. Set VPATH if srcdir is not `.'.
+ * Makefile.in: Add `prefix'.
+ (tar.info): New target.
+
+1991-07-30 David J. MacKenzie <djm@apple-gunkies>
+
+ * configure [FTIME_MISSING]: Instead of NEED_TZSET.
+
+1991-07-29 David J. MacKenzie <djm@wombat.gnu.ai.mit.edu>
+
+ * port.c [F_CHSIZE]: Additional version.
+
+1991-07-27 David J. MacKenzie <djm@wombat.gnu.ai.mit.edu>
+
+ * rmt.h: Clean up ifdefs.
+
+ * makefile.pc: Fix typo.
+ * port.h [__MSDOS__]: Instead of MSDOS.
+ [__MSDOS__]: Define off_t. Include io.h and not sys/param.h.
+ [__TURBOC__]: Use void * and don't define const.
+
+1991-07-26 David J. MacKenzie <djm@bleen>
+
+ * buffer.c: Rename `eof' to `hit_eof' to avoid conflict with an
+ MSDOS function.
+ * gnu.c (get_dir_contents): Return NULL, not "\0\0\0\0", on error.
+ * diffarch.c (diff_archive): Open files in binary mode.
+ Don't use or free a non-malloc'd return value from get_dir_contents.
+ * msd_dir.c [__TURBOC__]: Include stdlib.h.
+ * rmt.h: lseek returns off_t, not long.
+
+ * tar.c (describe): -X is +exclude-from, not +exclude.
+ (names_notfound): Free memory only if amiga, not !unix.
+
+ * tar.h, tar.c: Add +null option to make -T read
+ null-terminated filenames (such as those produced by GNU find
+ -print0), and disable -C option.
+ This guarantees that odd filenames will get archived.
+ * tar.c (read_name_from_file): New function.
+ (name_next): Call it instead of fgets.
+ From David J. MacKenzie.
+
+1991-07-24 David J. MacKenzie <djm@wookumz.gnu.ai.mit.edu>
+
+ * create.c [_AIX]: Declare alloca.
+
+ * buffer.c (open_archive): Check for successful open before,
+ not after, fstatting the fd.
+
+1991-07-23 David J. MacKenzie <djm@wookumz.gnu.ai.mit.edu>
+
+ * configure: Only define BSD42 if sys/file.h exists.
+ If alloca is missing and /usr/ucblib exists (SVR4), use it
+ instead of -lPW.
+
+ * port.h [!__STDC__]: #define const.
+ * gnu.c (dirent_cmp): Fix args to agree with ANSI C prototype.
+ * create.c: Declare ck_realloc.
+ * gnu.c, diffarch.c: Move check for symlinks to after port.h include.
+
+1991-07-20 David J. MacKenzie <djm@apple-gunkies>
+
+ * msd_dir.[ch]: Use POSIX-style `struct dirent' instead of
+ `struct direct'.
+ * create.c, gnu.c, tar.c: Adjust callers.
+
+1991-07-18 David J. MacKenzie <djm@bleen>
+
+ * port.c (ck_malloc, ck_realloc): Return PTR, not char *.
+ * gnu.c, create.c, tar.c: Fix decls.
+
+ * port.c: Don't use the preprocessor to guess missing
+ functions on Unix; let configure do it.
+ [WANT_GETWD] (getwd): Function removed; not needed because
+ getcwd is used if needed.
+ * gnu.c, tar.c [POSIX]: Use getcwd.
+
+ * rtapelib.c: Use SIGTYPE instead of testing SIGNAL_VOID.
+ Default to void (more common these days) instead of int.
+
+ * tar.c, gnu.c, mangle.c: Remove VOIDSTAR defn. Use PTR instead.
+ * port.h: Define PTR.
+
+ * gnu.c, tar.c [__MSDOS__ || USG]: Remove incorrect getcwd decl.
+ [!POSIX]: Put correct one in port.h.
+
+ * tar.c (describe): Print on stdout instead of stderr; it's
+ not so much a usage message (since you have to ask for it
+ explicitly) as on-line help, and you really need to be able to
+ page it because it's more than a screen long.
+
+ * Make #ifdefs for sys/file.h or fcntl.h, directory header,
+ sys/mtio.h consistent between files. Use NO_MTIO instead of
+ tricks with USG and HAVE_MTIO and NO_RMTIOCTL.
+ * Move decls of ANSI C and POSIX functions to port.h and
+ use standard headers to declare them if available
+ [STDC_HEADERS or POSIX].
+ * Add many missing function declarations and return types.
+ * Some places used __MSDOS__, some MSDOS; standardize on __MSDOS__.
+ * Change S_IF macros to S_IS for POSIX.
+ * port.h: Define appropriate S_IS macros if missing.
+ * port.h [POSIX]: Rename macros for testing exit status to conform to
+ POSIX; use the system's versions if available.
+ * Use POSIX PATH_MAX and NAME_MAX instead of MAXPATHLEN and MAXNAMLEN.
+ * port.h: Define PATH_MAX and NAME_MAX.
+ * create.c, gnu.c, tar.c: Use ck_malloc and free instead of
+ auto arrays of size PATH_MAX or NAME_MAX, since with pathconf
+ they might not be constants.
+ * Move all definitions of O_* to port.h to reduce redundancy.
+ * Make all source files that now need to include port.h do so.
+ * port.c: Remove #undefs of WANT_* so you can use -DWANT_*
+ when compiling, instead of having to edit port.c.
+ [WANT_DUMB_GET_DATE] (get_date): Function removed.
+ Even systems without bison can get bison output and compile it.
+ [WANT_STRING] (index, rindex, bcopy, bzero, bcmp): Functions
+ removed; the translation is now done by macros in port.h.
+ * wildmat.c (wildmat): Use POSIX.2 '!' instead of '^' to negate
+ character classes.
+
+1991-07-15 David J. MacKenzie <djm@wookumz.gnu.ai.mit.edu>
+
+ * testpad.c (main): Return type void.
+
+ * port.c [WANT_STRING]: Don't include memory.h if NO_MEMORY_H.
+
+ * create.c (dump_file) [AIX]: Fix typo, `allocate' for `alloca'.
+ * gnu.c (collect_and_sort_names): Move misplaced brace out of #ifdef.
+ Reported by Minh Tran-Le.
+
+ * configure: Also look in sys/signal.h for signal decl.
+
+1991-07-10 David J. MacKenzie <djm@wookumz.gnu.ai.mit.edu>
+
+ * Rename rtape_server.c to rmt.c and rtape_lib.c to rtapelib.c.
+
+ * configure, Makefile.in: $(INSTALLPROG) -> $(INSTALL).
+
+1991-07-09 David J. MacKenzie <djm@wookumz.gnu.ai.mit.edu>
+
+ * Most files: Refer to GPL version 2.
+ * COPYING: Use version 2.
+
+ * port.c [__TURBOC__] (utime): New function.
+
+ * xmalloc: New function (just calls ck_malloc), for alloca.c
+ and bison.simple (in getdate.y output).
+
+ * Makefile.in (AUX): Include alloca.c and tcexparg.c, a
+ command line globber for Turbo C.
+
+1991-07-08 David J. MacKenzie <djm@geech.gnu.ai.mit.edu>
+
+ * testpad.c: Open and write to testpad.h instead of stdout,
+ because some MS-DOS makes (Borland's at least) can't do
+ redirection in commands.
+ * Makefile.in: Don't redirect testpad output.
+
+1991-07-08 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
+
+ * buffer.c (fl_read): Missing \n in printf.
+
+1991-07-08 David J. MacKenzie <djm@geech.gnu.ai.mit.edu>
+
+ * create.c, extract.c, gnu.c, diffarch.c, tar.c: Comment out
+ unused variables.
+
+ * tar.c (options): Cast get_date arg to VOIDSTAR instead of
+ `struct timeb *', since on some non-BSD systems the latter is
+ undefined.
+
+1991-07-06 David J. MacKenzie <djm@geech.gnu.ai.mit.edu>
+
+ * Replace Makefile with configure, Makefile.in, and makefile.pc.
+ Update README with current compilation instructions.
+
+ * port.c [WANT_RENAME] (rename): New function.
+
+1991-07-03 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * testpad.c (main): Avoid warning from some compilers on array
+ address.
+
+ * rtape_server.c (sys_errlist): Should be declared extern.
+ Reported by Stuart Kemp.
+
+1991-07-01 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * Release of version 1.10; appropriate changes to README.
+
+ * create.c: Removed printf's about sparse files.
+
+1991-06-21 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * list.c (skip_extended_headers): Userec was being called in
+ the wrong place.
+
+1991-06-20 David J. MacKenzie <djm@geech.gnu.ai.mit.edu>
+
+ * tar.h [STDC_MSG]: Use ANSI prototypes for msg and msg_perror,
+ even if BSD42 is also.
+
+ * Makefile: Replace DESTDIR with bindir.
+ (install): Don't install tar.texinfo. There's no standard
+ place for texinfo files, and /usr/local/man is inappropriate.
+ Add TAGS, distclean, and realclean targets and SHELL= line.
+
+ * version.c: Move old change history to bottom of ChangeLog.
+
+1991-06-12 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * rtape_lib.c (__rmt_write) [SIGNAL_VOID]: Instead of USG.
+
+1991-06-05 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * tar.c (name_match, addname): Ugly hack to handle -C without
+ any files specified.
+ tar.h (struct name): New field for ugly hack.
+
+1991-06-03 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * testpad.c: New file to determine if we need special padding
+ in struct header in tar.h.
+
+ * tar.h (struct header): include padding if necessary, include
+ testpad.h.
+
+ * Makefile: rules to create testpad.h, etc.
+
+1991-05-22 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
+
+ * tar.c (options): -L takes an argument.
+
+ * rtape_lib.c (__rmt_open): add /usr/bin/nsh to the list of
+ remote shell programs.
+
+ * create.c: define MAXPATHLEN if we don't get it from a system
+ header file.
+
+ * create.c (deal_with_sparse): return a real return value if
+ we can't open the file.
+
+ * tar.c (long_options): +newer takes an argument.
+ (describe): fix printing in various trivial ways
+
+1991-05-21 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * tar.c (long_options): +get and +concatentate don't require arguments
+
+1991-05-20 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * create.c (write_eot): Don't try and write an EOF if we are
+ already at one.
+
+ * port.c (strstr): Looking for null string should return zero.
+
+1991-05-19 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * tar.c (options): -l doesn't take an argument
+
+ * Makefile: Minor fix for SGI 4D defines.
+ Reported by Andrew Torda.
+
+ * rtape_server.c (main.c): For 386/AIX. I'm suspicious about this
+ one.
+ * create.c (dump_file): For hidden files on AIX.
+ gnu.c (collect_and_sort_name, get_dir_contents): AIX hidden file mod.
+ Reported by Minh Tran-Le.
+
+ * tar.c: (name_next): Allow -C inside a file list given to -T.
+ Reported by David Taylor.
+
+ * Makefile: Comment describing presence of USE_REXEC.
+
+ * extract.c (extract_archive, case LF_SPARSE): zero check for
+ last element on numbytes needs to look at value after
+ converted from octal.
+
+ * port.c [HAVE_STRSTR]: Check it, instead of always demanding strstr.
+ Makefile: Comment describing presence of HAVE_STRSTR option.
+
+1991-05-19 David J. MacKenzie <djm@churchy.gnu.ai.mit.edu>
+
+ * port.c (get_date): Renamed from getdate, to avoid SVR4 conflict.
+ * tar.c: Call get_date instead of getdate.
+
+1991-05-10 Noah Friedman <friedman@nutrimat>
+
+ * tar.c: added "\n\" to the end of some documentation strings
+ where they were left off.
+
+1991-05-09 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * Makefile: added level-0, level-1, and backup-specs to AUX.
+ * version.c: changed to 1.10 beta.
+ * README: updated for 1.10 beta release.
+
+1991-04-02 Michael I Bushnell <mib@godwin>
+
+ * create.c (dump_file): HPUX's st_blocks is in 1024 byte units
+ instead of 512 like the rest of the world, so I special cased
+ it.
+ * tar.c: Undo Noah's changes.
+
+1991-04-01 Noah Friedman <friedman@wookumz.gnu.ai.mit.edu>
+
+ (This ought to be temporary until things are fixed properly. )
+
+ * tar.c: (struct option long_options): flag for "sparse" zero if
+ compiling under hpux.
+ tar.c: (functon options): case 'S' is a no-op if compiling under
+ hpux.
+
+1991-03-30 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * tar.h: new variable tape_length.
+
+ * tar.c (options): add new option +tape-length / -L.
+
+ * buffer.c (fl_write): Turn #ifdef TEST code for limited tape
+ length on always, for tape-length option.
+
+ * create.c (dump_file): avoid apollo lossage where S_IFIFO == S_IFSOCK.
+
+ * buffer.c: include regex.h
+ * buffer.c (fl_read, open_archive): Use regex routines for
+ volume header match.
+ * xmalloc.c: removed file; wasn't necessary.
+ * tar.c: (main) use ck_malloc instead of xmalloc.
+
+1991-03-28 Noah Friedman <friedman@goldman>
+
+ * regex.c, regex.o: New links.
+ * tar.c: include regex.h.
+ * Makefile (OBJ2): Add regex.o.
+ (regex.o, tar.o): Depend on regex.h
+ (SRC2, AUX): Add the new files.
+
+1991-03-23 Noah Friedman <friedman@wookumz.gnu.ai.mit.edu>
+
+ * Makefile: added default flags and options for compiling under
+ hpux.
+
+ * Added files alloca.c and xmalloc.c.
+
+1991-03-23 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * port.c [HPUX]: Define WANT_VALLOC.
+
+1991-03-15 David J. MacKenzie <djm@geech.ai.mit.edu>
+
+ * rtape_lib.c [USG && !HAVE_MTIO]: Define NO_RMTIOCTL automatically.
+ (_rmt_rexec): Temporarily re-open stdin and stdout to
+ /dev/tty, to guarantee that rexec() can prompt and read the
+ login name and password from the user.
+ * Makefile: Mention -DUSE_REXEC.
+ Reported by Pascal Meheut.
+
+1991-03-08 Michael I Bushnell <mib@wookumz.ai.mit.edu>
+
+ * tar.h, Makefile [HAVE_SIZE_T]: Might be useful for some people.
+
+ * gnu.c: lstat->stat define where appropriate
+
+ * buffer.c (fl_write): keep track of amount written for +totals.
+ * tar.c, tar.h: set flag f_totals from +totals option.
+ * tar.h (f_totals, tot_written): new variables.
+ * tar.c (main): print total written with CMD_CREATE.
+
+ * tar.c (main): return appropriate exit status
+
+1991-01-17 David J. MacKenzie <djm@apple-gunkies>
+
+ * port.c: Remove a spurious `+' between functions (a remnant
+ of a context diff, apparently).
+
+1991-01-09 Michael I Bushnell <mib@pogo.ai.mit.edu>
+
+ * create.c (where_is_data): Rewritten to be better, and then
+ #ifdef-ed out.
+ (deal_with_sparse): Severly pruned. Now we write or don't
+ write only complete blocks, not worrying about partial blocks.
+ This simplifies calculations, removes bugs, and elides the
+ second scan through the block. The first was zero_record, the
+ second was where_is_data.
+
+1991-01-07 Michael I Bushnell <mib@wookumz.ai.mit.edu>
+
+ * create.c (deal_with_sparse): Second computation (for short
+ reads) of numbytes increment had subtraction backwards.
+ Need to handle calling where_is_data better when we did a
+ short read (it might go past the end of the read), also, set
+ sparsearray[...].offset in this case too.
+
+1991-01-04 Jay Fenlason <hack@ai.mit.edu>
+
+ * buffer.c: Return a special error code if the archive
+ you're trying to read starts with a different label than
+ the one specified on the command line.
+
+1991-01-02 Jay Fenlason <hack@ai.mit.edu>
+
+ * gnu.c: Prepend the current directory to the gnu_dumpfile, so that
+ -C's won't affect where the output goes. (sigh.)
+
+1990-12-18 Jay Fenlason <hack@ai.mit.edu>
+
+ * gnu.c: Don't complain if the gnudumpfile we're reading info
+ from doesn't exist.
+
+ * create.c: Write out gnudumpfile after finishing writing the archive.
+
+ * tar.c: Add +exclude FNAME, and make +exclude-from do what +exclude
+ used to.
+ * Make +version an operation, not an option.
+ * Add +confirmation alias for +interactive.
+
+1990-12-04 Jay Fenlason <hack@ai.mit.edu>
+
+ * tar.c (check_exclude): Don't let MUMBLE match MUMBLE.c or
+ fooMUMBLE but only foo/MUMBLE.
+
+ * mangle.c: New file.
+ * create.c, extract.c: According changes.
+
+ * extract.c: Don't complain when extracting an already existing link.
+ Don't complain when extracting a directory iff it already exists.
+ Don't ad u+wx to directories when running as root.
+ Reported by Chip Salzenberg.
+
+ * gnu.c: Make +listed-incremental work.
+ Reported by Chip Salzenberg.
+
+ * port.c: Add the F_FREESP emulation of the ftruncate syscall.
+
+1990-11-21 Jay Fenlason <hack@ai.mit.edu>
+
+ Remove excess \n from lots of msg() calls.
+
+1990-11-19 Jay Fenlason <hack@ai.mit.edu>
+
+ * tar.c: Rename +volume to +label.
+
+1990-11-16 David J. MacKenzie <djm@apple-gunkies>
+
+ * tar.c (describe): Include the default values for -b and -f
+ (as set in the Makefile) in the message.
+
+1990-11-15 Jay Fenlason <hack@ai.mit.edu>
+
+ * extract.c (extract_archive): Do the utime() call before the
+ chmod() call, 'cuz some versons of utime() trash the file's mode
+ bits.
+
+ * list.c (read_and): Call do_something on volume headers and
+ multivol files even if they don't match the names we're looking
+ for, etc.
+
+1990-11-06 Jay Fenlason <hack@ai.mit.edu>
+
+ * port.c (un-quote-string): Don't try to write a null if there's
+ already one there.
+
+1990-11-01 Jay Fenlason <hack@ai.mit.edu>
+
+ * buffer.c (new_volume): fflush(msg_file) before reading for
+ confirmation on new volume. On EOF or error, print error msg and
+ abort.
+
+1990-10-29 Jay Fenlason <hack@ai.mit.edu>
+
+ * getdate.y: Use new version of getdate().
+
+ * tar.c (name_add): Use sizeof(char *) instead of sizeof(int)
+
+ * README: Give the correct return address.
+
+1990-10-25 Jay Fenlason <hack@ai.mit.edu>
+
+ rtape_lib.c [NO_RMTIOCTL]: Instead of RMTIOCTL, so it is on by default.
+
+ rmt.h [NO_REMOTE]: Add _isrmt() #define.
+
+ gnu.c: Add forward reference for add_dir_name().
+
+1990-10-16 Jay Fenlason <hack@ai.mit.edu>
+
+ Version 1.09 --- New -G file implementation of gnu-dump stuff.
+
+ * tar.c (name_add): Get the calls to ck_realloc and ck_malloc right.
+
+1990-10-11 Jay Fenlason <hack@ai.mit.edu>
+
+ * gnu.c: Fix A couple of typos.
+
+1990-09-19 David J. MacKenzie <djm@apple-gunkies>
+
+ * getdate.y [USG && !DAYLIGHT_MISSING] (ftime): Use `daylight'.
+
+1990-09-17 Jay Fenlason <hack@ai.mit.edu>
+
+ * gnu.c (gnu_restore): Don't use a passed char* for the
+ file name, use skipcrud+head->header.name, just like everything
+ else does. This means that gnu_restore will still work with
+ small buffers, etc.
+
+1990-09-13 Jay Fenlason <hack@ai.mit.edu>
+
+ * tar.c (add_exclude): Don't bus-error if the exclude file doesn't
+ end with a newline.
+
+1990-09-09 David J. MacKenzie <djm@albert.ai.mit.edu>
+
+ * Makefile (dist): Remove .fname when done.
+
+1990-09-06 Jay Fenlason <hack@ai.mti.edu>
+
+ * gnu.c (gnu_restore): Rember to skip_file() over the directory
+ contents, even if we don't have to do anything with them.
+
+ * create.c, extract.c, diffarch.c: Free sparsearray after we're
+ done with it.
+
+1990-09-04 Jay Fenlason <hack@ai.mit.edu>
+
+ * Makefile: Include gnu.c in dist
+
+ * gnu.c: Move add_dir above read_dir_file so that cc doesn't
+ complain about add_dir returning void.
+
+1990-09-02 David J. MacKenzie <djm@apple-gunkies>
+
+ * getdate.y: Declare some more functions and add storage
+ classes where omitted to shut compiler up.
+ [USG] (ftime): Don't use extern var `daylight'; appears that
+ some systems don't have it.
+
+1990-08-29 David J. MacKenzie <djm@apple-gunkies>
+
+ * getdate.y (lookup): In the code that allows `Aug.' to be
+ recognized as `Aug', don't chop off the final `.' from words
+ like `a.m.', so they can be recognized.
+
+1990-08-16 Jay Fenlason <hack@ai.mit.edu>
+
+ * buffer.c (open_archive): If -O, write verbosity to stderr
+ instead of stdout.
+
+1990-08-10 Jay Fenlason <hack@ai.mit.edu>
+
+ * getdate.y: Handle an explicit DST in the input string.
+ Reported by Per Foreby.
+
+1990-07-16 Jay Fenlason <hack@ai.mit.edu>
+
+ * tar.c: rename -g -G +incremental, +listed-imcremental, etc.
+
+1990-07-13 Jay Fenlason <hack@ai.mit.edu>
+
+ * tar.c: Make +newer and +newer-mtime work according to their names.
+
+ * gnu.c: If +newer or +newer-mtime, use the time specified on the
+ command line.
+
+ * buffer.c, create.c: Add test to see if dimwit is trying to
+ archive the archive.
+
+ * tar.c (long_options[]): Re-ordered, so that groups of similar
+ options are next to each other... I think.
+
+ (describe): Modified to more closely reflect reality.
+
+1990-07-06 Jay Fenlason <hack@ai.mit.edu>
+
+ * tar.c: Add compile-time option for SYS V (?) style
+ tape-drive names /dev/rmt/{n}[lmh]
+
+ * tar.c: Fix getopt-style stuff so that -C always works correctly.
+
+ * gnu.c, tar.c: Make filename to -G optional.
+
+ * {all over}: Replace some fprintf(stderr...) calls with calls
+ to msg().
+
+ * port.c: Make -Dmumble_MSG option on command line override
+ internal assumptions.
+
+ * Makefile: Mention -Dmumble_MSG options
+
+1990-07-06 David J. MacKenzie <djm@apple-gunkies>
+
+ * tar.c (options): Don't change `c' if it is 0, as getopt now
+ handles that internally.
+
+1990-07-02 Jay Fenlason <hack@ai.mit.edu>
+
+ * gnu.c (new file): Moved all the f_gnudump stuff here where we
+ can keep track of it easier. Also made -G take a file name where
+ it stores the inode information about directories so that we can
+ detect moved directores.
+
+ * create.c (dump_file): Changed slightly to work with the new
+ f_gnudump.
+
+ * tar.c: Moved the f_gnudump stuff to gnu.c
+
+ * tar.c, extract.c: Added the +do-chown option, which forces tar
+ to always try to chown the created files to their original owners.
+
+ * version.c: New version 1.09
+
+1990-06-24 David J. MacKenzie <djm@albert.ai.mit.edu>
+
+ * create.c: Change ifdefs for directory library header
+ selection to be like the ones in tar.c.
+ * Makefile [Xenix]: Link with -ldir to get the dirent.h
+ directory library.
+
+1990-06-07 David J. MacKenzie <djm@albert.ai.mit.edu>
+
+ * Makefile, buffer.c, diffarch.c [HAVE_MTIO]: Instead of MTIO, as
+ SCO Xenix defines 'MTIO' for an incompatible tape driver system in
+ a file included by termio.h.
+ * tar.h: Don't define size_t for Xenix.
+
+1990-06-05 Jay Fenlason <hack@ai.mit.edu>
+
+ * create.c (dump_file): Only print the
+ "... is on a different filesystem..." if f_verbose is on.
+ also add a case for S_IFSOCK and treat it like a FIFO.
+ (Not sure if that's the right thing to do or not, but it's better
+ than all those Unknown File Type msgs.)
+
+1990-05-31 Jay Fenlason <hack@ai.mit.edu>
+
+ * port.c [sparc]: Use instead of SPARC since the lowercase version
+ is defined, and the uppercase one isn't.
+
+1990-05-22 Jay Fenlason <hack@ai.mit.edu>
+
+ * port.c (ck_malloc): if size==0 pretend size=1
+ (ck_realloc): if(!ptr) call ck_malloc instead.
+
+1990-05-15 Jay Fenlason <hack@ai.mit.edu>
+
+ * diffarch.c (diff_archive): If not f_absolute_paths, and attempt
+ to open a file listed in the archive fails, try /filename also.
+ This will allow diff to open the wrong file if both /filename and
+ filename exist, but there's nothing we can do about that.
+
+1990-05-11 Jay Fenlason <hack@ai.mit.edu>
+
+ * Makefile: Describe new -DMTIO option.
+
+ * buffer.c, diffarch.c: Change ifdefs slightly, so that -DMTIO
+ will include sys/mtio.h even if USG is defined. This is for HPUX
+ and similar BSD/USG crossovers.
+
+1990-05-08 Jay Fenlason <hack@ai.mit.edu>
+
+ * update.c (update_archive): Call reset_eof() when appropriate.
+
+ * buffer.c (reset_eof): New function, that turns of EOF flag, and
+ re-sets the ar_record and ar_last pointers. This will allow
+ 'tar rf non-existant-file' to not core-dump.
+
+1990-05-04 David J. MacKenzie <djm@albert.ai.mit.edu>
+
+ * tar.c: Recognize the +sparse option. It was documented, but
+ only the short form (-S) was actually recognized.
+
+1990-04-17 Jay Fenlason <hack@ai.mit.edu>
+
+ * create.c: Don't access location 0 if ->dir_contents is null.
+
+1990-04-11 Jay Fenlason <hack@ai.mit.edu>
+
+ * buffer.c (flush_archive, close_archive, new_volume): Always
+ check the return value of rmtclose(), and only give a warning msg
+ if it is <0. Some device drivers (including Sun floppy disk, and
+ HP streaming tape) return -1 after an IO error (or something like
+ that.)
+
+1990-03-23 Jim Kingdon <kingdon@mole.ai.mit.edu>
+
+ * tar.c (long_options): Make it so +append +extract +list +update
+ +catenate and +delete don't take arguments.
+
+1990-03-12 Jay Fenlason <hack@ai.mit.edu>
+
+ * buffer.c (open_archive, fl_write): Set the mtime of the volume
+ header to the current time.
+
+1990-03-07 Jay Fenlason <hack@ai.mit.edu>
+
+ * buffer.c Fix +compress-block A two character patch from
+ Juha Sarlin.
+ Replace #ifdef __GNU__ with #ifdef __STDC__.
+ (new_volume): If open of new archive fails, ask again, as it
+ probably is user error.
+
+ * tar.c: Replace #ifdef __GNU__ with #ifdef __STDC__
+
+ * port.c: Clean up #ifdef and #defines a bit.
+ (quote_copy_string): Sometimes the malloc'd buffer would be up to
+ two characters too short.
+
+ * extract.c (extract_archive): Don't declare ind static.
+
+ * create.c (dump_file): Don't declare index_offset static.
+
+ * diffarch.c: Remove diff_name variable, and always use
+ head->header.name, which will always work, unlike diff_name, which
+ becomes trash when the next block is read in.
+
+1990-03-01 Jay Fenlason <hack@wookumz.ai.mit.edu>
+
+ * Makefile: Mention the -NO_REMOTE option.
+ * port.c [i386]: Fix typo, and define WANT_FTRUNCATE.
+
+1990-02-26 Jim Kingdon <kingdon@pogo.ai.mit.edu>
+
+ * getdate.y: Declare yylex and yyerror as static.
+ #define yyparse to getdate_yyparse.
+
+1990-02-25 David J. MacKenzie <djm@albert.ai.mit.edu>
+
+ * tar.c: Remove +old option, since it is a valid abbreviation of
+ +old-archive, which does the same thing.
+ (describe): A few small cleanups in message.
+
+1990-02-05 Jay Fenlason <hack@wookumz>
+
+ * port.c [sparc]: Define LOSING_MSG, since doprnt_msg doesn't work.
+ [WANT_GETWD]: Fix typo.
+
+1990-01-26 Jay Fenlason <hack@wookumz>
+
+ Version 1.08 --- Sparse file support added. Also various other
+ features.
+
+ * diffarch.c (compare_chunk): Include correct arguments in
+ a call to fprintf() for an error msg.
+ (compare_chunks, compare_dir): First argument is a long, not an int.
+
+ * tar.c (options): Use tar variable (argv[0]) as the name to print
+ in an error msg, instead of a constant "tar".
+ (confirm): Use external variable char TTY_NAME[] for name of file
+ to open for confirmation input.
+
+ * buffer.c (new_volume): Ditto.
+
+ * port.c: Add declaration for TTY_NAME[].
+
+ * rmt.h: Add long declarations for lseek() and __rmt_lseek();
+
+1990-01-23 Jay Fenlason <hack@wookumz>
+
+ * tar.c, create.c: Create the +newer-mtime option, which is like
+ +newer, but only looks for files whose mtime is newer than the
+ given date.
+
+ * rtape_lib.c [USG]: Make *both* instances of signal-handler stuff
+ use void (*foo)().
+
+1990-01-11 Jay Fenlason <hack@wookumz>
+
+ * getdate.y : Parse European dates of the form YYMMDD.
+ In ftime(): Init timezone by calling localtime(), and remember that
+ timezone is in seconds, but we want timeb->timezone to be in minutes.
+ Reported by Jörgen Haegg.
+
+ * rtape_lib.c (__rmt_open): Also look for /usr/bsd/rsh.
+ Declare signal handler as returning void instead of int if USG is
+ defined.
+
+ * port.c: Declare WANT_GETWD for SGI 4-D IRIS.
+
+ * Makefile: Include defines for SGI 4D version.
+ Reported by Mike Muuss.
+
+ * buffer.c (fl_read): Work properly on broken Ultrix systems where
+ read() returns -1 with errno==ENOSPC on end of tape. Correctly go
+ on to the next volume if f_multivol.
+
+ * list.c (list_archive, print_header): Flush msg_file after
+ printing messages.
+
+ * port.c: Delete unused references to alloca().
+ Don't crash if malloc() returns zero in quote_copy_string.
+ Flush stderr in msg() and msg_perror().
+
+ * tar.c: Flush msg_file after printing confirmation msg.
+
+1990-01-10 David J. MacKenzie <djm@hobbes.ai.mit.edu>
+
+ * tar.c (main): Change -help option and references to it to +help,
+ and remove suggestion to run info (which is unreleased, so not
+ likely to be of any help).
+
+1990-01-09 Jay Fenlason <hack @wookumz>
+
+ * create.c (dump_file): Close file descriptor if start_header()
+ fails.
+ (dump_file): Change test for `./'-ness to not think that `.' {any
+ character} is a `./'.
+ Reported by Piercarlo Grandi.
+
+ * diffarch.c (diff_init): Print correct number of bytes in error
+ message.
+
+1990-01-09 David J. MacKenzie <djm@hobbes.ai.mit.edu>
+
+ * Makefile: Add comment at top noting that two source files also
+ contain #defines that might need to be changed by hand.
+
+ * create.c, diffarch.c, extract.c: Change L_SET to 0 in lseek
+ calls, because only BSD defines it.
+ * create.c (dump_file) [BSD42]: Make sparse file checking code
+ conditional because it uses st_blocks, which the other systems lack.
+
+1990-01-02 Jay Fenlason <hack@gnu>
+
+ * port.c (quote_copy_string): Fix so it doesn't scramble memory if
+ the last character is non-printable.
+ Reported by Kian-Tat Lim.
+
+1989-12-19 Jim Kingdon <kingdon@pogo>
+
+ * port.c [BSD42]: Define DOPRNT_MSG.
+ tar.h [BSD42]: Do not prototype msg{,_perror}.
+
+1989-12-08 Jay Fenlason <hack@gnu>
+
+ * create.c (dump_file): Remove typo in msg.
+
+1989-12-01 David J. MacKenzie <djm@trix>
+
+ * Makefile: Remove comments referring to certain systems lacking
+ getopt, since it is now provided always and needed by all systems.
+
+ * port.c: Remove copy of getopt.c, as it is now linked in
+ separately to always get the current version.
+
+ * tar.c: Rename +cat-tars option to +catenate or +concatenate,
+ and +local-filesystem to +one-file-system (preferred by rms
+ and used in GNU cp for the same purpose).
+ (describe): Reflect changes.
+
+1989-11-28 David J. MacKenzie <djm@hobbes.ai.mit.edu>
+
+ * port.c: Move declaration of alloca into #else /* sparc */
+ so it will compile on sparcs.
+
+1989-11-27 David J. MacKenzie <djm@hobbes.ai.mit.edu>
+
+ * tar.c (options): Remove -version option (replaced by +version).
+ (describe): Mention long options.
+
+1989-11-25 David J. MacKenzie <djm@hobbes.ai.mit.edu>
+
+ * getoldopt.c (getoldopt): Make `opt_index' argument a pointer to
+ an int, not char.
+
+ * tar.c: Modify long options per rms's suggestions:
+ Make preserve-permissions an alias for same-permissions.
+ Make preserve-order an alias for same-order.
+ Define preserve to mean both of those combined.
+ Make old an alias for old-archive.
+ Make portability an alias for old-archive, also.
+ Rename sym-links to dereference.
+ Rename gnudump to incremental.
+ Rename filename to file.
+ Make compare an alias for diff. Leave diff but prefer compare.
+ Rename blocking-factor to block-size.
+ Rename chdir to directory.
+ Make uncompress an alias for compress.
+ Rename confirm to interactive.
+ Make get an alias for extract.
+ Rename volume-header to volume.
+
+ Also make +version an alias for -version.
+
+ (options): Shorten code that interprets long options by using
+ the equivalent short options' code. This also makes it tons
+ easier to change the long options.
+
+ (describe): Make usage message more internally consistent
+ stylistically.
+
+1989-11-20 hack@ai.mit.edu
+
+ * list.c (read_and): Call check_exclude() to see if the files
+ should be skipped on extract or list.
+
+1989-11-09 Jim Kingdon <kingdon@hobbes.ai.mit.edu>
+
+ * buffer.c (fl_read): Fix typos in error message
+ "tar EOF not on block boundary".
+
+1989-10-23 <hack@ai.mit.edu>
+
+ * tar.c (long_options[]): Add an option for blocked compression.
+
+1989-10-19 <hack@ai.mit.edu>
+
+ * buffer.c (writeerror): Print a more useful error msg.
+
+1989-09-27 <hack@ai.mit.edu>
+
+ * tar.c (main): Mention "tar -help" if the luser types a non-workable
+ set of options.
+
+1989-09-11 <hack@ai.mit.edu>
+
+ * tar.c (options): Have -F correctly set info_script.
+
+1989-08-29 <hack@ai.mit.edu>
+
+ * Makefile Include ChangeLog in tar.tar and tar.tar.Z
+
+1989-08-28 <hack@ai.mit.edu>
+
+ * tar.c (options) Made -F imply -M.
+ Also remind tar that the -f option takes an argument!
+
+ * Modified -F option to make it do what (I think) it
+ should. e.g, if you say -F, tar won't send a msg to
+ msg_file and wait for a <return> It'll just run the program
+ it was given, and when the prog returns, the new tape had
+ *better* be ready...
+
+ * buffer.c (open_archive): Give error message and abort if
+ the luser didn't give an archive name.
+
+1989-08-25 Joy Kendall <jak@hobbes>
+
+ * Added code to make a new option to run a specified script at
+ the end of each tape in a multi-volume backup. Changed: tar.c:
+ made new switch, -F, and new long-named option, "info-script".
+ Code is where you would expect.
+ * tar.h: added flag f_run_script_at_end, and an extern char *
+ called info_script, which optarg gets set to.
+ * buffer.c (new_volume): if f_run_script_at_end is set, we give
+ info_script to system(), otherwise we do what we've always done.
+
+1989-08-24 Joy Kendall <jak@spiff>
+(These changes made over the course of 6/89 - 8/89)
+
+ * diffarch.c: diff_archive: Added switches for LF_SPARSE in the
+ case statements that needed it. Also, skip any extended headers
+ if we need to when we skip over a file. (need to change the bit
+ about, if the size doesn't agree AND the file is NOT sparse,
+ then there's a discrepancy, because I added another field to
+ the header which should be able to deal with the sizes): If
+ the file is sparse, call the added routine "diff_sparse_files"
+ to compare. Also added routine "fill_in_sparse_array".
+
+ * extract.c: extract_archive: added the switch LF_SPARSE to the
+ case statement as needed, and code to treat the sparse file.
+ At label "again_file", modified opening the file to see if we
+ should have O_APPEND be one of the modes. Added code at label
+ "extract_file" to call the new routine "extract_sparse_file"
+ when we have an LF_SPARSE flag.
+
+ Note: really should erase the commented-out code in there,
+ because it's confusing.
+
+ * update.c: made sure that if a file needed to be "skipped"
+ over, it would check to see if the linkflag was sparse, and if
+ so, would then make sure to skip over any "extended headers"
+ that might come after the header itself. Do so by calling
+ "skip_extended_headers".
+
+ * create.c: create_archive: added code to detect a sparse file
+ when in the long case statement. Added ways to detect extended
+ headers, and label "extend" (ack! should get rid of that, is
+ atrocious). Call the new routine "finish_sparse_file" if the
+ linkflag is LF_SPARSE to write the info to the tape. Also added
+ routines "init_sparsearray", "deal_with_sparse", "clear_buffer",
+ "where_is_data", "zero_record", and "find_new_file_size".
+
+ * tar.h: Added the #define's SPARSE_EXT_HDR and SPARSE_IN_HDR.
+ Added the struct sparse and the struct sp_array. Added the
+ linkflag LF_SPARSE. Changed the tar header in several ways:
+ - added an array of struct sparse's SPARSE_IN_HDR long
+ - added a char flag isextended
+ - added a char string realsize to store the true size of a sparse file
+ Added another choice to the union record called a struct
+ extended_header, which is an array of 21 struct sparse's and a
+ char isextended flag. Added flag f_sparse_file to list of flags.
+
+ * tar.c: added long-named options to make tar compatible with
+ getopt_long, changed Makefile.
+
+1989-03-03 David MacKenzie (edf at rocky2.rockefeller.edu)
+(I'm not completely sure all these have been integrated -- FP.)
+
+ * buffer.c [USG]: ifdef'd out #include <sys/file.h>.
+ (close_archive): SysV doesn't have ftruncate, so substituted
+ fmtwrite (just copied the code for MS-DOS).
+ * create.c: Unos lacks <sys/sysmacros.h> so provided a substitute.
+ (start_header): Only strip leading paths if f_relative_paths is true.
+ * extract.c:
+ (extract_archive): Only strip leading paths if
+ f_relative_paths is true. Because the Unos filesystem has
+ only one timestamp, moved the utime call to after the chown
+ and chmod calls.
+ * getdate.y: Don't define ftime if Unos.
+ * list.c: Defined size_t for Unos. [USG]: Don't include <sys/file.h>.
+ Define <sys/sysmacros> stuff manually for Unos.
+ (decode_header): Add braces around switch cases; some compilers
+ require them.
+ (print_header): Changed UGSWIDTH from 11 to 25 because the smaller
+ value made tape listings of files owned by more than one user
+ gradually get wider, making them hard to read.
+ * port.c: Don't include <sys/file.h> if SysV. Define
+ size_t for Unos.
+ (mkdir): Add code to support Unos makedir sys call.
+ (getopt): Use malloc instead of alloca, because tar doesn't
+ use alloca anywhere else and many systems lack it. A few other
+ changes from the current version of getopt.c incorporated.
+ * rtape_lib.c: Undefine RMTIOCTL. Doesn't seem to be needed,
+ and can't compile on Unos/SysV with it defined. Might need to be
+ ifdef'd.
+ * tar.c: Alias addname to add_name and rmdir to deldir on Unos
+ due to C library weirdness.
+ (options): Recognize new -P option to set f_relative paths.
+ (describe): Clean up error message and add -P description.
+ * tar.h: Add variable, f_relative_paths, to cause tar to strip
+ leading `/' characters in pathnames during create and extract.
+ * tar.texinfo: Fixed a couple of typos, detected by texi2roff.
+ * update.c: Simulate <sys/sysmacros.h> for Unos.
+
+Previous releases by Jay Fenlason (hack@ai.mit.edu)
+
+ * Version 1.07 --- New version to go on beta tape with GCC 1.35.
+ Better USG support. Also support for __builtin_alloca if we're
+ compiling with GCC.
+
+ * diffarch.c: Include the correct header files so MTIOCTOP
+ is defined.
+ * tar.c: Don't print the verbose list of options unless
+ given -help. The list of options is *way* too long.
+
+ * Version 1.06 --- [__STDC__]: Use STDC_MSG.
+ ENXIO meand end-of-volume in archive (for the UNIX PC)
+ Added break after volume-header case (line 440) extract.c
+ Added patch to rtape_lib.c (reported by Arnold Robbins).
+ Added f_absolute_paths option.
+ Deleted refereces to UN*X manual sections (dump(8), etc)
+ Fixed to not core-dump on illegal options
+ Modified msg_perror to call perror("") instead of perror(0)
+ patch so -X - works
+ Fixed tar.c so 'tar cf - -C dir' doesn't core-dump
+ tar.c (name_match): Fixed to chdir() to the appropriate
+ directory if the matching name's change_dir is set. This
+ makes tar xv -C foo {files} work.
+
+ * Version 1.05 --- A fix to make confirm() work when the archive is
+ on stdin; include 'extern FILE *msg_file;' in pr_mkdir().
+ * tar.h [__STDC__]: Fix to work.
+
+ Added to port.c: mkdir() ftruncate(): Removed: lstat()
+ Fixed -G to work with -X
+ Another fix to tar.texinfo
+ Changed tar.c to say argv[0]":you must specify exactly ...
+ buffer.c: modified child_open() to keep tar from hanging when
+ it is done reading/writing a compressed archive
+ added fflush(msg_file) before printing error messages
+ create.c: fixed to make link_names non-absolute
+
+ * Version 1.04 --- Added functions msg() and msg_perror(): Modified
+ all the files to call them. Also checked that all (I hope) calls
+ to msg_perror() have a valid errno value.
+ (modified anno() to leave errno alone), etc.
+ Re-fixed the -X option. This time for sure...
+ re-modified the msg stuff. flushed anno() completely
+ Modified the directory stuff so it should work on sysV boxes
+ added ftime() to getdate.y
+ Fixed un_quote_string() so it won't wedge on \" Also fixed
+ \ddd (like \123, etc)
+ More fixes to tar.texinfo
+
+ * Version 1.03 --- Fixed buffer.c so 'tar tzf NON_EXISTENT_FILE'
+ returns an error message instead of hanging forever.
+ More fixes to tar.texinfo.
+
+ * Version 1.02 --- Fixed tar.c so 'tar -h' and 'tar -v' don't cause
+ core dump. Also fixed the 'usage' message to be more up-to-date.
+ * diffarch.c [!MTIOCTOP]: Fixed so verify should compile.
+
+ * Version 1.01 --- Fixed typoes in tar.texinfo.
+ Fixed a bug in the #define for rmtcreat().
+ Fixed the -X option to not call realloc() of 0.
+
+ * Version 1.00 --- version.c added. -version option added.
+ Installed new version of the remote-tape library.
+ Added -help option.
+
+
+----- tests/ChangeLog -----
+
+1997-04-25 François Pinard <pinard@iro.umontreal.ca>
+
+ * Release 1.12.
+
+ * gzip.sh, ignfail.sh: Adjust to new delayed error exit message.
+
+ * Makefile.am (BUILT_SOURCES): Define as preset, so preset is
+ regenerated if configuration changes.
+
+ * Makefile.am (TESTS): Nevertheless include delete01.sh.
+ (POSTPONED_TESTS): Adjusted.
+ Reported by Andreas Schwab.
+
+ * delete02.sh: Mention f - explicitly, do not assume it, in case
+ $TAPE is defined or the default archive has been overridden.
+ Reported by Andreas Schwab.
+
+1997-04-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * after: Unredirect stdout and stderr before removing the files.
+ If redirections are to NFS files, removing them while they are
+ still opened may have strange effects, failing almost all tests.
+ Reported by Kaveh R. Ghazi.
+
+1997-04-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11q.
+
+ * extrac03.sh: New file.
+ * Makefile.am (TESTS): Adjusted.
+ Reported by Marc Boucher.
+
+ * preset.in (LC_MESSAGES): Clear value before tests.
+ Reported by Sven Verdoolaege.
+
+ * Makefile.am (INCLUDES): Adjust so config.h gets found.
+
+ * genfile.c (usage): Corrected.
+
+ * delete01.sh: New name for delete.sh.
+ * delete02.sh: New file.
+ * Makefile.am (TESTS): Adjusted.
+ Reported by Vince Del Vecchio.
+
+ * Makefile.am (POSTPONED_TESTS): To contain the --delete tests.
+ (TESTS): Adjusted.
+ (EXTRA_DIST): Include $(POSTPONED_TESTS). The purpose is getting
+ the tests distributed, but not executed. These flaky tests are to
+ be addressed only after 1.12 is released.
+
+1997-04-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * Makefile.am (AUTOMAKE_OPTIONS): Declare ../src/ansi2knr.
+ * (DEFS): New, for defining LOCALEDIR.
+ * (genfile.o): Deleted, will be implied from DEFS above.
+ Reported by Bruno Haible and Kaveh R. Ghazi.
+
+1997-04-17 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11p.
+
+ * genfile.c (usage): Add a program description.
+ (main): Output --version according to recent GNU standards.
+
+1997-04-15 François Pinard <pinard@iro.umontreal.ca>
+
+ * ignfail.sh: Ensure the test does not fail if run as super-user.
+ Reported by John David Anglin.
+
+1997-04-12 François Pinard <pinard@iro.umontreal.ca>
+
+ * genfile.c (pattern): Remove trailing comma for last enum item.
+ Reported by Bruno Haible.
+
+1997-04-11 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11o.
+
+1997-03-29 François Pinard <pinard@iro.umontreal.ca>
+
+ * ignfail.sh: New file.
+ * Makefile.am (TESTS): Adjusted.
+ Reported by Ralph Schleicher.
+
+1997-03-24 François Pinard <pinard@iro.umontreal.ca>
+
+ * genfile.c: Implement --pattern=default/zeros.
+
+1997-02-25 François Pinard <pinard@iro.umontreal.ca>
+
+ * old.sh: New file.
+ * Makefile.am (TESTS): Adjusted.
+ Reported by Daniel Trinkle.
+
+1997-01-21 François Pinard <pinard@iro.umontreal.ca>
+
+ * extrac01.sh: New name for extract.sh.
+ * extrac02.sh: New file.
+ * Makefile.am (TESTS): Adjusted.
+ Reported by Axel Boldt.
+
+1996-11-25 François Pinard <pinard@iro.umontreal.ca>
+
+ * genfile.c (usage): Typo in message.
+ Reported by Christian Kirsch.
+
+1996-11-22 François Pinard <pinard@iro.umontreal.ca>
+
+ * incremen.sh: New file.
+ Reported by Wolfram Wagner.
+
+ * append.sh, delete.sh: New files.
+ * Makefile.am (TESTS): Adjusted.
+ Reported by Andreas Schwab.
+
+ * before: Ensure .. on PATH, so genfile may be found.
+ * Makefile.am ($(TESTS)): Depend on genfile, waiting for Automake
+ to be adjusted to do the proper thing for parallel make.
+
+ * gzip.sh: New name for childerr.sh.
+ * extract.sh: New name for direxist.sh.
+ * volume.sh: New name for volcheck.sh.
+ * Makefile.am: Adjusted.
+
+ * All tests: Use set -e whenever appropriate. Use "" instead of
+ '' for out and err, so allowing us to use escaped newlines. In
+ case of multiple output in a single test, ensure separator lines.
+
+1996-11-06 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.13.
+
+ * childerr.sh, direxist.sh, volcheck.sh: Use sh, not bash.
+ Reported by John David Anglin.
+
+1996-09-20 François Pinard <pinard@iro.umontreal.ca>
+
+ * volcheck.sh: New.
+ * Makefile.am (TESTS): Adjusted.
+
+1996-09-19 François Pinard <pinard@iro.umontreal.ca>
+
+ * Prerelease 1.11.12.
+
+ * Makefile.am ($(TESTS)): Depend on preset.
+ * version.sh (PATH): Adjust for multi-line --version output.
+ * preset.in (LANG, LANGUAGE): Export them, so gzip does not
+ localise its own output.
+ (echo_n, echo_c): Define from the result of echo configuration.
+ * after: Handle echo with newline suppressed.
+
+1996-09-09 François Pinard <pinard@iro.umontreal.ca>
+
+ * childerr.sh, direxist.sh, before, after: New files.
+ * Makefile.am: Adjusted.
+
+1996-09-04 François Pinard <pinard@iro.umontreal.ca>
+
+ * ChangeLog, Makefile.am, pretest.in, version.sh: New files.
+ * checktar.sh, genfile.c: New files, moved from src/.
+
+ A regression test is an old dream for GNU tar.
+ Reported by Tom Tromey and Robert Bernstein.
diff --git a/contrib/tar/INSTALL b/contrib/tar/INSTALL
new file mode 100644
index 0000000..666ffd9
--- /dev/null
+++ b/contrib/tar/INSTALL
@@ -0,0 +1,226 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for variables by setting
+them in the environment. You can do that on the command line like this:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Environment Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it cannot guess the host type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS
+ KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the host
+platform (i.e., that on which the generated programs will eventually be
+run) with `--host=TYPE'. In this case, you should also specify the
+build platform with `--build=TYPE', because, in this case, it may not
+be possible to guess the build platform (it sometimes involves
+compiling and running simple test programs, and this can't be done if
+the compiler is a cross compiler).
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Environment Variables
+=====================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to configure. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/contrib/tar/NEWS b/contrib/tar/NEWS
new file mode 100644
index 0000000..0934859
--- /dev/null
+++ b/contrib/tar/NEWS
@@ -0,0 +1,512 @@
+GNU tar NEWS - User visible changes.
+
+version 1.13.25 - Paul Eggert, 2001-09-26
+
+* Bug fixes.
+
+version 1.13.24 - Paul Eggert, 2001-09-22
+
+* New option --overwrite-dir.
+* Fixes for buffer overrun, porting, and copyright notice problems.
+
+version 1.13.23 - Paul Eggert, 2001-09-13
+
+* Bug, porting, and copyright notice fixes.
+
+version 1.13.22 - Paul Eggert, 2001-08-29
+
+* Bug fixes.
+
+version 1.13.21 - Paul Eggert, 2001-08-28
+
+* Porting and copyright notice fixes.
+
+version 1.13.20 - Paul Eggert, 2001-08-27
+
+* Some bugs were fixed:
+ - security problems
+ - hard links to symbolic links
+
+* New option --recursion (the default) that is the inverse of --no-recursion.
+
+* New options --anchored, --ignore-case, --wildcards,
+ --wildcards-match-slash, and their negations (e.g., --no-anchored).
+ Along with --recursion and --no-recursion, these options control how
+ exclude patterns are interpreted.
+
+* The default interpretation of exclude patterns is now --no-anchored
+ --no-ignore-case --recursion --wildcards --wildcards-match-slash.
+ This is a quiet change to the semantics of --exclude. The previous
+ semantics were a failed attempt at backward compatibility but it
+ became clear that the semantics were puzzling and did not satisfy
+ everybody. Rather than continue to try to revive that dead horse we
+ thought it better to substitute cleaner semantics, with options so
+ that you can change the behavior more to your liking.
+
+* New message translations for Indonesian and Turkish.
+ The translation for Korean has been withdrawn due to encoding errors.
+ It will be reissued once those are fixed.
+
+version 1.13.19 - Paul Eggert, 2001-01-13
+
+* The -I option has been withdrawn, as it was buggy and confusing.
+ Eventually it is planned to be reintroduced, with the same meaning as -T.
+
+* With an option like -N DATE, if DATE starts with "/" or ".", it is taken
+ to be a file name; the last-modified time of that file is used as the date.
+
+version 1.13.18 - Paul Eggert, 2000-10-29
+
+* Some security problems have been fixed. `tar -x' now modifies only
+ files under the working directory, unless you also specify an unsafe
+ option like --absolute-names or --overwrite.
+
+* The short name of the --bzip option has been changed to -j,
+ and -I is now an alias for -T, for compatibility with Solaris tar.
+
+* The manual is now distributed under the GNU Free Documentation License.
+
+* The new environment variable TAR_OPTIONS holds default command-line options.
+
+* The --no-recursion option now affects extraction too.
+
+* The wording in some diagnostics has been changed slightly.
+
+* Snapshot files now record whether each file was accessed via NFS.
+ The new file format is upward- and downward-compatible with the old.
+
+* New language supported: da.
+
+* Compilation by traditional (K&R) C compilers is no longer supported.
+ If you still use such a compiler, please use GCC instead.
+
+* This version of tar works best with GNU gzip test version 1.3 or later.
+ Please see <ftp://alpha.gnu.org/gnu/gzip/>.
+
+* `tar --delete -f -' now works again.
+
+version 1.13.17 - Paul Eggert, 2000-01-07.
+
+* `tar --delete -f -' is no longer allowed; it was too buggy.
+* Diagnostic messages have been made more regular and consistent.
+
+version 1.13.16 - Paul Eggert, 1999-12-13.
+
+* By default, tar now refuses to overwrite an existing file when
+ extracting files from an archive; instead, it removes the file
+ before extracting it. If the existing file is a symbolic link, the
+ link is removed and not the pointed-to file. There is one
+ exception: existing nonempty directories are not removed, nor are
+ their ownerships or permissions extracted. This fixes some
+ longstanding security problems.
+
+ The new --overwrite option enables the old default behavior.
+
+ For regular files, tar implements this change by using the O_EXCL
+ option of `open' to ensure that it creates the file; if this fails, it
+ removes the file and tries again. This is similar to the behavior of
+ the --unlink-first option, but it is faster in the common case of
+ extracting a new directory.
+
+* By default, tar now ignores file names containing a component of `..'
+ when extracting, and warns about such file names when creating an archive.
+ To enable the old behavior, use the -P or --absolute-names option.
+
+* Tar now handles file names with multibyte encodings (e.g. UTF-8, Shift-JIS)
+ correctly. It relies on the mbrtowc function to handle multibytes.
+
+* The file generated by -g or --listed-incremental now uses a format
+ that is independent of locale, so that users need not worry about
+ locale when restoring a backup. This is needed for proper support
+ of multibyte characters. Old-format files can still be read, and
+ older versions of GNU tar can read new-format files, unless member
+ names have multibyte chars.
+
+* Many diagnostics have been changed slightly, so that file names are
+ now output unambiguously. File names in diagnostics now are either
+ `quoted like this' (in the default C locale) or are followed by
+ colon, newline, or space, depending on context. Unprintable
+ characters are escaped with a C-like backslash conventions.
+ Terminating characters (e.g. close-quote, colon, newline)
+ are also escaped as needed.
+
+* tar now ignores socket files when creating an archive.
+ Previously tar archived sockets as fifos, which caused problems.
+
+version 1.13.15 - Paul Eggert, 1999-12-03.
+
+* If a file's ctime changes when being archived, report an error.
+ Previously tar looked at mtime, which missed some errors.
+
+version 1.13.14 - Paul Eggert, 1999-11-07.
+
+* New translations ja, pt_BR.
+* New options --help and --version for rmt.
+* Ignore Solaris door files when creating an archive.
+
+version 1.13.13 - Paul Eggert, 1999-10-11.
+
+* Invalid headers in tar files now elicit errors, not just warnings.
+* `tar --version' output conforms to the latest GNU coding standards.
+* If you specify an invalid date, `tar' now substitutes (time_t) -1.
+* `configure --with-dmalloc' is no longer available.
+
+version 1.13.12 - Paul Eggert, 1999-09-24.
+
+* `tar' now supports hard links to symbolic links.
+
+* New options --no-same-owner, --no-same-permissions.
+
+* --total now also outputs a human-readable size, and a throughput value.
+
+* `tar' now uses two's-complement base-256 when outputting header
+ values that are out of the range of the standard unsigned base-8
+ format. This affects archive members with negative or huge time
+ stamps or uids, and archive members 8 GB or larger. The new tar
+ archives cannot be read by traditional tar, or by older versions of
+ GNU tar. Use the --old-archive option to revert to the old
+ behavior, which uses unportable representations for negative values,
+ and which rejects large files.
+
+* On 32-bit hosts, `tar' now assumes that an incoming time stamp T in
+ the range 2**31 <= T < 2**32 represents the negative time (T -
+ 2**32). This behavior is nonstandard and is not portable to 64-bit
+ time_t hosts, so `tar' issues a warning.
+
+* `tar' no longer gives up extracting immediately upon discovering
+ that an archive contains garbage at the end. It attempts to extract
+ as many files as possible from the good data before the garbage.
+
+* A read error now causes a nonzero exit status, not just a warning.
+
+* Some diagnostics have been reworded for consistency.
+
+
+version 1.13.11 - Paul Eggert, 1999-08-23.
+
+* The short name of the --bzip option has been changed to -I,
+ for compatibility with paxutils.
+
+* -T /dev/null now matches nothing; previously, it matched anything
+ if no explicit operands were given.
+
+* The `--' option now works the same as with other GNU utilities;
+ it causes later operands to be interpreted as file names, not options,
+ even if they begin with `-'.
+
+* For the --newer and --after-date options, the table of time zone
+ abbreviations like `EST' has been updated to match current practice.
+ Also, local time abbreviations are now recognized, even if they are
+ not in tar's hardwired table. Remember, though, that you should use
+ numeric UTC offsets like `-0500' instead of abbreviations like
+ `EST', as abbreviations are not standardized and are ambiguous.
+
+
+version 1.13.10 - Paul Eggert, 1999-08-20.
+
+* `tar' now uses signed base-64 when outputting header values that are
+ out of the range of the standard unsigned base-8 format. [This
+ change was superseded in 1.13.12, described above.]
+
+
+version 1.13.9 - Paul Eggert, 1999-08-18.
+
+* `tar' now writes two zero blocks at end-of-archive instead of just one.
+ POSIX.1 requires this, and some other `tar' implementations check for it.
+
+* `tar' no longer silently accepts a block containing nonzero checksum bytes
+ as a zero block.
+
+* `tar' now reads buggy tar files that have a null byte at the start of a
+ numeric header field.
+
+
+version 1.13.8 - Paul Eggert, 1999-08-16.
+
+* For compatibility with traditional `tar', intermediate directories
+ created automatically by root are no longer given the uid and gid of
+ the original file or directory.
+
+
+version 1.13.7 - Paul Eggert, 1999-08-14.
+
+* --listed-incremental and --newer are now incompatible options.
+
+* When creating an archive, leading `./' is no longer stripped,
+ to match traditional tar's behavior (and simplify the documentation).
+
+* --diff without --absolute-names no longer falls back on absolute names.
+
+
+version 1.13.6 - Paul Eggert, 1999-08-11.
+
+* An --exclude pattern containing / now excludes a file only if it matches an
+ initial prefix of the file name; a pattern without / continues to
+ exclude a file if it matches any file name component.
+
+* The protocol for talking to rmt has been extended slightly.
+ Open flags are now communicated in symbolic format as well as numeric.
+ The symbolic format (e.g. "O_WRONLY|O_CREAT|O_TRUNC") is for portability
+ when rmt is operating on a different operating system from tar.
+ The numeric format is retained, and rmt uses it if symbolic format is absent,
+ for backward compatibility with older versions of tar and rmt.
+
+* When writing GNU tar format headers, tar now uses signed base-64
+ for values that cannot be represented in unsigned octal.
+ This supports larger files (2**66 - 1 bytes instead of 2**33 - 1 bytes),
+ larger uids, negative time stamps, etc.
+
+* When extracting files with unknown ownership, tar now looks up the
+ uid and gid "nobody" on hosts whose headers do not define UID_NOBODY
+ and GID_NOBODY, and falls back on uid/gid -2 if there is no "nobody".
+
+* tar -t --numeric-owner now prints numeric uids and gids, not symbolic.
+
+* New option -y or --bzip2 for bzip2 compression, by popular request.
+
+
+version 1.13.5 - Paul Eggert, 1999-07-20.
+
+* Do the delayed updates of file metadata even after a fatal error.
+
+
+version 1.13.4 - Paul Eggert, 1999-07-20.
+
+* Do not chmod unless we are root or the -p option was given;
+ this matches historical practice.
+
+
+version 1.13.3 - Paul Eggert, 1999-07-16.
+
+* A path name is excluded if any of its file name components matches an
+ excluded pattern, even if the path name was specified on the command line.
+ Also see 1.13.6 for later changes in this area.
+
+
+version 1.13.2 - Paul Eggert, 1999-07-14.
+
+* Bug reporting address changed to <bug-tar@gnu.org>.
+
+
+version 1.13.1 - Paul Eggert, 1999-07-12.
+
+* Bug fixes only.
+
+version 1.13 - Paul Eggert, 1999-07-08.
+
+* Support for large files, e.g. files larger than 2 GB on many 32-bit hosts.
+ Also, support for larger uids, device ids, etc.
+* Many bug fixes and porting fixes.
+* This release is only for fixes. A more ambitious test release,
+ with new features, is available as part of the paxutils. Please see:
+ ftp://alpha.gnu.org/gnu/paxutils/
+ The fixes in this release are intended to be merged with paxutils
+ at some point, but they haven't been merged yet.
+* An interim GNU tar alpha had new --bzip2 and --ending-file options,
+ but they have been removed to maintain compatibility with paxutils.
+ Please try --use=bzip2 instead of --bzip2.
+
+Version 1.12 - François Pinard, 1997-04.
+
+Sensitive matters
+* Use shell globbing patterns for --label, instead of regular expressions.
+* Do not quote anymore internally over the quoting done by the shell.
+
+Output for humans
+* Offer internationalization capabilities of most recent GNU gettext.
+* Messages available in many more languages, thanks to all translators!
+* Usage of ISO 8601 dates in listings, instead of local American dates.
+* More normalization and cleanup in error messages.
+
+Creation
+* For helping using tar with find, offer a --no-recursion option.
+* Implement --numeric-owner for ignoring symbolic names at create time.
+* New --owner, --group --mode options, still preliminary.
+* Recognize creating an archive on /dev/null, so Amanda works faster.
+* Object to the creation of an empty archive (like in `tar cf FILE').
+* Barely start implementing --posix and POSIXLY_CORRECT.
+
+Extraction
+* Make a better job at restoring file and directory attributes.
+* Automatically attempt deleting existing files when in the way.
+* Option --unlink-first (-U) removes most files prior to extraction.
+* Option --recursive-unlink removes non-empty directories when in the way.
+* Option --numeric-owner ignores owner/group names, it uses UID/GID instead.
+* Use global umask when creating missing intermediate directories.
+* When symlinks are not available, extract symbolic links as hard links.
+* Diagnose extraction of contiguous files as regular files.
+* New --backup, --suffix and --version-control options.
+
+Various changes
+* Better support of huge archives with --tape-length and --totals.
+* Rename option --read-full-blocks (-B) to --read-full-records (-B).
+* Rename option --block-size (-b) to --blocking-factor (-b).
+* Rename option --record-number (-R) to --block-number (-R).
+* With --block-number (-R), report null blocks and end of file.
+* Implement --record-size for introducing a size in bytes.
+* Delete --block-compress option and rather decide it automatically.
+* Rename option --modification-time to --touch.
+
+Many bugs are squashed, while others still run free.
+
+Version 1.11.8 - François Pinard, 1995-06.
+
+* Messages available in French, German, Portuguese and Swedish.
+* The distribution provides a rudimentary Texinfo manual.
+* The device defaults to stdin/stdout, unless overridden by the installer.
+* Option --sparse (-S) should work on more systems.
+* Option --rsh-command may select an alternative remote shell program.
+
+Most changes are internal, and should yield better portability.
+
+Version 1.11.2 - Michael Bushnell, 1993-03.
+
+* Changes in backup scripts: cleaned up considerably; notices error
+conditions better over rsh; DUMP_REMIND_SCRIPT is now an option in
+backup-specs; new file dump-remind is an example of a
+DUMP_REMIND_SCRIPT.
+
+* Superfluous "Reading dirname" was a bug; fixed.
+
+* Incompatibility problems with a bug on Solaris are fixed.
+
+* New option --gzip (aliases are --ungzip and -z); calls gzip instead
+of compress. Also, --use-compress-program lets you specify any
+compress program. --compress-block is renamed --block-compress and
+now requires one of the three compression options to be specified.
+
+* Several error messages are cleaned up.
+
+* Directory owners are now set properly when running as root.
+
+* Provide DUMP_REMIND_SCRIPT in backup-specs as a possible option
+for --info-script.
+
+* Behave better with broken rmt servers.
+
+* Dump scripts no longer use --atime-preserve; this causes a nasty probem.
+
+* Several Makefile cleanups.
+
+Version 1.11.1 - Michael Bushnell, 1992-09.
+
+* Many bug fixes.
+
+Version 1.11 - Michael Bushnell, 1992-09.
+Version 1.10.16 - 1992-07.
+Version 1.10.15 - 1992-06.
+Version 1.10.14 - 1992-05.
+Version 1.10.13 - 1992-01.
+
+* Many bug fixes.
+
+* Now uses GNU standard configure, generated by Autoconf.
+
+* Long options now use `--'; use of `+' is deprecated and support
+for it will eventually be removed.
+
+* New option --null causes filenames read by -T to be
+null-terminated, and causes -C to be ignored.
+
+* New option --remove-files deletes files (but not directories)
+after they are added to the archive.
+
+* New option --ignore-failed-read prevents read-errors from affecting
+the exit status.
+
+* New option --checkpoint prints occasional messages as the tape
+is being read or written.
+
+* New option --show-omitted-dirs prints the names of directories
+omitted from the archive.
+
+* Some tape drives which use a non-standard method of indicating
+end-of-tape now work correctly with multi-tape archives.
+
+* --volno-file: Read the volume number used in prompting the user
+(but not in recording volume ID's on the archive) from a file.
+
+* When using --multi-volume, you can now give multiple -f arguments;
+the various tape drives will get used in sequence and then wrap
+around to the beginning.
+
+* Remote archive names no longer have to be in /dev: any file with a
+`:' is interpreted as remote. If new option --force-local is given,
+then even archive files with a `:' are considered local.
+
+* New option --atime-preserve restores (if possible) atimes to
+their original values after dumping the file.
+
+* No longer does tar confusingly dump "." when you don't tell it
+what to dump.
+
+* When extracting directories, tar now correctly restores their
+modification and access times.
+
+* Longnames support is redone differently--long name info directly
+precedes the long-named file or link in the archive, so you no
+longer have to wait for the extract to hit the end of the tape for
+long names to work.
+
+Version 1.10 - Michael Bushnell, 1991-07.
+
+* Filename to -G is optional. -C works right. Names +newer and
++newer-mtime work right.
+
+* -g is now +incremental, -G is now +listed-incremental.
+
+* Sparse files now work correctly.
+
+* +volume is now called +label.
+
+* +exclude now takes a filename argument, and +exclude-from does
+what +exclude used to do.
+
+* Exit status is now correct.
+
+* +totals keeps track of total I/O and prints it when tar exits.
+
+* When using +label with +extract, the label is now a regexp.
+
+* New option +tape-length (-L) does multi-volume handling like BSD
+dump: you tell tar how big the tape is and it will prompt at that
+point instead of waiting for a write error.
+
+* New backup scripts level-0 and level-1 which might be useful
+to people. They use a file "backup-specs" for information, and
+shouldn't need local modification. These are what we use to do
+all our backups at the FSF.
+
+Version 1.09 - Jay Fenlason, 1990-10.
+Version 1.08 - Jay Fenlason, 1990-01.
+Versions 1.07 back to 1.00 by Jay Fenlason.
+
+* See ChangeLog for more details.
+
+
+
+Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free
+Software Foundation, Inc.
+
+This file is part of GNU tar.
+
+GNU tar is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU tar 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 tar; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+
+
+
+Local Variables:
+coding: iso-latin-1
+End:
diff --git a/contrib/tar/PORTS b/contrib/tar/PORTS
new file mode 100644
index 0000000..787f6ca
--- /dev/null
+++ b/contrib/tar/PORTS
@@ -0,0 +1,157 @@
+* Ports of GNU tar and other tars -*- outline -*-
+
+ Please write bug-tar@gnu.org if you are aware of various ports of GNU tar
+ to non-GNU and non-Unix systems not listed here, or for corrections.
+ Please provide the goal system, a complete and stable URL, the maintainer
+ name and address, the tar version used as a base, and your comments.
+
+.* Copyright notice
+
+ Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+
+ This file is part of GNU tar.
+
+ GNU tar is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU tar is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU tar; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+.* GNU/Linux and Unix
+
+. + Star <ftp://ftp.fokus.gmd.de/pub/unix/star> is a tape archiver
+ similar to tar.
+
+.* Amiga
+
+. + ftp://ftp.wustl.edu/systems/amiga/aminet/util/arc/GNUtar-1.11.8.lha
+ maintained by Enrico Forestieri <enrico@com.unipr.it>
+ Based on tar 1.11.8.
+
+. + ftp://ftp.ninemoons.com/pub/ade/current/amiga-bin/tar-1.11.8-bin.lha
+ maintained by the ADE group <fnf@fishpond.ninemoons.com>
+ Based on tar 1.11.8, needs ixemul.library.
+
+. + ftp://ftp.wustl.edu/systems/amiga/aminet/util/arc/gnutar.lha
+ maintained by <mscheler@wuarchive.wustl.edu>
+
+.* DEC alpha (NT)
+
+. + ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
+ maintained by Drew Bliss & Geoff Voelker
+
+.* DEC VAX (VMS)
+
+. + http://www.lp.se/free/vmstar/
+ maintained by Richard Levitte <levitte@lp.se>
+ This is not GNU tar, but a separate implementation.
+
+. + maintained by William Bader <william@nscs.fast.net>
+ For V4.7. Based on an old PDtar. Requires compatible shared libraries
+ to run V5 or V6 executables.
+
+.* IBM/PC (DV/X)
+
+. + ftp://qdeck.com/ (?)
+ maintained by David Ronis <ronis@gibbs.chem.mcgill.ca>
+ For Desqview/X. Everything works besides compression. Copy of hacked
+ sources available, some of DV/X's programmer's library also needed.
+
+.* IBM/PC (MSDOS)
+
+. + http://www.simtel.net/simtel.net/
+ http://www.leo.org/pub/comp/platforms/pc/gnuish (Germany)
+ ftp://ftp.simtel.net/simtelnet/gnu
+ ftp://ftp.leo.org/pub/comp/platforms/pc/gnuish
+ maintained by Darrel Hankerson <hankedr@mail.auburn.edu>
+ You get many GNU tools, not only `tar'. The GNUish project is described
+ in `gnuish_t.htm'.
+
+. + The DJGPP development tools also include some `tar' utilities.
+
+. + ftp://ftp.mcs.com/mcsnet.users/les/dos-gnutar/
+ maintained by Leslie Mikesell <les@mcs.net>
+ Based on tar 1.11.2. Support for SCSI (via ASPI) and network (rsh over
+ packet driver). No support for win95 long file names.
+
+. + ftp://ftp.wu-wien.ac.at:pub/src/PCmisc/aspi-tar/*
+ maintained by Christoph Splittgerber <chris@orion.sdata.de>
+ Based on tar 1.10. Support for SCSI (via ASPI).
+
+. + ftp://wuarchive (?)
+ Several DOS version based on PDtar. John Gilmore <gnu@toad.com> says
+ he has copies of several vintages saved.
+
+. + ftp://ftp.cdrom.com/.14/languages/ada/toolkit/msdos/gtar/gtar.exe
+ ftp://ftp.cdrom.com/.14/languages/ada/toolkit/msdos/gtar/gtar.taz
+ ftp://ftp.cdrom.com/.14/languages/ada/toolkit/msdos/gtar/gtar.zip
+
+. + ftp://ftp.cdrom.com/.4/os2/archiver/tar.zip
+ Based on PDtar.
+
+. + ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
+ maintained by Drew Bliss & Geoff Voelker
+ GNU tar for NT (intel and Alpha platforms).
+
+. + ftp://garbo.uwasa.fi/pc/unix/untgz095.zip
+ maintained by Tillmann Steinbrecher <tst@darmstadt.netsurf.de>
+ The `untgz' program is a fast .tar or .tar.gz (.tgz) extractor.
+
+. + http://people.darmstadt.netsurf.de/tst/tar.htm
+ maintained by Tillmann Steinbrecher <tst@darmstadt.netsurf.de>
+ This is not a `tar' port, but an index of them.
+
+.* IBM/PC (OS/2)
+
+. + http://www.leo.org/pub/comp/os/os2/leo/gnu/archiver/gtar254.zip
+ http://www.leo.org/pub/comp/os/os2/leo/gnu/archiver/gtak254.zip
+ maintained by Andreas Kaiser <Andreas.Kaiser@stuttgart.netsurf.de>
+ Version 2.54. Based on tar 1.10. The second archive contains SCSI
+ drivers (DAT streamers notably) and rmt-type programs.
+
+. + ftp://garbo.uwasa.fi/pc/unix/untgz095.zip
+ maintained by Tillmann Steinbrecher <tst@darmstadt.netsurf.de>
+ The `untgz' program is a fast .tar or .tar.gz (.tgz) extractor.
+
+.* IBM/PC (Win32: Windows 95, NT 3.5 or NT 4.0)
+
+. + ftp://ftp.cygnus.com:~ftp/pub/sac/win32/usersrc/*
+ maintained by Cygnus
+ GNU-Win32 B17.1 distribution. Download all files, `cat' them together,
+ and `untar' the result. You get many GNU tools, not only `tar'.
+ Based on tar 1.11.2.
+
+. + ftp://ftp.cdrom.com/.20/windows/archiver/tar.zip
+ maintained by Drew Bliss & Geoff Voelker
+ GNU tar for NT (intel and Alpha platforms).
+
+. + ftp://garbo.uwasa.fi/pc/unix/untgz095.zip
+ maintained by Tillmann Steinbrecher <tst@darmstadt.netsurf.de>
+ The `untgz' program is a fast .tar or .tar.gz (.tgz) extractor.
+
+.* IBM/PC (Windows 3.1)
+
+. + ftp://ftp.mcs.com/mcsnet.users/les/win-gnutar/
+ maintained by Leslie Mikesell <les@mcs.net>
+ Support for network (rsh over winsock). No support for win95 long
+ file names.
+
+. + ftp://ftp.gamesdomain.ru/.1/os/windows/programr/tar.zip
+ Based on GNU tar 1.11.2.
+
+.* Macintosh
+
+. + There is a tar in Stuffit Expander which is available many places and
+ comes with MacOS. It creates some spurious files but works on average.
+
+. + There is an excellent GNU tar bundled in Tenon MachTen, but it does not
+ seem to be available separately.
diff --git a/contrib/tar/README b/contrib/tar/README
new file mode 100644
index 0000000..5970df8
--- /dev/null
+++ b/contrib/tar/README
@@ -0,0 +1,196 @@
+README for GNU tar
+
+ Copyright 1990, 1991, 1992, 1994, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ This file is part of GNU tar.
+
+ GNU tar is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU tar 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 tar; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+
+Please glance through *all* sections of this
+`README' file before starting configuration. Also make sure you read files
+`ABOUT-NLS' and `INSTALL' if you are not familiar with them already.
+
+If you got the `tar' distribution in `shar' format, time stamps ought to be
+properly restored; do not ignore such complaints at `unshar' time.
+
+GNU `tar' saves many files together into a single tape or disk
+archive, and can restore individual files from the archive. It includes
+multivolume support, the ability to archive sparse files, automatic archive
+compression/decompression, remote archives and special features that allow
+`tar' to be used for incremental and full backups. This distribution
+also includes `rmt', the remote tape server. The `mt' tape drive control
+program is in the GNU `cpio' distribution.
+
+GNU `tar' is derived from John Gilmore's public domain `tar'.
+
+See file `ABOUT-NLS' for how to customize this program to your language.
+See file `COPYING' for copying conditions.
+See file `INSTALL' for compilation and installation instructions.
+See file `PORTS' for various ports of GNU tar to non-Unix systems.
+See file `NEWS' for a list of major changes in the current release.
+See file `THANKS' for a list of contributors.
+
+Besides those configure options documented in files `INSTALL' and
+`ABOUT-NLS', an extra option may be accepted after `./configure':
+
+* `--disable-largefile' omits support for large files, even if the
+operating system supports large files. Typically, large files are
+those larger on 2 GB on a 32-bit host.
+
+The default archive device is now `stdin' on read and `stdout' on write.
+The installer can still override this by presetting `DEFAULT_ARCHIVE'
+in the environment before configuring (the behavior of `-[0-7]' or
+`-[0-7]lmh' options in `tar' are then derived automatically). Similarly,
+`DEFAULT_BLOCKING' can be preset to something else than 20.
+
+For comprehensive modifications to GNU tar, you might need tools beyond
+those used in simple installations. Fully install GNU m4 1.4 first,
+and only then, Autoconf 2.13 or later. Install Perl, then Automake
+1.4 or later. You might need Bison 1.28 or later, and GNU tar itself.
+All are available on GNU archive sites, like in
+ftp://ftp.gnu.org/pub/gnu/.
+
+Send bug reports to `bug-tar@gnu.org'. (Beware, old-timers: it is
+`@gnu', not `@prep'; and not `bug-gnu-utils' anymore.) A bug report is
+an adequate description of the problem: your input, what you expected,
+what you got, and why this is wrong. Diffs are welcome, but they only
+describe a solution, from which the problem might be uneasy to infer.
+If needed, submit actual data files with your report. Small data files
+are preferred. Big files may sometimes be necessary, but do not send them
+to the report address; rather take special arrangement with the maintainer.
+
+Your feedback will help us to make a better and more portable package.
+Consider documentation errors as bugs, and report them as such. If you
+develop anything pertaining to `tar' or have suggestions, let us know
+and share your findings by writing to <bug-tar@gnu.org>.
+
+
+Installation hints
+------------------
+
+Here are a few hints which might help installing `tar' on some systems.
+
+* gzip and bzip2.
+
+GNU tar uses the gzip and bzip2 programs to read and write compressed
+archives. If you don't have these programs already, you need to
+install them. Their sources can be found at:
+
+ftp://ftp.gnu.org/gnu/gzip/
+http://sourceware.cygnus.com/bzip2/
+
+If you see the following symptoms:
+
+ $ tar -xzf file.tar.gz
+ gzip: stdin: decompression OK, trailing garbage ignored
+ tar: Child returned status 2
+
+then you have encountered a gzip incompatibility that should be fixed
+in gzip test version 1.3, which as of this writing is available at
+<ftp://alpha.gnu.org/gnu/gzip/>. You can work around the
+incompatibility by using a shell command like
+ `gzip -d <file.tar.gz | tar -xzf -'.
+
+* Solaris issues.
+
+GNU tar exercises many features that can cause problems with older GCC
+versions. In particular, GCC 2.8.1 (sparc, -O1 or -O2) is known to
+miscompile GNU tar. No compiler-related problems have been reported
+when using GCC 2.95.2 or later.
+
+Recent versions of Solaris tar sport a new -E option to generate
+extended headers in an undocumented format. GNU tar does not
+understand these headers.
+
+* Static linking.
+
+Some platform will, by default, prepare a smaller `tar' executable
+which depends on shared libraries. Since GNU `tar' may be used for
+system-level backups and disaster recovery, installers might prefer to
+force static linking, making a bigger `tar' executable maybe, but able to
+work standalone, in situations where shared libraries are not available.
+The way to achieve static linking varies between systems. Set LDFLAGS
+to a value from the table below, before configuration (see `INSTALL').
+
+ Platform Compiler LDFLAGS
+
+ (any) Gnu C -static
+ AIX (vendor) -bnso -bI:/lib/syscalls.exp
+ HPUX (vendor) -Wl,-a,archive
+ IRIX (vendor) -non_shared
+ OSF (vendor) -non_shared
+ SCO 3.2v5 (vendor) -dn
+ Solaris (vendor) -Bstatic
+ SunOS (vendor) -Bstatic
+
+* Failed tests `ignfail.sh' or `incremen.sh'.
+
+In an NFS environment, lack of synchronization between machine clocks
+might create difficulties to any tool comparing dates and file time stamps,
+like `tar' in incremental dumps. This has been a recurrent problem with
+GNU Make for the last few years. We would like a general solution.
+
+* BSD compatibility matters.
+
+Set LIBS to `-lbsd' before configuration (see `INSTALL') if the linker
+complains about `bsd_ioctl' (Slackware). Also set CPPFLAGS to
+`-I/usr/include/bsd' if <sgtty.h> is not found (Slackware).
+
+* OPENStep 4.2 swap files
+
+Tar cannot read the file /private/vm/swapfile.front (even as root).
+This file is not a real file, but some kind of uncompressed view of
+the real compressed swap file; there is no reason to back it up, so
+the simplest workaround is to avoid tarring this file.
+
+
+Special topics
+--------------
+
+Here are a few special matters about GNU `tar', not related to build
+matters. See previous section for such.
+
+* File attributes.
+
+About *security*, it is probable that future releases of `tar' will have
+some behavior changed. There are many pending suggestions to choose from.
+Today, extracting an archive not being `root', `tar' will restore suid/sgid
+bits on files but owned by the extracting user. `root' automatically gets
+a lot of special privileges, `-p' might later become required to get them.
+
+GNU `tar' does not properly restore symlink attributes. Various systems
+implement flavors of symbolic links showing different behavior and
+properties. We did not successfully sorted all these out yet. Currently,
+the `lchown' call will be used if available, but that's all.
+
+* POSIX compliance.
+
+GNU `tar' implements an early draft of the POSIX 1003.1 `ustar' standard
+which is different from the final standard. This will be progressively
+corrected over the incoming few years. Don't be mislead by the mere
+existence of the --posix option. Later releases will become able to
+read truly POSIX archives, and also to produce them under option. (Also,
+if you look at the internals, don't take the GNU extensions you see for
+granted, as they are planned to change.) GNU tar 2.0 will produce POSIX
+archives by default, but there is a long way before we get there.
+
+* What's next?
+
+In the future we will try to release tar-1.14 as soon as possible and
+start merging with paxutils afterwards. We'll also try to rewrite
+some parts of the documentation after paxutils has been merged.
diff --git a/contrib/tar/README-alpha b/contrib/tar/README-alpha
new file mode 100644
index 0000000..3c45c19
--- /dev/null
+++ b/contrib/tar/README-alpha
@@ -0,0 +1,242 @@
+This is a test release of GNU tar.
+
+Please send comments and problem reports to <bug-tar@gnu.org>.
+
+ Copyright 2001 Free Software Foundation, Inc.
+
+ This file is part of GNU tar.
+
+ GNU tar is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU tar 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 tar; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+This release was built with GNU automake 1.5 patched as follows:
+
+2001-09-24 Paul Eggert <eggert@twinsun.com>
+
+ * m4/header.m4 (_AM_Config_Header_Index): Remove.
+ (AM_CONFIG_HEADER): Don't use it. It wasn't working, and was
+ causing needless rebuilds.
+
+2001-09-14 Paul Eggert <eggert@twinsun.com>
+
+ * lib/am/distdir.am (REMOVE_DISTDIR):
+ New macro. Do not change permission of non-directories.
+ (distdir, dist, dist-bzip2, dist-tarZ, dist-shar, dist-zip, dist-all,
+ distcheck): Use it.
+
+===================================================================
+RCS file: lib/am/distdir.am,v
+retrieving revision 1.5
+retrieving revision 1.5.0.1
+diff -pu -r1.5 -r1.5.0.1
+--- lib/am/distdir.am 2001/07/14 20:12:52 1.5
++++ lib/am/distdir.am 2001/09/15 05:12:18 1.5.0.1
+@@ -29,6 +29,11 @@ else !%?TOPDIR_P%
+ ?DISTDIR?distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+ endif !%?TOPDIR_P%
+
++REMOVE_DISTDIR = \
++ { test ! -d $(distdir) \
++ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
++ && rm -fr $(distdir); }; }
++
+ distdir: $(DISTFILES)
+ ##
+ ## For Gnits users, this is pretty handy. Look at 15 lines
+@@ -47,7 +52,7 @@ endif %?TOPDIR_P%
+ ## Only for the top dir.
+ ##
+ if %?TOPDIR_P%
+- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
++ $(REMOVE_DISTDIR)
+ mkdir $(distdir)
+ endif %?TOPDIR_P%
+ ##
+@@ -168,13 +173,13 @@ GZIP_ENV = --best
+ .PHONY: dist
+ dist: distdir
+ $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
++ $(REMOVE_DISTDIR)
+
+ if %?BZIP2%
+ .PHONY: dist-bzip2
+ dist-bzip2: distdir
+ $(AMTAR) chof - $(distdir) | bzip2 -9 -c >$(distdir).tar.bz2
+- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
++ $(REMOVE_DISTDIR)
+ endif %?BZIP2%
+
+
+@@ -182,7 +187,7 @@ if %?COMPRESS%
+ .PHONY: dist-tarZ
+ dist-tarZ: distdir
+ $(AMTAR) chof - $(distdir) | compress -c >$(distdir).tar.Z
+- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
++ $(REMOVE_DISTDIR)
+ endif %?COMPRESS%
+
+
+@@ -190,7 +195,7 @@ if %?SHAR%
+ .PHONY: dist-shar
+ dist-shar: distdir
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
++ $(REMOVE_DISTDIR)
+ endif %?SHAR%
+
+
+@@ -199,7 +204,7 @@ if %?ZIP%
+ dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
++ $(REMOVE_DISTDIR)
+ endif %?ZIP%
+
+ endif %?TOPDIR_P%
+@@ -223,7 +228,7 @@ dist-all: distdir
+ ?SHAR? shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ ?ZIP? -rm -f $(distdir).zip
+ ?ZIP? zip -rq $(distdir).zip $(distdir)
+- -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
++ $(REMOVE_DISTDIR)
+
+ endif %?TOPDIR_P%
+
+@@ -239,8 +244,7 @@ if %?TOPDIR_P%
+ # tarfile.
+ .PHONY: distcheck
+ distcheck: dist
+-## Make sure we can remove distdir before trying to remove it.
+- -chmod -R a+w $(distdir) > /dev/null 2>&1; rm -rf $(distdir)
++ $(REMOVE_DISTDIR)
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf -
+ ## Make the new source tree read-only. Distributions ought to work in
+ ## this case. However, make the top-level directory writable so we
+@@ -273,7 +277,7 @@ distcheck: dist
+ && (test `find . -type f -print | wc -l` -eq 0 \
+ || (echo "Error: files left after distclean" 1>&2; \
+ exit 1) )
+- -chmod -R a+w $(distdir) > /dev/null 2>&1; rm -rf $(distdir)
++ $(REMOVE_DISTDIR)
+ @echo "$(distdir).tar.gz is ready for distribution" | \
+ sed 'h;s/./=/g;p;x;p;x'
+ endif %?TOPDIR_P%
+===================================================================
+RCS file: m4/header.m4,v
+retrieving revision 1.5
+retrieving revision 1.5.0.1
+diff -pu -r1.5 -r1.5.0.1
+--- m4/header.m4 2001/07/21 05:27:26 1.5
++++ m4/header.m4 2001/09/24 18:29:30 1.5.0.1
+@@ -11,18 +11,16 @@ AC_PREREQ([2.12])
+
+ AC_DEFUN([AM_CONFIG_HEADER],
+ [ifdef([AC_FOREACH],dnl
+- [dnl init our file count if it isn't already
+- m4_ifndef([_AM_Config_Header_Index], m4_define([_AM_Config_Header_Index], [0]))
++ [
+ dnl prepare to store our destination file list for use in config.status
+ AC_FOREACH([_AM_File], [$1],
+ [m4_pushdef([_AM_Dest], m4_patsubst(_AM_File, [:.*]))
+- m4_define([_AM_Config_Header_Index], m4_incr(_AM_Config_Header_Index))
+ dnl and add it to the list of files AC keeps track of, along
+ dnl with our hook
+ AC_CONFIG_HEADERS(_AM_File,
+ dnl COMMANDS, [, INIT-CMDS]
+ [# update the timestamp
+-echo timestamp >"AS_ESCAPE(_AM_DIRNAME(]_AM_Dest[))/stamp-h]_AM_Config_Header_Index["
++echo timestamp >"AS_ESCAPE(_AM_DIRNAME(]_AM_Dest[))/stamp-h"
+ ][$2]m4_ifval([$3], [, [$3]]))dnl AC_CONFIG_HEADERS
+ m4_popdef([_AM_Dest])])],dnl
+ [AC_CONFIG_HEADER([$1])
+
+
+
+and with GNU autoconf 2.52 patched as follows:
+
+2001-09-15 Paul Eggert <eggert@twinsun.com>
+
+ Fix bug reported by Paul Townsend on AIX 4.3.3.0 with
+ CFLAGS=-O4 or CFLAGS=-O5. In that case, the linker has a
+ relaxed view of fatal errors, and AC_CHECK_LIB causes it to
+ include libraries even when they don't exist.
+
+ * acheaders.m4 (AC_HEADER_DIRENT): Use AC_SEARCH_LIBS, not
+ AC_CHECK_LIB, so that we don't use -ldir or -lx if we don't
+ need it.
+
+ * acspecific.m4 (AC_ISC_POSIX): Replace the old, crufty
+ version with the version used by fileutils 4.1, except use
+ AC_SEARCH_LIBS, not AC_CHECK_LIB, so that we don't use
+ -lcposix if we don't need it.
+
+===================================================================
+RCS file: acheaders.m4,v
+retrieving revision 2.52
+retrieving revision 2.52.0.1
+diff -pu -r2.52 -r2.52.0.1
+--- acheaders.m4 2001/07/03 14:19:09 2.52
++++ acheaders.m4 2001/09/16 02:53:51 2.52.0.1
+@@ -158,9 +158,9 @@ ac_header_dirent=$ac_hdr; break])
+ done
+ # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+ if test $ac_header_dirent = dirent.h; then
+- AC_CHECK_LIB(dir, opendir, LIBS="$LIBS -ldir")
++ AC_SEARCH_LIBS(opendir, dir)
+ else
+- AC_CHECK_LIB(x, opendir, LIBS="$LIBS -lx")
++ AC_SEARCH_LIBS(opendir, x)
+ fi
+ ])# AC_HEADER_DIRENT
+
+===================================================================
+RCS file: acspecific.m4,v
+retrieving revision 2.52
+retrieving revision 2.52.0.1
+diff -pu -r2.52 -r2.52.0.1
+--- acspecific.m4 2001/06/15 17:46:01 2.52
++++ acspecific.m4 2001/09/16 02:53:51 2.52.0.1
+@@ -993,28 +993,7 @@ fi
+ # AC_ISC_POSIX
+ # ------------
+ AC_DEFUN([AC_ISC_POSIX],
+-[AC_REQUIRE([AC_PROG_CC])dnl
+-AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
+-AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
+-AC_MSG_CHECKING([for POSIXized ISC])
+-if test -d /etc/conf/kconfig.d &&
+- grep _POSIX_VERSION [/usr/include/sys/unistd.h] >/dev/null 2>&1
+-then
+- AC_MSG_RESULT([yes])
+- ISC=yes # If later tests want to check for ISC.
+- AC_DEFINE(_POSIX_SOURCE, 1,
+- [Define if you need to in order for stat and other things to
+- work.])
+- if test "$GCC" = yes; then
+- CC="$CC -posix"
+- else
+- CC="$CC -Xp"
+- fi
+-else
+- AC_MSG_RESULT([no])
+- ISC=
+-fi
+-])# AC_ISC_POSIX
++[AC_SEARCH_LIBS(strerror, cposix)])
+
+
+ # AC_XENIX_DIR
diff --git a/contrib/tar/THANKS b/contrib/tar/THANKS
new file mode 100644
index 0000000..0673cca
--- /dev/null
+++ b/contrib/tar/THANKS
@@ -0,0 +1,493 @@
+GNU tar THANKS file
+
+Public domain tar was written by John Gilmore, with contributions
+from Henry Spencer, Fred Fish, Ian Darwin, Geoff Collyer, Stan Barber,
+Guy Harris, Dave Brower, Richard Todd, Michael Rendell, Stu Heiss and
+Rich $alz. The FSF version, named GNU tar, was derived from PDTAR by
+Jay Fenlason and Joy Kendall, and was maintained in turn by François
+Pinard and Paul Eggert.
+
+Many people further contributed to GNU tar by reporting problems,
+suggesting various improvements or submitting actual code. Here is a
+list of these people. Help me keep it complete and exempt of errors.
+See various ChangeLogs for a detailed description of contributions.
+
+Aage Robeck aagero@ifi.uio.no
+Akiko Matsushita matusita@sra.co.jp
+Alan Bawden Alan@lcs.mit.edu
+Alan Cox alan@cymru.net
+Alan Modra alan@spri.levels.unisa.edu.au
+Albert W. Dorrington awdorrin@ictest.delcoelect.com
+Alex Schmidt root@lacesm.ufsm.br
+Alexander Dupuy dupuy@smarts.com
+Alexander Lehmann alex@hal.rhein-main.de
+Alexander V. Lukyanov lav@long.yar.ru
+Alois Steindl Alois.Steindl+Mechanik@tuwien.ac.at
+Amos Yahil ayahil@sbast4.ess.sunysb.edu
+Anders Andersson andersa@docs.uu.se
+Anders Liljeborg anders@fysik4.kth.se
+Andre Novaes Cunha Andre.Cunha@br.global-one.net
+Andreas Degert ad@papyrus.hamburg.com
+Andreas Haumer andreas@vlsivie.tuwien.ac.at
+Andreas Jaeger aj@arthur.pfalz.de
+Andreas Koppenhoefer koppenh@trick.informatik.uni-stuttgart.de
+Andreas Reuter ar205@bonzo.geowiss.nat.tu-bs.de
+Andreas Schwab schwab@issan.informatik.uni-dortmund.de
+Andrew A. Ivanov ivanov@mics.msu.su
+Andrew J. Schorr schorr@ead.dsa.com
+Andrew Torda torda@igc.chem.ethz.ch
+Andrey A. Chernov ache@astral.msk.su
+Andy Gay andy@rdl.co.uk
+Antonio Jose Coutinho ajc@di.uminho.pt
+Ariel Faigon ariel@engr.sgi.com
+Arne Wichmann aw@math.uni-sb.de
+Arnold Robbins arnold@gnu.org
+Art Isbell aisbell@cubicsol.com
+Axel Boldt boldt@math.ucsb.edu
+Axel Habermann kiwi@belly.in-berlin.de
+Bdale Garbee bdale@gag.com
+Becki Kain beckers@josephus.furph.com
+Bela Lubkin filbo@armory.com
+Ben A. Mesander ben@piglet.cr.usgs.gov
+Benedikt Stockebrand benedikt@devnull.ruhr.de
+Bennett Todd bet@mordor.com
+Benny Holmgren benny@hgs.se
+Bernard Chen bern@cs.ucla.edu
+Bernard Derval derval@iro.umontreal.ca
+Bo Nygaard Bai bai@iesd.auc.dk
+Bob Kaehms kaehms@was.archive.org
+Bob Mende Pie mende@piecomputer.rutgers.edu
+Bradley A. Smith basmith@prometheus.chem.umn.edu
+Brendan Kehoe brendan@cygnus.com
+Brett Gaines gaines@saifr00.ateng.az.honeywell.com
+Brian Perkins bperkins@netspace.org
+Brian R. Smith brian@cygnus.com
+Bruce Evans bde@runx.oz.au
+Bruce Jerrick bruce@cse.ogi.edu
+Bruno Haible haible@ilog.fr
+Bryant Fujimoto fujimoto@denali.chem.washington.edu
+Burkhard Plache plache@krusty.optimax.ns.ca
+Calvin Cliff cliff@trifid.astro.ucla.edu
+Cameron Elliott cam@mvbms.mvbms.com
+Carl Streeter streeter@cae.wisc.edu
+Carsten Heyl heyl@nads.de
+Catrin Urbanneck cur@gppc.de
+Cesar Romani romani@ifm.uni-hamburg.de
+Chad Hurwitz churritz@cts.com
+Chance Reschke creschke@usra.edu
+Charles Fu ccwf@klab.caltech.edu
+Charles Lopes Charles.Lopes@infm.ulst.ac.uk
+Charles M. Hannum mycroft@gnu.org
+Chip Salzenberg tct!chip
+Chris Arthur csa@gnu.org
+Chris F.M. Verberne verberne@prl.philips.nl
+Chris G. Demetriou cgd@sun-lamp.cs.berkeley.edu
+Chris Hopps sycom.mi.org!ro-chp!chopps
+Chris Metcalf metcalf@catfish.lcs.mit.edu
+Chris Ransom chris@quests.com
+Christian Callsen Christian.Callsen@eng.sun.com
+Christian Kirsch ck@held.mind.de
+Christian Laubscher <christian.laubscher@tiscalinet.ch>
+Christian T. Dum ctd@mpe-garching.mpg.de
+Christian von Roques roques@pond.sub.org
+Christoph Litauer litauer@mailhost.uni-koblenz.de
+Christophe Colle colle@krtkg1.rug.ac.be
+Christophe Kalt Christophe.Kalt@kbcfp.com
+Christopher T. Johnson cjohnson@camelot.com
+Christopher Vickery vickery@ipc1.cs.qc.edu
+Claude Scarpelli claude@genethon.fr
+Claus Heine Claus_Heine@ac2.maus.de
+Cliff Krumvieda cliff@cs.cornell.edu
+Clinton Carr clint@netcom.com
+Conrad Hughes chughes@maths.tcd.ie
+Constantin Belous const@cris.net
+Coranth Gryphon gryphon@bur.visidyne.com
+Dale R. Worley worley@world.std.com
+Dale Wiles wiles@geordi.calspan.com
+Dan Bloch dan@transarc.com
+Dan Reish dreish@izzy.net
+Daniel Hagerty hag@gnu.org
+Daniel Quinlan quinlan@pathname.com
+Daniel R. Guilderson d.guilderson@ma30.bull.com
+Daniel S. Barclay daniel@compass-da.com
+Daniel Trinkle trinkle@cs.purdue.edu
+Danny R. Johnston danny@cs.weber.edu
+Dave Barr barr@math.psu.edu
+Dave Gentzel gentzel@nova.enet.dec.com
+Dave Gregorich dtg@ipac.caltech.edu
+David J. MacKenzie djm@uunet.uu.net
+David Johnson David.W.Johnson@colorado.edu
+David K. Drum ccdavid@mizzou1.missouri.edu
+David Lawyer david.lawyer@patchbay.com
+David Lemson lemson@uiuc.edu
+David Mansfield david@cobite.com
+David Martin dmartin@lerc.nasa.gov
+David N. Brown dbrown@lorien.physics.louisville.edu
+David Nugent davidn@blaze.net.au
+David Shaw david.shaw@alcatel.com.au
+David Steiner dsteiner@ispa.uni-osnabrueck.de
+David Taylor taylor@think.com
+Dean Gaudet dgaudet@watdragon.uwaterloo.ca
+Demizu Noritoshi nori-d@is.aist-nara.ac.jp
+Denis Fortin fortin@acm.org
+Dennis Pixton dennis@math.binghamton.edu
+Dick Streefland dicks@tasking.nl
+Dietmar Braun dietmar@highway.bertelsmann.de
+Dimitri Bougoulias opus@hol.gr
+Dimitris Fousekis dfousek@leon.nrcps.ariadne-t.gr
+Dirk Herr-Hoyman hoymand@gate.net
+Don Bennett dpb@netcom.com
+Donald B Gordon dbgordon@gnu.org
+Donald H. Locker dhl@spuf1d83.lcp.chrysler.com
+Douglas Scott doug@foxtrot.ccmrc.ucsb.edu
+Drew Sullivan drew@sni.ca
+Drew Trieger trieger@woodstock.abbott.com
+Dunstan Vavasour dev@cegelecproj.co.uk
+Ed Childs echilds@bgs.com
+Edgar Taube et@immd8.informatik.uni-erlangen.de
+Eduardo Kortright eduardo@cs.ua.edu
+Eduardo V. de Rivas eddie@asterion.com
+Edward Welbourne eddy@gen.cam.ac.uk
+Elmar Heeb heeb@itp.ethz.ch
+Elmer Fittery elmerf@ptw.com
+Eric Backus ericb@lsid.hp.com
+Eric Benson eb@amazon.com
+Eric M. Boehm Eric.M.Boehm@optimumtech.com
+Eric Norum eric@ee.ualberta.ca
+Erich Stefan Boleyn erich@uruk.org
+Erick Branderhorst branderh@debian.iaehv.nl
+Erik D. Frederick edf@deckard.mc.duke.edu
+Esa Karell karell@cs.helsinki.fi
+Ezra Peisach epeisach@mit.edu
+Fabio d'Alessi cars@civ.bio.unipd.it
+Frank Koenen koenfr@lidp.com
+Franz-Werner Gergen gergen@edvulx.mpi-stuttgart.mpg.de
+François Pinard pinard@iro.umontreal.ca
+Fritz Elfert fritz@fsun.triltsch.de
+George Chyu gschyu@ccgate.dp.beckman.com
+Gerben Wierda gerben@rna.indiv.nluug.nl
+Gerd Knorr kraxel@cs.tu-berlin.de
+Gerhard Poul gpoul@gnu.org
+Giorgio Signorini signo@chim.unifi.it
+Graham Whitted gbw@sgrail.com
+Grant McDorman grant@isgtec.com
+Greg Black gjb@gba.oz.au
+Greg Chung gchung@caip.rutgers.edu
+Greg Hudson ghudson@mit.edu
+Greg Maples greg@clari.net
+Greg McGary gkm@cstone.net
+Göran Uddeborg gvran@uddeborg.pp.se
+Hans Guerth 100664.3101@compuserve.com
+Harald König koenig@tat.physik.uni-tuebingen.de
+Harald Milz hm@seneca.ix.de
+Heiko Schinke mdqac@biochemtech.uni-halle.de
+Heiko Schlichting heiko@fu-berlin.de
+Henrik Bakman hb@csd.uu.se
+Hernan Prieto Schmidt hernan@pea.usp.br
+Hiroyuki Bessho bsh@grotto.iijnet.or.jp
+Holger Teutsch holger@hotbso.rhein-main.de
+Hugh Secker-Walker hugh@ear.mit.edu
+Hunyue Yau hunyue.yau@picksys.com
+Ian Jackson ijackson@gnu.org
+Ian Lance Taylor ian@cygnus.com
+Ian T. Zimmerman itz@crl.com
+Indra Singhal indra@synoptics.com
+J. Dean Brock brock@cs.unca.edu
+J.J. Bailey jjb@jagware.bcc.com
+J.T. Conklin jtc@cygnus.com
+James Crawford Ralston qralston+@pitt.edu
+James E. Carpenter jimc@zach1.tiac.net
+James H Caldwell Jr caldwell@cs.fsu.edu
+James Stevens James.Stevens@jrcs.co.uk
+James V. DI Toro III karrde@gats.hampton.va.us
+James W. McKelvey mckelvey@fafnir.com
+Jamie Zawinski jwz@lucid.com
+Jan Carlson janc@sni.ca
+Jan Djarv jan.djarv@mbox200.swipnet.se
+Janice Burton r06a165@bcc25.kodak.com
+Janne Snabb snabb@niksula.hut.fi
+Jason R. Mastaler jason@webmaster.net
+Jay Fenlason hack@gnu.org
+Jean-Michel Soenen soenen@lectra.fr
+Jean-Ph. Martin-Flatin syj@ecmwf.int
+Jean-loup Gailly jloup@chorus.fr
+Jeff Moskow jeff@rtr.com
+Jeff Prothero jsp@betz.biostr.washington.edu
+Jeff Siegel js@hornet.att.com
+Jeff Sorensen sorenj@alumni.rpi.edu
+Jeffrey Goldberg J.Goldberg@cranfield.ac.uk
+Jeffrey Mark Siskind Qobi@emba.uvm.edu
+Jeffrey W. Parker jwpkr@mcs.com
+Jens Henrik Jensen recjhl@mediator.uni-c.dk
+Jim Blandy jimb@totoro.cs.oberlin.edu
+Jim Clausing jac@postbox.acs.ohio-state.edu
+Jim Farrell jwf@platinum.com
+Jim Meyering meyering@na-net.ornl.gov
+Jim Murray jjm@jjm.com
+Joachim Holzfuss Joachim.Holzfuss@iap.physik.th-darmstadt.de
+Joachim Seelig joachim@kruemel.han.de
+Joe DeBattista joed@itsa.ucsf.edu
+Johan Vromans jvromans@squirrel.nl
+Johannes Helander jvh@cs.hut.fi
+John Clark jclark@gray.cscwc.pima.edu
+John D. Sybalsky John_D._Sybalsky.MV@envos.xerox.com
+John David Anglin dave@hiauly1.hia.nrc.ca
+John Gilmore gnu@toad.com
+John J. Szetela johns@angelo.amd.com
+John L. Chmielewski jlc@attmail.com
+John Oleynick juo@klinzhai.rutgers.edu
+John R. Vanderpool fish@daacdev1.stx.com
+John Rouillard rouilj@cs.umb.edu
+Jon Lewis jlewis@inorganic5.fdt.net
+Jonathan I. Kamens jik@cam.ov.com
+Jonathan N. Sherman sysjns@etacrs1.safb.af.mil
+Jonathan Thornburg thornbur@theory.physics.ubc.ca
+Joseph E. Sacco jsacco@ssl.com
+Joshua R. Poulson jrp@plaza.ds.adp.com
+Joutsiniemi Tommi Il tj75064@cs.tut.fi
+Joy Kendall jak8@world.std.com
+Judy Ricker jricker@gdstech.grumman.com
+Juha Sarlin juha@tds.kth.se
+Jurgen Botz jbotz@orixa.mtholyoke.edu
+Jürgen Lüters jlueters@t-online.de
+Jürgen Reiss reiss@psychologie.uni-wuerzburg.de
+Jyh-Shyang Wang erik@vsp.ee.nctu.edu.tw
+Jörg Weule weule@cs.uni-duesseldorf.de
+Jörgen Hägg Jorgen.Hagg@axis.se
+Kai Petzke wpp@marie.physik.tu-berlin.de
+Kai Schlichting kai@computel.com
+Karl Berry karl@cs.umb.edu
+Karl Heuer kwzh@gnu.org
+Karl Vogel vogelke@c-17igp.wpafb.af.mil
+Karlos Z. Smith kazen@viptx.net
+Karsten Thygesen karthy@kom.auc.dk
+Kaveh R. Ghazi ghazi@caip.rutgers.edu
+Keith Young youngk@astro.ocis.temple.edu
+Kelly Stephens kstephen@holli.com
+Ken Raeburn raeburn@cygnus.com
+Ken Steube steube@sdsc.edu
+Kevin D Quitt drs@netcom.com
+Kevin Dalley kevin@aimnet.com
+Kimball Collins kpc@ptolemy.arc.nasa.gov
+Kimmy Posey kimmyd@bnr.ca
+Koji Kishi kis@rqa.sony.co.jp
+Konno Hiroharu konno@pac.co.jp
+Kurt Jaeger pi@lf.net
+Larry Creech lcreech@lonestar.rcclub.org
+Larry Schwimmer rosebud@cyclone.stanford.edu
+Laurent Caillat-Vallet caillat@noe.lyon.cemagref.fr
+Laurent Sainte-Marthe smarthe@genethon.fr
+Les Mikesell les@mcs.com
+Loren J. Rittle rittle@comm.mot.com
+Loïc Prylli Loic.Prylli@lip.ens-lyon.fr
+Luke Mewburn lukem@connect.com.au
+Machael Stone mstone@cs.loyola.edu
+Manfred Weichel Manfred.Weichel@mch.sni.de
+Manuel Munier Manuel.Munier@loria.fr
+Marc Boucher marc@cam.org
+Marc Ewing marc@redhat.com
+Marcin Matuszewski marcin@frodo.nask.org.pl
+Marcus Daniels marcus@sysc.pdx.edu
+Mark Bynum bynum@cennas.nhmfl.gov
+Mark Clements mpc@mbsmm.com
+Mark Frost mfrost@ncd.com
+Mark Kollert Mark.Kollert@oi42.kwu.siemens.de
+Mark W. Eichin eichin@cygnus.com
+Markus Kuhn mskuhn@cip.informatik.uni-erlangen.de
+Martin Bellenberg sunsoft@ifm.uni-hamburg.de
+Martin Goik goik@HDM-Stuttgart.de
+Martin Mares mj@k332.feld.cvut.cz
+Marty Leisner leisner@eso.mc.xerox.com
+Massimo Dal Zotto dz@cs.unitn.it
+Mats Lofkvist d87-mal@nada.kth.se
+Matt Power mhpower@mit.edu
+Matthew J. D'Errico doc@deathstar.lis.cch.com
+Matti Aarnio mea@utu.fi
+Max Hailperin max@nic.gac.edu
+Maxime Taksar mmt@redbrick.com
+Melissa O'Neill oneill@cs.sfu.ca
+Melissa Weisshaus melissa@gnu.org
+Michael Dietrich mdt@is.in-berlin.de
+Michael Ellis bosun@aquarius.seaoar.uvic.ca
+Michael Giddings giddings@whitewater.chem.wisc.edu
+Michael Hayes michaelh@poroporo.chch.cri.nz
+Michael Helm mike@fionn.lbl.gov
+Michael Holmes mholmes@lccinc.com
+Michael Kaufman mkaufman@netgsi.com
+Michael Kubik mkubik@qitgsdv1.telecom.com.au
+Michael Lin mlin@lynx.com
+Michael Maass michael.maass@bk.bosch.de
+Michael Meissner meissner@cygnus.com
+Michael P Urban urban@cobra.jpl.nasa.gov
+Michael Schmidt michael@muc.de
+Michael Schwingen m.schwingen@stochastik.rwth-aachen.de
+Michael Smolsky fnsiguc@astro.weizmann.ac.il
+Mike Muuss mike@brl.mil
+Mike Nolan nolan@lpl.arizona.edu
+Mike Rogers mike@demon.net
+Mike Silano silano@newton.cs.jhu.edu
+Mike Walker M.D.Walker@larc.nasa.gov
+Milan Hodoscek milan@kihp6.ki.si
+Minh Tran-Le tranle@intellicorp.com
+Mitsuaki Masuhara masuhara@mcprv.mec.mei.co.jp
+Nate Eldredge nate@cs.hmc.edu
+Neil Faulks neil@dcs.kcl.ac.uk
+Neil Jerram nj104@cus.cam.ac.uk
+Nelson H.F. Beebe beebe@math.utah.edu
+Nick Barron nikb@cix.compulink.co.uk
+Noah Friedman friedman@gnu.org
+Noel Cragg noel@red-bean.com
+Norbert Kiesel norbert@rwthi3.informatik.rwth-aachen.de
+Olaf Schlueter olaf@toppoint.de
+Olaf Wucknitz owucknitz@hs.uni-hamburg.de
+Oliver Trepte oliver@fysik4.kth.se
+Olivier Roussel roussel@lifl.fr
+Oswald P. Backus IV backus@lks.csi.com
+Pascal Meheut pascal@cnam.cnam.fr
+Patrick Fulconis fulco@sig.uvsq.fr
+Patrick Timmons timmons@electech.polymtl.ca
+Paul Eggert eggert@twinsun.com
+Paul Kanz paul@icx.com
+Paul Mitchell P.Mitchell@surrey.ac.uk
+Paul Nevai pali+@osu.edu
+Paul Nordstrom 100067.3532@compuserve.com
+Paul O'Connor oconnorp@ul.ie
+Paul Siddall pauls@postman.essex.ac.uk
+Peder Chr. Norgaard pcn@tbit.dk
+Pekka Janhunen Pekka.Janhunen@fmi.fi
+Per Bojsen pb@delta.dk
+Per Foreby perf@efd.lth.se
+Pete Geenhuizen peteg@beno.css.gov
+Peter Carah pete@looneytunes.com
+Peter Fox fox@gec-mi-at.co.uk
+Peter Kutschera peter@zditr1.arcs.ac.at
+Peter Seebach seebs@taniemarie.solon.com
+Phil Hands phil@hands.com
+Philippe Defert defert@cern.ch
+Piercarlo Grandi piercarl@sabi.demon.co.uk
+Pierce Cantrell cantrell@ee.tamu.edu
+R. Kent Dybvig dyb@cadence.bloomington.in.us
+R. Scott Butler butler@prism.es.dupont.com
+Rainer Orth ro@TechFak.Uni-Bielefeld.DE
+Ralf Suckow suckow@contrib.de
+Ralph Schleicher rs@purple.ul.bawue.de
+Randy Bias randyb@edge.edge.net
+Ray Dassen jdassen@wi.leidenuniv.nl
+Reuben J. Ravago reuben@asti.dost.gov.ph
+Reuben Sumner rasumner@undergrad.math.uwaterloo.ca
+Ricardo Marek ricky@ornet.co.il
+Richard Deal deal@xi.cs.fsu.edu
+Richard J. Kettlewell rjk@greenend.org.uk
+Richard Lloyd R.K.Lloyd@csc.liv.ac.uk
+Richard O'Neill richard@nexus.vnus.bc.ca
+Richard Sims rbs@acs.bu.edu
+Richard Stallman rms@gnu.org
+Richard Westerik richardw@bssi.nl
+Rick Emerson rick@ssg.com
+Rob Parry rparry@hydrolab.arsusda.gov
+Robert Anthony Nader naderr@usa.net
+Robert Bernstein rocky@panix.com
+Robert E. Brown brown@bibliotech.com
+Robert Frey bobf@unix.advansys.com
+Robert Leslie rob@mars.org
+Robert Lipe robertl@arnet.com
+Robert McGraw mcgraw@sunspot.noao.edu
+Robert W. Kim robertwk@aixpdslib.seas.ucla.edu
+Robert Weiner robert@progplus.com
+Robert Weissenfels robert@hop.ping.de
+Rocky Giannini rocky@nova.umd.edu
+Rod Buchanan rod.buchanan@kratos.co.uk
+Rod Thompson rodt@synopsys.com
+Roderich Schupp roderich@syntec.m.eunet.de
+Rodney Brown RBrown@cocam.com.au
+Roland McGrath roland@gnu.org
+Roland Schemers III schemers@vela.acs.oakland.edu
+Rolf Niepraschk niepraschk@chbrb.berlin.ptb.de
+Roman Gollent roman@portal.stwing.upenn.edu
+Roman Czyborra czyborra@cs.tu-berlin.de
+Ron Guilmette rfg@netcom.com
+Roy Marantz marantz@nbcs.rutgers.edu
+Russ Evans e_gs18@ub.nmh.ac.uk
+Russell Cattelan cattelan@thebarn.com
+Ryutaro Susukita susukita@pn.scphys.kyoto-u.ac.jp
+Sam Richards sam@blueskyprod.com
+Sakai Kiyotaka ksakai@netwk.ntt-at.co.jp
+Santiago Vila Doncel sanvila@unex.es
+Sarah Quady squady@warp10.keck.hawaii.edu
+Saul Lubkin lubkin@cs.rochester.edu
+Scott Grosch garath@engin.umich.edu
+Scott Hunziker ksh@eskimo.com
+Scott J. Kramer sjk@graham.com
+Scott L. Burson gyro@zeta-soft.com
+Scott S. Bertilson scott@geom.umn.edu
+Serge Granik serge@euler.berkeley.edu
+Seth Robertson seth@ctr.columbia.edu
+Sherwood Botsford sherwood@space.ualberta.ca
+Simon Wright simon.j.wright@gecm.com
+Sisira Jayasinghe sisira.jayasinghe@sdrc.com
+Skip Montanaro skip@mojam.com http://www.musi-cal.com/~skip/
+Simon Wright simon@pogner.demon.co.uk
+Stefan Skoglund sp2stes1@ida.his.se
+Steffen Stempel stempel@ira.uka.de
+Stephen Gildea gildea@intouchsys.com
+Stephen J Bevan stephenb@harlequin.co.uk
+Stephen Saroff saroff@msc.edu
+Stuart Kemp skemp@bmc.com
+Stuart Poulin stuart@indsys.com
+Sven Verdoolaege skimo@breughel.ufsia.ac.be
+Sylvain Rougier un@grolier.fr
+Tarang Kumar Patel mombasa@ptolemy.arc.nasa.gov
+Ted Rule Ted_Rule@flextech.co.uk
+The King elvis@gnu.org
+Thomas Bushnell n/BSG thomas@gnu.org
+Thomas König Thomas.Koenig@ciw.uni-karlsruhe.de
+Thomas Krebs krebs@faps.uni-erlangen.de
+Thomas M. Browder Jr. browder@use1.eglin.af.mil
+Thomas Priesner priesner@flo.sh.bosch.de
+Thomas Waas waas@echild.aiss.de
+Thorbjxrn Willoch willoch@oslo.sgp.slb.com
+Tilman Schmidt ts@gb1.sema.de
+Tim Bradshaw tfb@aiai.ed.ac.uk
+Tim Lashua tim@winternet.com
+Tim Magill tim@tct.com
+Tim P. Starrin noid@cyborg.larc.nasa.gov
+Tim Ramsey tar@ksu.ksu.edu
+Tim Rylance tkr@puffball.demon.co.uk
+Tim Towers tzt@uniplex.co.uk
+Timothy J. Lee timlee@netcom.com
+Timothy Fossum fossum@cs.uwp.edu
+Tito Flagella tito@di.unipi.it
+Tom Popovitch tpop@informix.com
+Tom Quinn trq@astro.washington.edu
+Tom Tromey tromey@drip.colorado.edu
+Tor Lillqvist tml@hemuli.tte.vtt.fi
+Torbjorn Granlund tege@sics.se
+Torkel Hasle torkel@bibsyst.no
+Toshiaki Nishi toshi@sss.osa.sharp.co.jp
+Travis L. Priest T.L.Priest@larc.nasa.gov
+Troy Rudolph rudtr01@cai.com
+Tsutomu Yamada tsutomu@sra.co.jp
+Ulrich Drepper drepper@gnu.org
+Van Snyder vsnyder@math.jpl.nasa.gov
+Vic Abell abe@cc.purdue.edu
+Victor J. Griswold vgris@aironet.com
+Ville Herva v@iki.fi
+Vince Del Vecchio vdelvecc@inmet.com
+W. Phillip Moore wpm@morgan.com
+Warner Losh imp@boulder.parcplace.com
+Warren Dodge warrend@sptekwv3.wv.tek.com
+Wayne Christopher wayne@icemcfd.com
+Werner Almesberger werner.almesberger@lrc.di.epfl.ch
+William Bader william@nscs.fast.net
+William J. Eaton wje@hoffman.rstnu.bcm.tmc.edu
+William Kucharski kucharsk@netcom.com
+Wlodzimierz Jan Martin wjm@pg.gda.pl
+Wolfgang Rupprecht wolfgang@wsrcc.com
+Wolfram Gloger Wolfram.Gloger@dent.med.uni-muenchen.de
+Wolfram Wagner ww@mpi-sb.mpg.de
+Yasushi Suzudo SGR00413@niftyserve.or.jp
+Yu-Min Liang min@taz.ho.att.com
+
+Local Variables:
+coding: iso-latin-1
+End:
diff --git a/contrib/tar/TODO b/contrib/tar/TODO
new file mode 100644
index 0000000..40f7759
--- /dev/null
+++ b/contrib/tar/TODO
@@ -0,0 +1,5 @@
+From: Roesinger Eric <ROESINGE@tce.com>
+Date: Sat, 28 Jul 2001 18:43:43 -0500
+
+It would be useful to be able to use '--remove-files' with '--diff',
+to remove all files that compare successfully, when verifying a backup.
diff --git a/contrib/tar/doc/fdl.texi b/contrib/tar/doc/fdl.texi
new file mode 100644
index 0000000..361f90f
--- /dev/null
+++ b/contrib/tar/doc/fdl.texi
@@ -0,0 +1,403 @@
+
+@node GNU Free Documentation License
+@appendixsec GNU Free Documentation License
+
+@cindex FDL, GNU Free Documentation License
+@center Version 1.1, March 2000
+
+@display
+Copyright @copyright{} 2000 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@enumerate 0
+@item
+PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+written document @dfn{free} in the sense of freedom: to assure everyone
+the effective freedom to copy and redistribute it, with or without
+modifying it, either commercially or noncommercially. Secondarily,
+this License preserves for the author and publisher a way to get
+credit for their work, while not being considered responsible for
+modifications made by others.
+
+This License is a kind of ``copyleft'', which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+
+@item
+APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work that contains a
+notice placed by the copyright holder saying it can be distributed
+under the terms of this License. The ``Document'', below, refers to any
+such manual or work. Any member of the public is a licensee, and is
+addressed as ``you''.
+
+A ``Modified Version'' of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A ``Secondary Section'' is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall subject
+(or to related matters) and contains nothing that could fall directly
+within that overall subject. (For example, if the Document is in part a
+textbook of mathematics, a Secondary Section may not explain any
+mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The ``Invariant Sections'' are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.
+
+The ``Cover Texts'' are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.
+
+A ``Transparent'' copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, whose contents can be viewed and edited directly and
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup has been designed to thwart or discourage
+subsequent modification by readers is not Transparent. A copy that is
+not ``Transparent'' is called ``Opaque''.
+
+Examples of suitable formats for Transparent copies include plain
+@sc{ascii} without markup, Texinfo input format, La@TeX{} input format,
+@acronym{SGML} or @acronym{XML} using a publicly available
+@acronym{DTD}, and standard-conforming simple @acronym{HTML} designed
+for human modification. Opaque formats include PostScript,
+@acronym{PDF}, proprietary formats that can be read and edited only by
+proprietary word processors, @acronym{SGML} or @acronym{XML} for which
+the @acronym{DTD} and/or processing tools are not generally available,
+and the machine-generated @acronym{HTML} produced by some word
+processors for output purposes only.
+
+The ``Title Page'' means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, ``Title Page'' means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+@item
+VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+@item
+COPYING IN QUANTITY
+
+If you publish printed copies of the Document numbering more than 100,
+and the Document's license notice requires Cover Texts, you must enclose
+the copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a publicly-accessible computer-network location containing a complete
+Transparent copy of the Document, free of added material, which the
+general network-using public has access to download anonymously at no
+charge using public-standard network protocols. If you use the latter
+option, you must take reasonably prudent steps, when you begin
+distribution of Opaque copies in quantity, to ensure that this
+Transparent copy will remain thus accessible at the stated location
+until at least one year after the last time you distribute an Opaque
+copy (directly or through your agents or retailers) of that edition to
+the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+@item
+MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+
+@enumerate A
+@item
+Use in the Title Page (and on the covers, if any) a title distinct
+from that of the Document, and from those of previous versions
+(which should, if there were any, be listed in the History section
+of the Document). You may use the same title as a previous version
+if the original publisher of that version gives permission.
+
+@item
+List on the Title Page, as authors, one or more persons or entities
+responsible for authorship of the modifications in the Modified
+Version, together with at least five of the principal authors of the
+Document (all of its principal authors, if it has less than five).
+
+@item
+State on the Title page the name of the publisher of the
+Modified Version, as the publisher.
+
+@item
+Preserve all the copyright notices of the Document.
+
+@item
+Add an appropriate copyright notice for your modifications
+adjacent to the other copyright notices.
+
+@item
+Include, immediately after the copyright notices, a license notice
+giving the public permission to use the Modified Version under the
+terms of this License, in the form shown in the Addendum below.
+
+@item
+Preserve in that license notice the full lists of Invariant Sections
+and required Cover Texts given in the Document's license notice.
+
+@item
+Include an unaltered copy of this License.
+
+@item
+Preserve the section entitled ``History'', and its title, and add to
+it an item stating at least the title, year, new authors, and
+publisher of the Modified Version as given on the Title Page. If
+there is no section entitled ``History'' in the Document, create one
+stating the title, year, authors, and publisher of the Document as
+given on its Title Page, then add an item describing the Modified
+Version as stated in the previous sentence.
+
+@item
+Preserve the network location, if any, given in the Document for
+public access to a Transparent copy of the Document, and likewise
+the network locations given in the Document for previous versions
+it was based on. These may be placed in the ``History'' section.
+You may omit a network location for a work that was published at
+least four years before the Document itself, or if the original
+publisher of the version it refers to gives permission.
+
+@item
+In any section entitled ``Acknowledgments'' or ``Dedications'',
+preserve the section's title, and preserve in the section all the
+substance and tone of each of the contributor acknowledgments
+and/or dedications given therein.
+
+@item
+Preserve all the Invariant Sections of the Document,
+unaltered in their text and in their titles. Section numbers
+or the equivalent are not considered part of the section titles.
+
+@item
+Delete any section entitled ``Endorsements''. Such a section
+may not be included in the Modified Version.
+
+@item
+Do not retitle any existing section as ``Endorsements''
+or to conflict in title with any Invariant Section.
+@end enumerate
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section entitled ``Endorsements'', provided it contains
+nothing but endorsements of your Modified Version by various
+parties---for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+@item
+COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections entitled ``History''
+in the various original documents, forming one section entitled
+``History''; likewise combine any sections entitled ``Acknowledgments'',
+and any sections entitled ``Dedications''. You must delete all sections
+entitled ``Endorsements.''
+
+@item
+COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+@item
+AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, does not as a whole count as a Modified Version
+of the Document, provided no compilation copyright is claimed for the
+compilation. Such a compilation is called an ``aggregate'', and this
+License does not apply to the other self-contained works thus compiled
+with the Document, on account of their being thus compiled, if they
+are not themselves derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one quarter
+of the entire aggregate, the Document's Cover Texts may be placed on
+covers that surround only the Document within the aggregate.
+Otherwise they must appear on covers around the whole aggregate.
+
+@item
+TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License provided that you also include the
+original English version of this License. In case of a disagreement
+between the translation and the original English version of this
+License, the original English version will prevail.
+
+@item
+TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License. Any other attempt to
+copy, modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License. However,
+parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+@item
+FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns. See
+@uref{http://www.gnu.org/copyleft/}.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License ``or any later version'' applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+@end enumerate
+
+@page
+@appendixsubsec ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+@smallexample
+@group
+ Copyright (C) @var{year} @var{your name}.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.1
+ or any later version published by the Free Software Foundation;
+ with the Invariant Sections being @var{list their titles}, with the
+ Front-Cover Texts being @var{list}, and with the Back-Cover Texts being @var{list}.
+ A copy of the license is included in the section entitled ``GNU
+ Free Documentation License''.
+@end group
+@end smallexample
+
+If you have no Invariant Sections, write ``with no Invariant Sections''
+instead of saying which ones are invariant. If you have no
+Front-Cover Texts, write ``no Front-Cover Texts'' instead of
+``Front-Cover Texts being @var{list}''; likewise for Back-Cover Texts.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
+
+@c Local Variables:
+@c ispell-local-pdict: "ispell-dict"
+@c End:
+
diff --git a/contrib/tar/doc/freemanuals.texi b/contrib/tar/doc/freemanuals.texi
new file mode 100644
index 0000000..25343f9
--- /dev/null
+++ b/contrib/tar/doc/freemanuals.texi
@@ -0,0 +1,89 @@
+@cindex free documentation
+
+The biggest deficiency in the free software community today is not in
+the software---it is the lack of good free documentation that we can
+include with the free software. Many of our most important
+programs do not come with free reference manuals and free introductory
+texts. Documentation is an essential part of any software package;
+when an important free software package does not come with a free
+manual and a free tutorial, that is a major gap. We have many such
+gaps today.
+
+Consider Perl, for instance. The tutorial manuals that people
+normally use are non-free. How did this come about? Because the
+authors of those manuals published them with restrictive terms---no
+copying, no modification, source files not available---which exclude
+them from the free software world.
+
+That wasn't the first time this sort of thing happened, and it was far
+from the last. Many times we have heard a GNU user eagerly describe a
+manual that he is writing, his intended contribution to the community,
+only to learn that he had ruined everything by signing a publication
+contract to make it non-free.
+
+Free documentation, like free software, is a matter of freedom, not
+price. The problem with the non-free manual is not that publishers
+charge a price for printed copies---that in itself is fine. (The Free
+Software Foundation sells printed copies of manuals, too.) The
+problem is the restrictions on the use of the manual. Free manuals
+are available in source code form, and give you permission to copy and
+modify. Non-free manuals do not allow this.
+
+The criteria of freedom for a free manual are roughly the same as for
+free software. Redistribution (including the normal kinds of
+commercial redistribution) must be permitted, so that the manual can
+accompany every copy of the program, both on-line and on paper.
+
+Permission for modification of the technical content is crucial too.
+When people modify the software, adding or changing features, if they
+are conscientious they will change the manual too---so they can
+provide accurate and clear documentation for the modified program. A
+manual that leaves you no choice but to write a new manual to document
+a changed version of the program is not really available to our
+community.
+
+Some kinds of limits on the way modification is handled are
+acceptable. For example, requirements to preserve the original
+author's copyright notice, the distribution terms, or the list of
+authors, are ok. It is also no problem to require modified versions
+to include notice that they were modified. Even entire sections that
+may not be deleted or changed are acceptable, as long as they deal
+with nontechnical topics (like this one). These kinds of restrictions
+are acceptable because they don't obstruct the community's normal use
+of the manual.
+
+However, it must be possible to modify all the @emph{technical}
+content of the manual, and then distribute the result in all the usual
+media, through all the usual channels. Otherwise, the restrictions
+obstruct the use of the manual, it is not free, and we need another
+manual to replace it.
+
+Please spread the word about this issue. Our community continues to
+lose manuals to proprietary publishing. If we spread the word that
+free software needs free reference manuals and free tutorials, perhaps
+the next person who wants to contribute by writing documentation will
+realize, before it is too late, that only free manuals contribute to
+the free software community.
+
+If you are writing documentation, please insist on publishing it under
+the GNU Free Documentation License or another free documentation
+license. Remember that this decision requires your approval---you
+don't have to let the publisher decide. Some commercial publishers
+will use a free license if you insist, but they will not propose the
+option; it is up to you to raise the issue and say firmly that this is
+what you want. If the publisher you are dealing with refuses, please
+try other publishers. If you're not sure whether a proposed license
+is free, write to @email{licensing@@gnu.org}.
+
+You can encourage commercial publishers to sell more free, copylefted
+manuals and tutorials by buying them, and particularly by buying
+copies from the publishers that paid for their writing or for major
+improvements. Meanwhile, try to avoid buying non-free documentation
+at all. Check the distribution terms of a manual before you buy it,
+and insist that whoever seeks your business must respect your freedom.
+Check the history of the book, and try reward the publishers that have
+paid or pay the authors to work on it.
+
+The Free Software Foundation maintains a list of free documentation
+published by other publishers, at
+@url{http://www.fsf.org/doc/other-free-books.html}.
diff --git a/contrib/tar/doc/getdate.texi b/contrib/tar/doc/getdate.texi
new file mode 100644
index 0000000..06f6031
--- /dev/null
+++ b/contrib/tar/doc/getdate.texi
@@ -0,0 +1,432 @@
+@node Date input formats
+@chapter Date input formats
+
+@c Copyright 1994, 1995, 1996, 1997, 1999, 2000, 2001 Free Software
+@c Foundation, Inc.
+
+@c Permission is granted to copy, distribute and/or modify this document
+@c under the terms of the GNU Free Documentation License, Version 1.1
+@c or any later version published by the Free Software Foundation;
+@c with no Invariant Sections, with no
+@c Front-Cover Texts, and with no Back-Cover Texts.
+@c A copy of the license is included in the section entitled ``GNU
+@c Free Documentation License''.
+
+@cindex date input formats
+@findex getdate
+
+First, a quote:
+
+@quotation
+Our units of temporal measurement, from seconds on up to months, are so
+complicated, asymmetrical and disjunctive so as to make coherent mental
+reckoning in time all but impossible. Indeed, had some tyrannical god
+contrived to enslave our minds to time, to make it all but impossible
+for us to escape subjection to sodden routines and unpleasant surprises,
+he could hardly have done better than handing down our present system.
+It is like a set of trapezoidal building blocks, with no vertical or
+horizontal surfaces, like a language in which the simplest thought
+demands ornate constructions, useless particles and lengthy
+circumlocutions. Unlike the more successful patterns of language and
+science, which enable us to face experience boldly or at least
+level-headedly, our system of temporal calculation silently and
+persistently encourages our terror of time.
+
+@dots{} It is as though architects had to measure length in feet, width
+in meters and height in ells; as though basic instruction manuals
+demanded a knowledge of five different languages. It is no wonder then
+that we often look into our own immediate past or future, last Tuesday
+or a week from Sunday, with feelings of helpless confusion. @dots{}
+
+--- Robert Grudin, @cite{Time and the Art of Living}.
+@end quotation
+
+This section describes the textual date representations that @sc{gnu}
+programs accept. These are the strings you, as a user, can supply as
+arguments to the various programs. The C interface (via the
+@code{getdate} function) is not described here.
+
+@cindex beginning of time, for @sc{posix}
+@cindex epoch, for @sc{posix}
+Although the date syntax here can represent any possible time since the
+year zero, computer integers often cannot represent such a wide range of
+time. On @sc{posix} systems, the clock starts at 1970-01-01 00:00:00
+@sc{utc}: @sc{posix} does not require support for times before the
+@sc{posix} Epoch and times far in the future. Traditional Unix systems
+have 32-bit signed @code{time_t} and can represent times from 1901-12-13
+20:45:52 through 2038-01-19 03:14:07 @sc{utc}. Systems with 64-bit
+signed @code{time_t} can represent all the times in the known
+lifetime of the universe.
+
+@menu
+* General date syntax:: Common rules.
+* Calendar date items:: 19 Dec 1994.
+* Time of day items:: 9:20pm.
+* Time zone items:: @sc{est}, @sc{pdt}, @sc{gmt}, ...
+* Day of week items:: Monday and others.
+* Relative items in date strings:: next tuesday, 2 years ago.
+* Pure numbers in date strings:: 19931219, 1440.
+* Authors of getdate:: Bellovin, Eggert, Salz, Berets, et al.
+@end menu
+
+
+@node General date syntax
+@section General date syntax
+
+@cindex general date syntax
+
+@cindex items in date strings
+A @dfn{date} is a string, possibly empty, containing many items
+separated by whitespace. The whitespace may be omitted when no
+ambiguity arises. The empty string means the beginning of today (i.e.,
+midnight). Order of the items is immaterial. A date string may contain
+many flavors of items:
+
+@itemize @bullet
+@item calendar date items
+@item time of the day items
+@item time zone items
+@item day of the week items
+@item relative items
+@item pure numbers.
+@end itemize
+
+@noindent We describe each of these item types in turn, below.
+
+@cindex numbers, written-out
+@cindex ordinal numbers
+@findex first @r{in date strings}
+@findex next @r{in date strings}
+@findex last @r{in date strings}
+A few numbers may be written out in words in most contexts. This is
+most useful for specifying day of the week items or relative items (see
+below). Here is the list: @samp{first} for 1, @samp{next} for 2,
+@samp{third} for 3, @samp{fourth} for 4, @samp{fifth} for 5,
+@samp{sixth} for 6, @samp{seventh} for 7, @samp{eighth} for 8,
+@samp{ninth} for 9, @samp{tenth} for 10, @samp{eleventh} for 11 and
+@samp{twelfth} for 12. Also, @samp{last} means exactly @math{-1}.
+
+@cindex months, written-out
+When a month is written this way, it is still considered to be written
+numerically, instead of being ``spelled in full''; this changes the
+allowed strings.
+
+@cindex language, in dates
+In the current implementation, only English is supported for words and
+abbreviations like @samp{AM}, @samp{DST}, @samp{EST}, @samp{first},
+@samp{January}, @samp{Sunday}, @samp{tomorrow}, and @samp{year}.
+
+@cindex language, in dates
+@cindex time zone item
+The output of @command{date} is not always acceptable as a date string,
+not only because of the language problem, but also because there is no
+standard meaning for time zone items like @samp{IST}. When using
+@command{date} to generate a date string intended to be parsed later,
+specify a date format that is independent of language and that does not
+use time zone items other than @samp{UTC} and @samp{Z}. Here are some
+ways to do this:
+
+@example
+$ LC_ALL=C TZ=UTC0 date
+Fri Dec 15 19:48:05 UTC 2000
+$ TZ=UTC0 date +"%Y-%m-%d %H:%M:%SZ"
+2000-12-15 19:48:05Z
+$ date --iso-8601=seconds # a GNU extension
+2000-12-15T11:48:05-0800
+$ date --rfc-822 # a GNU extension
+Fri, 15 Dec 2000 11:48:05 -0800
+$ date +"%Y-%m-%d %H:%M:%S %z" # %z is a GNU extension.
+2000-12-15 11:48:05 -0800
+@end example
+
+@cindex case, ignored in dates
+@cindex comments, in dates
+Alphabetic case is completely ignored in dates. Comments may be introduced
+between round parentheses, as long as included parentheses are properly
+nested. Hyphens not followed by a digit are currently ignored. Leading
+zeros on numbers are ignored.
+
+
+@node Calendar date items
+@section Calendar date items
+
+@cindex calendar date item
+
+A @dfn{calendar date item} specifies a day of the year. It is
+specified differently, depending on whether the month is specified
+numerically or literally. All these strings specify the same calendar date:
+
+@example
+1972-09-24 # @sc{iso} 8601.
+72-9-24 # Assume 19xx for 69 through 99,
+ # 20xx for 00 through 68.
+72-09-24 # Leading zeros are ignored.
+9/24/72 # Common U.S. writing.
+24 September 1972
+24 Sept 72 # September has a special abbreviation.
+24 Sep 72 # Three-letter abbreviations always allowed.
+Sep 24, 1972
+24-sep-72
+24sep72
+@end example
+
+The year can also be omitted. In this case, the last specified year is
+used, or the current year if none. For example:
+
+@example
+9/24
+sep 24
+@end example
+
+Here are the rules.
+
+@cindex @sc{iso} 8601 date format
+@cindex date format, @sc{iso} 8601
+For numeric months, the @sc{iso} 8601 format
+@samp{@var{year}-@var{month}-@var{day}} is allowed, where @var{year} is
+any positive number, @var{month} is a number between 01 and 12, and
+@var{day} is a number between 01 and 31. A leading zero must be present
+if a number is less than ten. If @var{year} is 68 or smaller, then 2000
+is added to it; otherwise, if @var{year} is less than 100,
+then 1900 is added to it. The construct
+@samp{@var{month}/@var{day}/@var{year}}, popular in the United States,
+is accepted. Also @samp{@var{month}/@var{day}}, omitting the year.
+
+@cindex month names in date strings
+@cindex abbreviations for months
+Literal months may be spelled out in full: @samp{January},
+@samp{February}, @samp{March}, @samp{April}, @samp{May}, @samp{June},
+@samp{July}, @samp{August}, @samp{September}, @samp{October},
+@samp{November} or @samp{December}. Literal months may be abbreviated
+to their first three letters, possibly followed by an abbreviating dot.
+It is also permitted to write @samp{Sept} instead of @samp{September}.
+
+When months are written literally, the calendar date may be given as any
+of the following:
+
+@example
+@var{day} @var{month} @var{year}
+@var{day} @var{month}
+@var{month} @var{day} @var{year}
+@var{day}-@var{month}-@var{year}
+@end example
+
+Or, omitting the year:
+
+@example
+@var{month} @var{day}
+@end example
+
+
+@node Time of day items
+@section Time of day items
+
+@cindex time of day item
+
+A @dfn{time of day item} in date strings specifies the time on a given
+day. Here are some examples, all of which represent the same time:
+
+@example
+20:02:0
+20:02
+8:02pm
+20:02-0500 # In @sc{est} (U.S. Eastern Standard Time).
+@end example
+
+More generally, the time of the day may be given as
+@samp{@var{hour}:@var{minute}:@var{second}}, where @var{hour} is
+a number between 0 and 23, @var{minute} is a number between 0 and
+59, and @var{second} is a number between 0 and 59. Alternatively,
+@samp{:@var{second}} can be omitted, in which case it is taken to
+be zero.
+
+@findex am @r{in date strings}
+@findex pm @r{in date strings}
+@findex midnight @r{in date strings}
+@findex noon @r{in date strings}
+If the time is followed by @samp{am} or @samp{pm} (or @samp{a.m.}
+or @samp{p.m.}), @var{hour} is restricted to run from 1 to 12, and
+@samp{:@var{minute}} may be omitted (taken to be zero). @samp{am}
+indicates the first half of the day, @samp{pm} indicates the second
+half of the day. In this notation, 12 is the predecessor of 1:
+midnight is @samp{12am} while noon is @samp{12pm}.
+(This is the zero-oriented interpretation of @samp{12am} and @samp{12pm},
+as opposed to the old tradition derived from Latin
+which uses @samp{12m} for noon and @samp{12pm} for midnight.)
+
+@cindex time zone correction
+@cindex minutes, time zone correction by
+The time may alternatively be followed by a time zone correction,
+expressed as @samp{@var{s}@var{hh}@var{mm}}, where @var{s} is @samp{+}
+or @samp{-}, @var{hh} is a number of zone hours and @var{mm} is a number
+of zone minutes. When a time zone correction is given this way, it
+forces interpretation of the time relative to
+Coordinated Universal Time (@sc{utc}), overriding any previous
+specification for the time zone or the local time zone. The @var{minute}
+part of the time of the day may not be elided when a time zone correction
+is used. This is the best way to specify a time zone correction by
+fractional parts of an hour.
+
+Either @samp{am}/@samp{pm} or a time zone correction may be specified,
+but not both.
+
+
+@node Time zone items
+@section Time zone items
+
+@cindex time zone item
+
+A @dfn{time zone item} specifies an international time zone, indicated
+by a small set of letters, e.g., @samp{UTC} or @samp{Z}
+for Coordinated Universal
+Time. Any included periods are ignored. By following a
+non-daylight-saving time zone by the string @samp{DST} in a separate
+word (that is, separated by some white space), the corresponding
+daylight saving time zone may be specified.
+
+Time zone items other than @samp{UTC} and @samp{Z}
+are obsolescent and are not recommended, because they
+are ambiguous; for example, @samp{EST} has a different meaning in
+Australia than in the United States. Instead, it's better to use
+unambiguous numeric time zone corrections like @samp{-0500}, as
+described in the previous section.
+
+
+@node Day of week items
+@section Day of week items
+
+@cindex day of week item
+
+The explicit mention of a day of the week will forward the date
+(only if necessary) to reach that day of the week in the future.
+
+Days of the week may be spelled out in full: @samp{Sunday},
+@samp{Monday}, @samp{Tuesday}, @samp{Wednesday}, @samp{Thursday},
+@samp{Friday} or @samp{Saturday}. Days may be abbreviated to their
+first three letters, optionally followed by a period. The special
+abbreviations @samp{Tues} for @samp{Tuesday}, @samp{Wednes} for
+@samp{Wednesday} and @samp{Thur} or @samp{Thurs} for @samp{Thursday} are
+also allowed.
+
+@findex next @var{day}
+@findex last @var{day}
+A number may precede a day of the week item to move forward
+supplementary weeks. It is best used in expression like @samp{third
+monday}. In this context, @samp{last @var{day}} or @samp{next
+@var{day}} is also acceptable; they move one week before or after
+the day that @var{day} by itself would represent.
+
+A comma following a day of the week item is ignored.
+
+
+@node Relative items in date strings
+@section Relative items in date strings
+
+@cindex relative items in date strings
+@cindex displacement of dates
+
+@dfn{Relative items} adjust a date (or the current date if none) forward
+or backward. The effects of relative items accumulate. Here are some
+examples:
+
+@example
+1 year
+1 year ago
+3 years
+2 days
+@end example
+
+@findex year @r{in date strings}
+@findex month @r{in date strings}
+@findex fortnight @r{in date strings}
+@findex week @r{in date strings}
+@findex day @r{in date strings}
+@findex hour @r{in date strings}
+@findex minute @r{in date strings}
+The unit of time displacement may be selected by the string @samp{year}
+or @samp{month} for moving by whole years or months. These are fuzzy
+units, as years and months are not all of equal duration. More precise
+units are @samp{fortnight} which is worth 14 days, @samp{week} worth 7
+days, @samp{day} worth 24 hours, @samp{hour} worth 60 minutes,
+@samp{minute} or @samp{min} worth 60 seconds, and @samp{second} or
+@samp{sec} worth one second. An @samp{s} suffix on these units is
+accepted and ignored.
+
+@findex ago @r{in date strings}
+The unit of time may be preceded by a multiplier, given as an optionally
+signed number. Unsigned numbers are taken as positively signed. No
+number at all implies 1 for a multiplier. Following a relative item by
+the string @samp{ago} is equivalent to preceding the unit by a
+multiplier with value @math{-1}.
+
+@findex day @r{in date strings}
+@findex tomorrow @r{in date strings}
+@findex yesterday @r{in date strings}
+The string @samp{tomorrow} is worth one day in the future (equivalent
+to @samp{day}), the string @samp{yesterday} is worth
+one day in the past (equivalent to @samp{day ago}).
+
+@findex now @r{in date strings}
+@findex today @r{in date strings}
+@findex this @r{in date strings}
+The strings @samp{now} or @samp{today} are relative items corresponding
+to zero-valued time displacement, these strings come from the fact
+a zero-valued time displacement represents the current time when not
+otherwise changed by previous items. They may be used to stress other
+items, like in @samp{12:00 today}. The string @samp{this} also has
+the meaning of a zero-valued time displacement, but is preferred in
+date strings like @samp{this thursday}.
+
+When a relative item causes the resulting date to cross a boundary
+where the clocks were adjusted, typically for daylight-saving time,
+the resulting date and time are adjusted accordingly.
+
+
+@node Pure numbers in date strings
+@section Pure numbers in date strings
+
+@cindex pure numbers in date strings
+
+The precise interpretation of a pure decimal number depends
+on the context in the date string.
+
+If the decimal number is of the form @var{yyyy}@var{mm}@var{dd} and no
+other calendar date item (@pxref{Calendar date items}) appears before it
+in the date string, then @var{yyyy} is read as the year, @var{mm} as the
+month number and @var{dd} as the day of the month, for the specified
+calendar date.
+
+If the decimal number is of the form @var{hh}@var{mm} and no other time
+of day item appears before it in the date string, then @var{hh} is read
+as the hour of the day and @var{mm} as the minute of the hour, for the
+specified time of the day. @var{mm} can also be omitted.
+
+If both a calendar date and a time of day appear to the left of a number
+in the date string, but no relative item, then the number overrides the
+year.
+
+
+@node Authors of getdate
+@section Authors of @code{getdate}
+
+@cindex authors of @code{getdate}
+
+@cindex Bellovin, Steven M.
+@cindex Salz, Rich
+@cindex Berets, Jim
+@cindex MacKenzie, David
+@cindex Meyering, Jim
+@cindex Eggert, Paul
+@code{getdate} was originally implemented by Steven M. Bellovin
+(@email{smb@@research.att.com}) while at the University of North Carolina
+at Chapel Hill. The code was later tweaked by a couple of people on
+Usenet, then completely overhauled by Rich $alz (@email{rsalz@@bbn.com})
+and Jim Berets (@email{jberets@@bbn.com}) in August, 1990. Various
+revisions for the @sc{gnu} system were made by David MacKenzie, Jim Meyering,
+Paul Eggert and others.
+
+@cindex Pinard, F.
+@cindex Berry, K.
+This chapter was originally produced by Fran@,{c}ois Pinard
+(@email{pinard@@iro.umontreal.ca}) from the @file{getdate.y} source code,
+and then edited by K.@: Berry (@email{kb@@cs.umb.edu}).
diff --git a/contrib/tar/doc/header.texi b/contrib/tar/doc/header.texi
new file mode 100644
index 0000000..c91fe7f
--- /dev/null
+++ b/contrib/tar/doc/header.texi
@@ -0,0 +1,235 @@
+/* GNU tar Archive Format description.
+
+ Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 2000, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* If OLDGNU_COMPATIBILITY is not zero, tar produces archives which, by
+ default, are readable by older versions of GNU tar. This can be
+ overriden by using --posix; in this case, POSIXLY_CORRECT in environment
+ may be set for enforcing stricter conformance. If OLDGNU_COMPATIBILITY
+ is zero or undefined, tar will eventually produces archives which, by
+ default, POSIX compatible; then either using --posix or defining
+ POSIXLY_CORRECT enforces stricter conformance.
+
+ This #define will disappear in a few years. FP, June 1995. */
+#define OLDGNU_COMPATIBILITY 1
+
+/* tar Header Block, from POSIX 1003.1-1990. */
+
+/* POSIX header. */
+
+struct posix_header
+@{ /* byte offset */
+ char name[100]; /* 0 */
+ char mode[8]; /* 100 */
+ char uid[8]; /* 108 */
+ char gid[8]; /* 116 */
+ char size[12]; /* 124 */
+ char mtime[12]; /* 136 */
+ char chksum[8]; /* 148 */
+ char typeflag; /* 156 */
+ char linkname[100]; /* 157 */
+ char magic[6]; /* 257 */
+ char version[2]; /* 263 */
+ char uname[32]; /* 265 */
+ char gname[32]; /* 297 */
+ char devmajor[8]; /* 329 */
+ char devminor[8]; /* 337 */
+ char prefix[155]; /* 345 */
+ /* 500 */
+@};
+
+#define TMAGIC "ustar" /* ustar and a null */
+#define TMAGLEN 6
+#define TVERSION "00" /* 00 and no null */
+#define TVERSLEN 2
+
+/* Values used in typeflag field. */
+#define REGTYPE '0' /* regular file */
+#define AREGTYPE '\0' /* regular file */
+#define LNKTYPE '1' /* link */
+#define SYMTYPE '2' /* reserved */
+#define CHRTYPE '3' /* character special */
+#define BLKTYPE '4' /* block special */
+#define DIRTYPE '5' /* directory */
+#define FIFOTYPE '6' /* FIFO special */
+#define CONTTYPE '7' /* reserved */
+
+/* Bits used in the mode field, values in octal. */
+#define TSUID 04000 /* set UID on execution */
+#define TSGID 02000 /* set GID on execution */
+#define TSVTX 01000 /* reserved */
+ /* file permissions */
+#define TUREAD 00400 /* read by owner */
+#define TUWRITE 00200 /* write by owner */
+#define TUEXEC 00100 /* execute/search by owner */
+#define TGREAD 00040 /* read by group */
+#define TGWRITE 00020 /* write by group */
+#define TGEXEC 00010 /* execute/search by group */
+#define TOREAD 00004 /* read by other */
+#define TOWRITE 00002 /* write by other */
+#define TOEXEC 00001 /* execute/search by other */
+
+/* tar Header Block, GNU extensions. */
+
+/* In GNU tar, SYMTYPE is for to symbolic links, and CONTTYPE is for
+ contiguous files, so maybe disobeying the `reserved' comment in POSIX
+ header description. I suspect these were meant to be used this way, and
+ should not have really been `reserved' in the published standards. */
+
+/* *BEWARE* *BEWARE* *BEWARE* that the following information is still
+ boiling, and may change. Even if the OLDGNU format description should be
+ accurate, the so-called GNU format is not yet fully decided. It is
+ surely meant to use only extensions allowed by POSIX, but the sketch
+ below repeats some ugliness from the OLDGNU format, which should rather
+ go away. Sparse files should be saved in such a way that they do *not*
+ require two passes at archive creation time. Huge files get some POSIX
+ fields to overflow, alternate solutions have to be sought for this. */
+
+/* Descriptor for a single file hole. */
+
+struct sparse
+@{ /* byte offset */
+ char offset[12]; /* 0 */
+ char numbytes[12]; /* 12 */
+ /* 24 */
+@};
+
+/* Sparse files are not supported in POSIX ustar format. For sparse files
+ with a POSIX header, a GNU extra header is provided which holds overall
+ sparse information and a few sparse descriptors. When an old GNU header
+ replaces both the POSIX header and the GNU extra header, it holds some
+ sparse descriptors too. Whether POSIX or not, if more sparse descriptors
+ are still needed, they are put into as many successive sparse headers as
+ necessary. The following constants tell how many sparse descriptors fit
+ in each kind of header able to hold them. */
+
+#define SPARSES_IN_EXTRA_HEADER 16
+#define SPARSES_IN_OLDGNU_HEADER 4
+#define SPARSES_IN_SPARSE_HEADER 21
+
+/* The GNU extra header contains some information GNU tar needs, but not
+ foreseen in POSIX header format. It is only used after a POSIX header
+ (and never with old GNU headers), and immediately follows this POSIX
+ header, when typeflag is a letter rather than a digit, so signaling a GNU
+ extension. */
+
+struct extra_header
+@{ /* byte offset */
+ char atime[12]; /* 0 */
+ char ctime[12]; /* 12 */
+ char offset[12]; /* 24 */
+ char realsize[12]; /* 36 */
+ char longnames[4]; /* 48 */
+ char unused_pad1[68]; /* 52 */
+ struct sparse sp[SPARSES_IN_EXTRA_HEADER];
+ /* 120 */
+ char isextended; /* 504 */
+ /* 505 */
+@};
+
+/* Extension header for sparse files, used immediately after the GNU extra
+ header, and used only if all sparse information cannot fit into that
+ extra header. There might even be many such extension headers, one after
+ the other, until all sparse information has been recorded. */
+
+struct sparse_header
+@{ /* byte offset */
+ struct sparse sp[SPARSES_IN_SPARSE_HEADER];
+ /* 0 */
+ char isextended; /* 504 */
+ /* 505 */
+@};
+
+/* The old GNU format header conflicts with POSIX format in such a way that
+ POSIX archives may fool old GNU tar's, and POSIX tar's might well be
+ fooled by old GNU tar archives. An old GNU format header uses the space
+ used by the prefix field in a POSIX header, and cumulates information
+ normally found in a GNU extra header. With an old GNU tar header, we
+ never see any POSIX header nor GNU extra header. Supplementary sparse
+ headers are allowed, however. */
+
+struct oldgnu_header
+@{ /* byte offset */
+ char unused_pad1[345]; /* 0 */
+ char atime[12]; /* 345 */
+ char ctime[12]; /* 357 */
+ char offset[12]; /* 369 */
+ char longnames[4]; /* 381 */
+ char unused_pad2; /* 385 */
+ struct sparse sp[SPARSES_IN_OLDGNU_HEADER];
+ /* 386 */
+ char isextended; /* 482 */
+ char realsize[12]; /* 483 */
+ /* 495 */
+@};
+
+/* OLDGNU_MAGIC uses both magic and version fields, which are contiguous.
+ Found in an archive, it indicates an old GNU header format, which will be
+ hopefully become obsolescent. With OLDGNU_MAGIC, uname and gname are
+ valid, though the header is not truly POSIX conforming. */
+#define OLDGNU_MAGIC "ustar " /* 7 chars and a null */
+
+/* The standards committee allows only capital A through capital Z for
+ user-defined expansion. */
+
+/* This is a dir entry that contains the names of files that were in the
+ dir at the time the dump was made. */
+#define GNUTYPE_DUMPDIR 'D'
+
+/* Identifies the *next* file on the tape as having a long linkname. */
+#define GNUTYPE_LONGLINK 'K'
+
+/* Identifies the *next* file on the tape as having a long name. */
+#define GNUTYPE_LONGNAME 'L'
+
+/* This is the continuation of a file that began on another volume. */
+#define GNUTYPE_MULTIVOL 'M'
+
+/* For storing filenames that do not fit into the main header. */
+#define GNUTYPE_NAMES 'N'
+
+/* This is for sparse files. */
+#define GNUTYPE_SPARSE 'S'
+
+/* This file is a tape/volume header. Ignore it on extraction. */
+#define GNUTYPE_VOLHDR 'V'
+
+/* tar Header Block, overall structure. */
+
+/* tar files are made in basic blocks of this size. */
+#define BLOCKSIZE 512
+
+enum archive_format
+@{
+ DEFAULT_FORMAT, /* format to be decided later */
+ V7_FORMAT, /* old V7 tar format */
+ OLDGNU_FORMAT, /* GNU format as per before tar 1.12 */
+ POSIX_FORMAT, /* restricted, pure POSIX format */
+ GNU_FORMAT /* POSIX format with GNU extensions */
+@};
+
+union block
+@{
+ char buffer[BLOCKSIZE];
+ struct posix_header header;
+ struct extra_header extra_header;
+ struct oldgnu_header oldgnu_header;
+ struct sparse_header sparse_header;
+@};
+
+/* End of Format description. */
diff --git a/contrib/tar/doc/tar.texi b/contrib/tar/doc/tar.texi
new file mode 100644
index 0000000..a3e9286e
--- /dev/null
+++ b/contrib/tar/doc/tar.texi
@@ -0,0 +1,8465 @@
+\input texinfo
+@c %**start of header
+@setfilename tar.info
+@settitle GNU tar
+@finalout
+@smallbook
+@setchapternewpage odd
+@c %**end of header
+
+@c ======================================================================
+@c This document has three levels of rendition: PUBLISH, DISTRIB or PROOF,
+@c as decided by @set symbols. The PUBLISH rendition does not show
+@c notes or marks asking for revision. Most users will prefer having more
+@c information, even if this information is not fully revised for adequacy,
+@c so DISTRIB is the default for tar distributions. The PROOF rendition
+@c show all marks to the point of ugliness, but is nevertheless useful to
+@c those working on the manual itself.
+@c ======================================================================
+
+@ifclear PUBLISH
+@ifclear DISTRIB
+@ifclear PROOF
+@set DISTRIB
+@end ifclear
+@end ifclear
+@end ifclear
+
+@ifset PUBLISH
+@set RENDITION The book, version
+@end ifset
+
+@ifset DISTRIB
+@set RENDITION FTP release, version
+@end ifset
+
+@ifset PROOF
+@set RENDITION Proof reading version
+@end ifset
+
+@c ---------------------------------------------------------------------
+@c The @FIXME's, @UNREVISED and @c comments are part Fran@,{c}ois's work
+@c plan. These annotations are somewhat precious to him; he asks that I
+@c do not alter them inconsiderately. Much work is needed for GNU tar
+@c internals (the sources, the programs themselves). Revising the
+@c adequacy of the manual while revising the sources, and cleaning them
+@c both at the same time, seems to him like a good way to proceed.
+@c ---------------------------------------------------------------------
+
+@c Output marks for nodes needing revision, but not in PUBLISH rendition.
+
+@macro UNREVISED
+@ifclear PUBLISH
+@quotation
+@emph{(This message will disappear, once this node revised.)}
+@end quotation
+@end ifclear
+@end macro
+
+@c Output various FIXME information only in PROOF rendition.
+
+@macro FIXME{string}
+@allow-recursion
+@quote-arg
+@ifset PROOF
+@strong{<FIXME>} \string\ @strong{</>}
+@end ifset
+
+@end macro
+
+@macro FIXME-ref{string}
+@quote-arg
+@ifset PROOF
+@strong{<REF>} \string\ @strong{</>}
+@end ifset
+
+@end macro
+
+@macro FIXME-pxref{string}
+@quote-arg
+@ifset PROOF
+@strong{<PXREF>} \string\ @strong{</>}
+@end ifset
+
+@end macro
+
+@macro FIXME-xref{string}
+@quote-arg
+@ifset PROOF
+@strong{<XREF>} \string\ @strong{</>}
+@end ifset
+
+@end macro
+
+@c @macro option{entry}
+@c @quote-arg
+@c @opindex{--\entry\}
+@c @value{\entry\}
+@c @end macro
+
+@set op-absolute-names @kbd{--absolute-names} (@kbd{-P})
+@set ref-absolute-names @ref{absolute}
+@set xref-absolute-names @xref{absolute}
+@set pxref-absolute-names @pxref{absolute}
+
+@set op-after-date @kbd{--after-date=@var{date}} (@kbd{--newer=@var{date}}, @kbd{-N @var{date}})
+@set ref-after-date @ref{after}
+@set xref-after-date @xref{after}
+@set pxref-after-date @pxref{after}
+
+@set op-append @kbd{--append} (@kbd{-r})
+@set ref-append @ref{add}
+@set xref-append @xref{add}
+@set pxref-append @pxref{add}
+
+@set op-atime-preserve @kbd{--atime-preserve}
+@set ref-atime-preserve @ref{Attributes}
+@set xref-atime-preserve @xref{Attributes}
+@set pxref-atime-preserve @pxref{Attributes}
+
+@set op-backup @kbd{--backup}
+@set ref-backup @ref{Backup options}
+@set xref-backup @xref{Backup options}
+@set pxref-backup @pxref{Backup options}
+
+@set op-block-number @kbd{--block-number} (@kbd{-R})
+@set ref-block-number @ref{verbose}
+@set xref-block-number @xref{verbose}
+@set pxref-block-number @pxref{verbose}
+
+@set op-blocking-factor @kbd{--blocking-factor=@var{512-size}} (@kbd{-b @var{512-size}})
+@set ref-blocking-factor @ref{Blocking Factor}
+@set xref-blocking-factor @xref{Blocking Factor}
+@set pxref-blocking-factor @pxref{Blocking Factor}
+
+@set op-bzip2 @kbd{--bzip2} (@kbd{-j})
+@set ref-bzip2 @ref{gzip}
+@set xref-bzip2 @xref{gzip}
+@set pxref-bzip2 @pxref{gzip}
+
+@set op-checkpoint @kbd{--checkpoint}
+@set ref-checkpoint @ref{verbose}
+@set xref-checkpoint @xref{verbose}
+@set pxref-checkpoint @pxref{verbose}
+
+@set op-compare @kbd{--compare} (@kbd{--diff}, @kbd{-d})
+@set ref-compare @ref{compare}
+@set xref-compare @xref{compare}
+@set pxref-compare @pxref{compare}
+
+@set op-compress @kbd{--compress} (@kbd{--uncompress}, @kbd{-Z})
+@set ref-compress @ref{gzip}
+@set xref-compress @xref{gzip}
+@set pxref-compress @pxref{gzip}
+
+@set op-concatenate @kbd{--concatenate} (@kbd{--catenate}, @kbd{-A})
+@set ref-concatenate @ref{concatenate}
+@set xref-concatenate @xref{concatenate}
+@set pxref-concatenate @pxref{concatenate}
+
+@set op-create @kbd{--create} (@kbd{-c})
+@set ref-create @ref{create}
+@set xref-create @xref{create}
+@set pxref-create @pxref{create}
+
+@set op-delete @kbd{--delete}
+@set ref-delete @ref{delete}
+@set xref-delete @xref{delete}
+@set pxref-delete @pxref{delete}
+
+@set op-dereference @kbd{--dereference} (@kbd{-h})
+@set ref-dereference @ref{dereference}
+@set xref-dereference @xref{dereference}
+@set pxref-dereference @pxref{dereference}
+
+@set op-directory @kbd{--directory=@var{directory}} (@kbd{-C @var{directory}})
+@set ref-directory @ref{directory}
+@set xref-directory @xref{directory}
+@set pxref-directory @pxref{directory}
+
+@set op-exclude @kbd{--exclude=@var{pattern}}
+@set ref-exclude @ref{exclude}
+@set xref-exclude @xref{exclude}
+@set pxref-exclude @pxref{exclude}
+
+@set op-exclude-from @kbd{--exclude-from=@var{file-of-patterns}} (@kbd{-X @var{file-of-patterns}})
+@set ref-exclude-from @ref{exclude}
+@set xref-exclude-from @xref{exclude}
+@set pxref-exclude-from @pxref{exclude}
+
+@set op-extract @kbd{--extract} (@kbd{--get}, @kbd{-x})
+@set ref-extract @ref{extract}
+@set xref-extract @xref{extract}
+@set pxref-extract @pxref{extract}
+
+@set op-file @kbd{--file=@var{archive-name}} (@kbd{-f @var{archive-name}})
+@set ref-file @ref{file}
+@set xref-file @xref{file}
+@set pxref-file @pxref{file}
+
+@set op-files-from @kbd{--files-from=@var{file-of-names}} (@kbd{-T @var{file-of-names}})
+@set ref-files-from @ref{files}
+@set xref-files-from @xref{files}
+@set pxref-files-from @pxref{files}
+
+@set op-force-local @kbd{--force-local}
+@set ref-force-local @ref{file}
+@set xref-force-local @xref{file}
+@set pxref-force-local @pxref{file}
+
+@set op-group @kbd{--group=@var{group}}
+@set ref-group @ref{Option Summary}
+@set xref-group @xref{Option Summary}
+@set pxref-group @pxref{Option Summary}
+
+@set op-gzip @kbd{--gzip} (@kbd{--gunzip}, @kbd{--ungzip}, @kbd{-z})
+@set ref-gzip @ref{gzip}
+@set xref-gzip @xref{gzip}
+@set pxref-gzip @pxref{gzip}
+
+@set op-help @kbd{--help}
+@set ref-help @ref{help}
+@set xref-help @xref{help}
+@set pxref-help @pxref{help}
+
+@set op-ignore-failed-read @kbd{--ignore-failed-read}
+@set ref-ignore-failed-read @ref{create options}
+@set xref-ignore-failed-read @xref{create options}
+@set pxref-ignore-failed-read @pxref{create options}
+
+@set op-ignore-zeros @kbd{--ignore-zeros} (@kbd{-i})
+@set ref-ignore-zeros @ref{Reading}
+@set xref-ignore-zeros @xref{Reading}
+@set pxref-ignore-zeros @pxref{Reading}
+
+@set op-incremental @kbd{--incremental} (@kbd{-G})
+@set ref-incremental @ref{Inc Dumps}
+@set xref-incremental @xref{Inc Dumps}
+@set pxref-incremental @pxref{Inc Dumps}
+
+@set op-info-script @kbd{--info-script=@var{script-name}} (@kbd{--new-volume-script=@var{script-name}}, @kbd{-F @var{script-name}})
+@set ref-info-script @ref{Multi-Volume Archives}
+@set xref-info-script @xref{Multi-Volume Archives}
+@set pxref-info-script @pxref{Multi-Volume Archives}
+
+@set op-interactive @kbd{--interactive} (@kbd{-w})
+@set ref-interactive @ref{interactive}
+@set xref-interactive @xref{interactive}
+@set pxref-interactive @pxref{interactive}
+
+@set op-keep-old-files @kbd{--keep-old-files} (@kbd{-k})
+@set ref-keep-old-files @ref{Writing}
+@set xref-keep-old-files @xref{Writing}
+@set pxref-keep-old-files @pxref{Writing}
+
+@set op-label @kbd{--label=@var{archive-label}} (@kbd{-V @var{archive-label}})
+@set ref-label @ref{label}
+@set xref-label @xref{label}
+@set pxref-label @pxref{label}
+
+@set op-list @kbd{--list} (@kbd{-t})
+@set ref-list @ref{list}
+@set xref-list @xref{list}
+@set pxref-list @pxref{list}
+
+@set op-listed-incremental @kbd{--listed-incremental=@var{snapshot-file}} (@kbd{-g @var{snapshot-file}})
+@set ref-listed-incremental @ref{Inc Dumps}
+@set xref-listed-incremental @xref{Inc Dumps}
+@set pxref-listed-incremental @pxref{Inc Dumps}
+
+@set op-mode @kbd{--mode=@var{permissions}}
+@set ref-mode @ref{Option Summary}
+@set xref-mode @xref{Option Summary}
+@set pxref-mode @pxref{Option Summary}
+
+@set op-multi-volume @kbd{--multi-volume} (@kbd{-M})
+@set ref-multi-volume @ref{Multi-Volume Archives}
+@set xref-multi-volume @xref{Multi-Volume Archives}
+@set pxref-multi-volume @pxref{Multi-Volume Archives}
+
+@set op-newer-mtime @kbd{--newer-mtime=@var{date}}
+@set ref-newer-mtime @ref{after}
+@set xref-newer-mtime @xref{after}
+@set pxref-newer-mtime @pxref{after}
+
+@set op-no-recursion @kbd{--no-recursion}
+@set ref-no-recursion @ref{recurse}
+@set xref-no-recursion @xref{recurse}
+@set pxref-no-recursion @pxref{recurse}
+
+@set op-no-same-owner @kbd{--no-same-owner}
+@set ref-no-same-owner @ref{Attributes}
+@set xref-no-same-owner @xref{Attributes}
+@set pxref-no-same-owner @pxref{Attributes}
+
+@set op-no-same-permissions @kbd{--no-same-permissions}
+@set ref-no-same-permissions @ref{Attributes}
+@set xref-no-same-permissions @xref{Attributes}
+@set pxref-no-same-permissions @pxref{Attributes}
+
+@set op-null @kbd{--null}
+@set ref-null @ref{files}
+@set xref-null @xref{files}
+@set pxref-null @pxref{files}
+
+@set op-numeric-owner @kbd{--numeric-owner}
+@set ref-numeric-owner @ref{Attributes}
+@set xref-numeric-owner @xref{Attributes}
+@set pxref-numeric-owner @pxref{Attributes}
+
+@set op-old-archive @kbd{--old-archive} (@kbd{-o})
+@set ref-old-archive @ref{old}
+@set xref-old-archive @xref{old}
+@set pxref-old-archive @pxref{old}
+
+@set op-one-file-system @kbd{--one-file-system} (@kbd{-l})
+@set ref-one-file-system @ref{one}
+@set xref-one-file-system @xref{one}
+@set pxref-one-file-system @pxref{one}
+
+@set op-overwrite @kbd{--overwrite}
+@set ref-overwrite @ref{Overwrite Old Files}
+@set xref-overwrite @xref{Overwrite Old Files}
+@set pxref-overwrite @pxref{Overwrite Old Files}
+
+@set op-owner @kbd{--owner=@var{user}}
+@set ref-owner @ref{Option Summary}
+@set xref-owner @xref{Option Summary}
+@set pxref-owner @pxref{Option Summary}
+
+@set op-posix @kbd{--posix}
+@set ref-posix @ref{posix}
+@set xref-posix @xref{posix}
+@set pxref-posix @pxref{posix}
+
+@set op-preserve @kbd{--preserve}
+@set ref-preserve @ref{Attributes}
+@set xref-preserve @xref{Attributes}
+@set pxref-preserve @pxref{Attributes}
+
+@set op-record-size @kbd{--record-size=@var{size}}
+@set ref-record-size @ref{Blocking}
+@set xref-record-size @xref{Blocking}
+@set pxref-record-size @pxref{Blocking}
+
+@set op-recursive-unlink @kbd{--recursive-unlink}
+@set ref-recursive-unlink @ref{Writing}
+@set xref-recursive-unlink @xref{Writing}
+@set pxref-recursive-unlink @pxref{Writing}
+
+@set op-read-full-records @kbd{--read-full-records} (@kbd{-B})
+@set ref-read-full-records @ref{Blocking}
+@set xref-read-full-records @xref{Blocking}
+@set pxref-read-full-records @pxref{Blocking}
+@c FIXME: or should it be Reading, or Blocking Factor
+
+@set op-remove-files @kbd{--remove-files}
+@set ref-remove-files @ref{Writing}
+@set xref-remove-files @xref{Writing}
+@set pxref-remove-files @pxref{Writing}
+
+@set op-rsh-command @kbd{rsh-command=@var{command}}
+
+@set op-same-order @kbd{--same-order} (@kbd{--preserve-order}, @kbd{-s})
+@set ref-same-order @ref{Scarce}
+@set xref-same-order @xref{Scarce}
+@set pxref-same-order @pxref{Scarce}
+@c FIXME: or should it be Reading, or Attributes?
+
+@set op-same-owner @kbd{--same-owner}
+@set ref-same-owner @ref{Attributes}
+@set xref-same-owner @xref{Attributes}
+@set pxref-same-owner @pxref{Attributes}
+
+@set op-same-permissions @kbd{--same-permissions} (@kbd{--preserve-permissions}, @kbd{-p})
+@set ref-same-permissions @ref{Attributes}
+@set xref-same-permissions @xref{Attributes}
+@set pxref-same-permissions @pxref{Attributes}
+@c FIXME: or should it be Writing?
+
+@set op-show-omitted-dirs @kbd{--show-omitted-dirs}
+@set ref-show-omitted-dirs @ref{verbose}
+@set xref-show-omitted-dirs @xref{verbose}
+@set pxref-show-omitted-dirs @pxref{verbose}
+
+@set op-sparse @kbd{--sparse} (@kbd{-S})
+@set ref-sparse @ref{sparse}
+@set xref-sparse @xref{sparse}
+@set pxref-sparse @pxref{sparse}
+
+@set op-starting-file @kbd{--starting-file=@var{name}} (@kbd{-K @var{name}})
+@set ref-starting-file @ref{Scarce}
+@set xref-starting-file @xref{Scarce}
+@set pxref-starting-file @pxref{Scarce}
+
+@set op-suffix @kbd{--suffix=@var{suffix}}
+@set ref-suffix @ref{Backup options}
+@set xref-suffix @xref{Backup options}
+@set pxref-suffix @pxref{Backup options}
+
+@set op-tape-length @kbd{--tape-length=@var{1024-size}} (@kbd{-L @var{1024-size}})
+@set ref-tape-length @ref{Using Multiple Tapes}
+@set xref-tape-length @xref{Using Multiple Tapes}
+@set pxref-tape-length @pxref{Using Multiple Tapes}
+
+@set op-to-stdout @kbd{--to-stdout} (@kbd{-O})
+@set ref-to-stdout @ref{Writing}
+@set xref-to-stdout @xref{Writing}
+@set pxref-to-stdout @pxref{Writing}
+
+@set op-totals @kbd{--totals}
+@set ref-totals @ref{verbose}
+@set xref-totals @xref{verbose}
+@set pxref-totals @pxref{verbose}
+
+@set op-touch @kbd{--touch} (@kbd{-m})
+@set ref-touch @ref{Writing}
+@set xref-touch @xref{Writing}
+@set pxref-touch @pxref{Writing}
+
+@set op-unlink-first @kbd{--unlink-first} (@kbd{-U})
+@set ref-unlink-first @ref{Writing}
+@set xref-unlink-first @xref{Writing}
+@set pxref-unlink-first @pxref{Writing}
+
+@set op-update @kbd{--update} (@kbd{-u})
+@set ref-update @ref{update}
+@set xref-update @xref{update}
+@set pxref-update @pxref{update}
+
+@set op-use-compress-prog @kbd{--use-compress-prog=@var{program}}
+@set ref-use-compress-prog @ref{gzip}
+@set xref-use-compress-prog @xref{gzip}
+@set pxref-use-compress-prog @pxref{gzip}
+
+@set op-verbose @kbd{--verbose} (@kbd{-v})
+@set ref-verbose @ref{verbose}
+@set xref-verbose @xref{verbose}
+@set pxref-verbose @pxref{verbose}
+
+@set op-verify @kbd{--verify} (@kbd{-W})
+@set ref-verify @ref{verify}
+@set xref-verify @xref{verify}
+@set pxref-verify @pxref{verify}
+
+@set op-version @kbd{--version}
+@set ref-version @ref{help}
+@set xref-version @xref{help}
+@set pxref-version @pxref{help}
+
+@set op-volno-file @kbd{--volno-file=@var{file-of-number}}
+@set ref-volno-file @ref{Using Multiple Tapes}
+@set xref-volno-file @xref{Using Multiple Tapes}
+@set pxref-volno-file @pxref{Using Multiple Tapes}
+
+@include version.texi
+
+@c Put everything in one index (arbitrarily chosen to be the concept index).
+@syncodeindex fn cp
+@syncodeindex ky cp
+@syncodeindex pg cp
+@syncodeindex vr cp
+
+@defindex op
+@syncodeindex op cp
+
+@dircategory GNU Packages
+@direntry
+* Tar: (tar). Making tape (or disk) archives.
+@end direntry
+
+@dircategory Individual utilities
+@direntry
+* tar: (tar)tar invocation. Invoking @sc{gnu} @command{tar}
+@end direntry
+
+@ifinfo
+This file documents @sc{gnu} @command{tar}, which creates and extracts
+files from archives.
+
+Copyright 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001 Free Software
+Foundation, Inc.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1
+or any later version published by the Free Software Foundation;
+with no Invariant Sections, with no
+Front-Cover Texts, and with no Back-Cover Texts.
+A copy of the license is included in the section entitled ``GNU
+Free Documentation License''.
+
+@end ifinfo
+
+@shorttitlepage @sc{gnu} @command{tar}
+
+@titlepage
+@title @sc{gnu} tar: an archiver tool
+@subtitle @value{RENDITION} @value{VERSION}, @value{UPDATED}
+@author Melissa Weisshaus, Jay Fenlason,
+@author Thomas Bushnell, n/BSG, Amy Gorin
+@c he said to remove it: Fran@,{c}ois Pinard
+@c i'm thinking about how the author page *should* look. -mew 2may96
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1
+or any later version published by the Free Software Foundation;
+with no Invariant Sections, with no
+Front-Cover Texts, and with no Back-Cover Texts.
+A copy of the license is included in the section entitled ``GNU
+Free Documentation License''.
+@end titlepage
+
+@ifnottex
+@node Top
+@top @sc{gnu} tar: an archiver tool
+
+@cindex file archival
+@cindex archiving files
+
+@sc{gnu} @command{tar} creates and extracts files from archives.
+
+This manual documents version @value{VERSION} of @sc{gnu} @command{tar}.
+
+The first part of this master menu lists the major nodes in this Info
+document. The rest of the menu lists all the lower level nodes.
+@end ifnottex
+
+@c The master menu, created with texinfo-master-menu, goes here.
+@c (However, getdate.texi's menu is interpolated by hand.)
+
+@menu
+* Introduction::
+* Tutorial::
+* tar invocation::
+* operations::
+* Backups::
+* Choosing::
+* Date input formats::
+* Formats::
+* Media::
+* Free Software Needs Free Documentation::
+* Copying This Manual::
+* Index::
+
+@detailmenu
+ --- The Detailed Node Listing ---
+
+Introduction
+
+* Book Contents:: What this Book Contains
+* Definitions:: Some Definitions
+* What tar Does:: What @command{tar} Does
+* Naming tar Archives:: How @command{tar} Archives are Named
+* posix compliance::
+* Authors:: @sc{gnu} @command{tar} Authors
+* Reports:: Reporting bugs or suggestions
+
+Tutorial Introduction to @command{tar}
+
+* assumptions::
+* stylistic conventions::
+* basic tar options:: Basic @command{tar} Operations and Options
+* frequent operations::
+* Two Frequent Options::
+* create:: How to Create Archives
+* list:: How to List Archives
+* extract:: How to Extract Members from an Archive
+* going further::
+
+Two Frequently Used Options
+
+* file tutorial::
+* verbose tutorial::
+* help tutorial::
+
+How to Create Archives
+
+* prepare for examples::
+* Creating the archive::
+* create verbose::
+* short create::
+* create dir::
+
+How to List Archives
+
+* list dir::
+
+How to Extract Members from an Archive
+
+* extracting archives::
+* extracting files::
+* extract dir::
+* failing commands::
+
+Invoking @sc{gnu} @command{tar}
+
+* Synopsis::
+* using tar options::
+* Styles::
+* All Options::
+* help::
+* verbose::
+* interactive::
+
+The Three Option Styles
+
+* Mnemonic Options:: Mnemonic Option Style
+* Short Options:: Short Option Style
+* Old Options:: Old Option Style
+* Mixing:: Mixing Option Styles
+
+All @command{tar} Options
+
+* Operation Summary::
+* Option Summary::
+* Short Option Summary::
+
+@sc{gnu} @command{tar} Operations
+
+* Basic tar::
+* Advanced tar::
+* create options::
+* extract options::
+* backup::
+* Applications::
+* looking ahead::
+
+Advanced @sc{gnu} @command{tar} Operations
+
+* Operations::
+* current state::
+* append::
+* update::
+* concatenate::
+* delete::
+* compare::
+
+How to Add Files to Existing Archives: @code{--append}
+
+* appending files:: Appending Files to an Archive
+* multiple::
+
+Updating an Archive
+
+* how to update::
+
+Options Used by @code{--create}
+
+* Ignore Failed Read::
+
+Options Used by @code{--extract}
+
+* Reading:: Options to Help Read Archives
+* Writing:: Changing How @command{tar} Writes Files
+* Scarce:: Coping with Scarce Resources
+
+Options to Help Read Archives
+
+* read full records::
+* Ignore Zeros::
+
+Changing How @command{tar} Writes Files
+
+* Dealing with Old Files::
+* Overwrite Old Files::
+* Keep Old Files::
+* Unlink First::
+* Recursive Unlink::
+* Modification Times::
+* Setting Access Permissions::
+* Writing to Standard Output::
+* remove files::
+
+Coping with Scarce Resources
+
+* Starting File::
+* Same Order::
+
+Performing Backups and Restoring Files
+
+* Full Dumps:: Using @command{tar} to Perform Full Dumps
+* Inc Dumps:: Using @command{tar} to Perform Incremental Dumps
+* incremental and listed-incremental:: The Incremental Options
+* Backup Levels:: Levels of Backups
+* Backup Parameters:: Setting Parameters for Backups and Restoration
+* Scripted Backups:: Using the Backup Scripts
+* Scripted Restoration:: Using the Restore Script
+
+Setting Parameters for Backups and Restoration
+
+* backup-specs example:: An Example Text of @file{Backup-specs}
+* Script Syntax:: Syntax for @file{Backup-specs}
+
+Choosing Files and Names for @command{tar}
+
+* file:: Choosing the Archive's Name
+* Selecting Archive Members::
+* files:: Reading Names from a File
+* exclude:: Excluding Some Files
+* Wildcards::
+* after:: Operating Only on New Files
+* recurse:: Descending into Directories
+* one:: Crossing Filesystem Boundaries
+
+Reading Names from a File
+
+* nul::
+
+Excluding Some Files
+
+* controlling pattern-patching with exclude::
+* problems with exclude::
+
+Crossing Filesystem Boundaries
+
+* directory:: Changing Directory
+* absolute:: Absolute File Names
+
+Date input formats
+
+* General date syntax:: Common rules.
+* Calendar date items:: 19 Dec 1994.
+* Time of day items:: 9:20pm.
+* Time zone items:: @sc{est}, @sc{pdt}, @sc{gmt}, ...
+* Day of week items:: Monday and others.
+* Relative items in date strings:: next tuesday, 2 years ago.
+* Pure numbers in date strings:: 19931219, 1440.
+* Authors of getdate:: Bellovin, Eggert, Salz, Berets, et al.
+
+Controlling the Archive Format
+
+* Portability:: Making @command{tar} Archives More Portable
+* Compression:: Using Less Space through Compression
+* Attributes:: Handling File Attributes
+* Standard:: The Standard Format
+* Extensions:: @sc{gnu} Extensions to the Archive Format
+* cpio:: Comparison of @command{tar} and @command{cpio}
+
+Making @command{tar} Archives More Portable
+
+* Portable Names:: Portable Names
+* dereference:: Symbolic Links
+* old:: Old V7 Archives
+* posix:: @sc{posix} archives
+* Checksumming:: Checksumming Problems
+* Large or Negative Values:: Large files, negative time stamps, etc.
+
+Using Less Space through Compression
+
+* gzip:: Creating and Reading Compressed Archives
+* sparse:: Archiving Sparse Files
+
+Tapes and Other Archive Media
+
+* Device:: Device selection and switching
+* Remote Tape Server::
+* Common Problems and Solutions::
+* Blocking:: Blocking
+* Many:: Many archives on one tape
+* Using Multiple Tapes:: Using Multiple Tapes
+* label:: Including a Label in the Archive
+* verify::
+* Write Protection::
+
+Blocking
+
+* Format Variations:: Format Variations
+* Blocking Factor:: The Blocking Factor of an Archive
+
+Many Archives on One Tape
+
+* Tape Positioning:: Tape Positions and Tape Marks
+* mt:: The @command{mt} Utility
+
+Using Multiple Tapes
+
+* Multi-Volume Archives:: Archives Longer than One Tape or Disk
+* Tape Files:: Tape Files
+
+Copying This Manual
+
+* GNU Free Documentation License:: License for copying this manual
+
+@end detailmenu
+@end menu
+
+@node Introduction
+@chapter Introduction
+
+Welcome to the @sc{gnu} @command{tar} manual. @sc{gnu} @command{tar} creates
+and manipulates (@dfn{archives}) which are actually collections of
+many other files; the program provides users with an organized and
+systematic method for controlling a large amount of data.
+
+@menu
+* Book Contents:: What this Book Contains
+* Definitions:: Some Definitions
+* What tar Does:: What @command{tar} Does
+* Naming tar Archives:: How @command{tar} Archives are Named
+* posix compliance::
+* Authors:: @sc{gnu} @command{tar} Authors
+* Reports:: Reporting bugs or suggestions
+@end menu
+
+@node Book Contents
+@section What this Book Contains
+
+The first part of this chapter introduces you to various terms that will
+recur throughout the book. It also tells you who has worked on @sc{gnu}
+@command{tar} and its documentation, and where you should send bug reports
+or comments.
+
+The second chapter is a tutorial (@pxref{Tutorial}) which provides a
+gentle introduction for people who are new to using @command{tar}. It is
+meant to be self contained, not requiring any reading from subsequent
+chapters to make sense. It moves from topic to topic in a logical,
+progressive order, building on information already explained.
+
+Although the tutorial is paced and structured to allow beginners to
+learn how to use @command{tar}, it is not intended solely for beginners.
+The tutorial explains how to use the three most frequently used
+operations (@samp{create}, @samp{list}, and @samp{extract}) as well as
+two frequently used options (@samp{file} and @samp{verbose}). The other
+chapters do not refer to the tutorial frequently; however, if a section
+discusses something which is a complex variant of a basic concept, there
+may be a cross reference to that basic concept. (The entire book,
+including the tutorial, assumes that the reader understands some basic
+concepts of using a Unix-type operating system; @pxref{Tutorial}.)
+
+The third chapter presents the remaining five operations, and
+information about using @command{tar} options and option syntax.
+
+@FIXME{this sounds more like a @sc{gnu} Project Manuals Concept [tm] more
+than the reality. should think about whether this makes sense to say
+here, or not.} The other chapters are meant to be used as a
+reference. Each chapter presents everything that needs to be said
+about a specific topic.
+
+One of the chapters (@pxref{Date input formats}) exists in its entirety
+in other @sc{gnu} manuals, and is mostly self-contained. In addition, one
+section of this manual (@pxref{Standard}) contains a big quote which is
+taken directly from @command{tar} sources.
+
+In general, we give both the long and short (abbreviated) option names
+at least once in each section where the relevant option is covered, so
+that novice readers will become familiar with both styles. (A few
+options have no short versions, and the relevant sections will
+indicate this.)
+
+@node Definitions
+@section Some Definitions
+
+@cindex archive
+@cindex tar archive
+The @command{tar} program is used to create and manipulate @command{tar}
+archives. An @dfn{archive} is a single file which contains the contents
+of many files, while still identifying the names of the files, their
+owner(s), and so forth. (In addition, archives record access
+permissions, user and group, size in bytes, and last modification time.
+Some archives also record the file names in each archived directory, as
+well as other file and directory information.) You can use @command{tar}
+to @dfn{create} a new archive in a specified directory.
+
+@cindex member
+@cindex archive member
+@cindex file name
+@cindex member name
+The files inside an archive are called @dfn{members}. Within this
+manual, we use the term @dfn{file} to refer only to files accessible in
+the normal ways (by @command{ls}, @command{cat}, and so forth), and the term
+@dfn{member} to refer only to the members of an archive. Similarly, a
+@dfn{file name} is the name of a file, as it resides in the filesystem,
+and a @dfn{member name} is the name of an archive member within the
+archive.
+
+@cindex extraction
+@cindex unpacking
+The term @dfn{extraction} refers to the process of copying an archive
+member (or multiple members) into a file in the filesystem. Extracting
+all the members of an archive is often called @dfn{extracting the
+archive}. The term @dfn{unpack} can also be used to refer to the
+extraction of many or all the members of an archive. Extracting an
+archive does not destroy the archive's structure, just as creating an
+archive does not destroy the copies of the files that exist outside of
+the archive. You may also @dfn{list} the members in a given archive
+(this is often thought of as ``printing'' them to the standard output,
+or the command line), or @dfn{append} members to a pre-existing archive.
+All of these operations can be performed using @command{tar}.
+
+@node What tar Does
+@section What @command{tar} Does
+
+@cindex tar
+The @command{tar} program provides the ability to create @command{tar}
+archives, as well as various other kinds of manipulation. For example,
+you can use @command{tar} on previously created archives to extract files,
+to store additional files, or to update or list files which were already
+stored.
+
+Initially, @command{tar} archives were used to store files conveniently on
+magnetic tape. The name @command{tar} comes from this use; it stands for
+@code{t}ape @code{ar}chiver. Despite the utility's name, @command{tar} can
+direct its output to available devices, files, or other programs (using
+pipes). @command{tar} may even access remote devices or files (as archives).
+
+@FIXME{the following table entries need a bit of work..}
+
+You can use @command{tar} archives in many ways. We want to stress a few
+of them: storage, backup, and transportation.
+
+@table @asis
+@item Storage
+Often, @command{tar} archives are used to store related files for
+convenient file transfer over a network. For example, the @sc{gnu} Project
+distributes its software bundled into @command{tar} archives, so that
+all the files relating to a particular program (or set of related
+programs) can be transferred as a single unit.
+
+A magnetic tape can store several files in sequence. However, the tape
+has no names for these files; it only knows their relative position on
+the tape. One way to store several files on one tape and retain their
+names is by creating a @command{tar} archive. Even when the basic transfer
+mechanism can keep track of names, as FTP can, the nuisance of handling
+multiple files, directories, and multiple links makes @command{tar}
+archives useful.
+
+Archive files are also used for long-term storage. You can think of
+this as transportation from the present into the future. (It is a
+science-fiction idiom that you can move through time as well as in
+space; the idea here is that @command{tar} can be used to move archives in
+all dimensions, even time!)
+
+@item Backup
+Because the archive created by @command{tar} is capable of preserving file
+information and directory structure, @command{tar} is commonly used for
+performing full and incremental backups of disks. A backup puts a
+collection of files (possibly pertaining to many users and
+projects) together on a disk or a tape. This guards against accidental
+destruction of the information in those files. @sc{gnu} @command{tar} has
+special features that allow it to be used to make incremental and full
+dumps of all the files in a filesystem.
+
+@item Transportation
+You can create an archive on one system, transfer it to another system,
+and extract the contents there. This allows you to transport a group of
+files from one system to another.
+@end table
+
+@node Naming tar Archives
+@section How @command{tar} Archives are Named
+
+Conventionally, @command{tar} archives are given names ending with
+@samp{.tar}. This is not necessary for @command{tar} to operate properly,
+but this manual follows that convention in order to accustom readers to
+it and to make examples more clear.
+
+@cindex tar file
+@cindex entry
+@cindex tar entry
+Often, people refer to @command{tar} archives as ``@command{tar} files,'' and
+archive members as ``files'' or ``entries''. For people familiar with
+the operation of @command{tar}, this causes no difficulty. However, in
+this manual, we consistently refer to ``archives'' and ``archive
+members'' to make learning to use @command{tar} easier for novice users.
+
+@node posix compliance
+@section @sc{posix} Compliance
+
+@noindent
+@FIXME{must ask franc,ois about this. dan hagerty thinks this might
+be an issue, but we're not really sure at this time. dan just tried a
+test case of mixing up options' orders while the variable was set, and
+there was no problem...}
+
+We make some of our recommendations throughout this book for one
+reason in addition to what we think of as ``good sense''. The main
+additional reason for a recommendation is to be compliant with the
+@sc{posix} standards. If you set the shell environment variable
+@env{POSIXLY_CORRECT}, @sc{gnu} @command{tar} will force you to adhere to
+these standards. Therefore, if this variable is set and you violate
+one of the @sc{posix} standards in the way you phrase a command, for
+example, @sc{gnu} @command{tar} will not allow the command and will signal an
+error message. You would then have to reorder the options or rephrase
+the command to comply with the @sc{posix} standards.
+
+There is a chance in the future that, if you set this environment
+variable, your archives will be forced to comply with @sc{posix} standards,
+also. No @sc{gnu} @command{tar} extensions will be allowed.
+
+@node Authors
+@section @sc{gnu} @command{tar} Authors
+
+@sc{gnu} @command{tar} was originally written by John Gilmore, and modified by
+many people. The @sc{gnu} enhancements were written by Jay Fenlason, then
+Joy Kendall, and the whole package has been further maintained by
+Thomas Bushnell, n/BSG, and finally Fran@,{c}ois Pinard, with
+the help of numerous and kind users.
+
+We wish to stress that @command{tar} is a collective work, and owes much to
+all those people who reported problems, offered solutions and other
+insights, or shared their thoughts and suggestions. An impressive, yet
+partial list of those contributors can be found in the @file{THANKS}
+file from the @sc{gnu} @command{tar} distribution.
+
+@FIXME{i want all of these names mentioned, Absolutely. BUT, i'm not
+sure i want to spell out the history in this detail, at least not for
+the printed book. i'm just not sure it needs to be said this way.
+i'll think about it.}
+
+@FIXME{History is more important, and surely more interesting, than
+actual names. Quoting names without history would be meaningless. FP}
+
+Jay Fenlason put together a draft of a @sc{gnu} @command{tar} manual,
+borrowing notes from the original man page from John Gilmore. This
+was withdrawn in version
+1.11. Thomas Bushnell, n/BSG and Amy Gorin worked on a tutorial and
+manual for @sc{gnu} @command{tar}. Fran@,{c}ois Pinard put version 1.11.8
+of the manual together by taking information from all these sources
+and merging them. Melissa Weisshaus finally edited and redesigned the
+book to create version 1.12. @FIXME{update version number as
+necessary; i'm being optimistic!} @FIXME{Someone [maybe karl berry?
+maybe bob chassell? maybe melissa? maybe julie sussman?] needs to
+properly index the thing.}
+
+For version 1.12, Daniel Hagerty contributed a great deal of technical
+consulting. In particular, he is the primary author of @ref{Backups}.
+
+@node Reports
+@section Reporting bugs or suggestions
+
+@cindex bug reports
+@cindex reporting bugs
+If you find problems or have suggestions about this program or manual,
+please report them to @file{bug-tar@@gnu.org}.
+
+@node Tutorial
+@chapter Tutorial Introduction to @command{tar}
+
+This chapter guides you through some basic examples of three @command{tar}
+operations: @samp{--create}, @samp{--list}, and @samp{--extract}. If
+you already know how to use some other version of @command{tar}, then you
+may not need to read this chapter. This chapter omits most complicated
+details about how @command{tar} works.
+
+@menu
+* assumptions::
+* stylistic conventions::
+* basic tar options:: Basic @command{tar} Operations and Options
+* frequent operations::
+* Two Frequent Options::
+* create:: How to Create Archives
+* list:: How to List Archives
+* extract:: How to Extract Members from an Archive
+* going further::
+@end menu
+
+@node assumptions
+@section Assumptions this Tutorial Makes
+
+This chapter is paced to allow beginners to learn about @command{tar}
+slowly. At the same time, we will try to cover all the basic aspects of
+these three operations. In order to accomplish both of these tasks, we
+have made certain assumptions about your knowledge before reading this
+manual, and the hardware you will be using:
+
+@itemize @bullet
+@item
+Before you start to work through this tutorial, you should understand
+what the terms ``archive'' and ``archive member'' mean
+(@pxref{Definitions}). In addition, you should understand something
+about how Unix-type operating systems work, and you should know how to
+use some basic utilities. For example, you should know how to create,
+list, copy, rename, edit, and delete files and directories; how to
+change between directories; and how to figure out where you are in the
+filesystem. You should have some basic understanding of directory
+structure and how files are named according to which directory they are
+in. You should understand concepts such as standard output and standard
+input, what various definitions of the term ``argument'' mean, and the
+differences between relative and absolute path names. @FIXME{and what
+else?}
+
+@item
+This manual assumes that you are working from your own home directory
+(unless we state otherwise). In this tutorial, you will create a
+directory to practice @command{tar} commands in. When we show path names,
+we will assume that those paths are relative to your home directory.
+For example, my home directory path is @file{/home/fsf/melissa}. All of
+my examples are in a subdirectory of the directory named by that path
+name; the subdirectory is called @file{practice}.
+
+@item
+In general, we show examples of archives which exist on (or can be
+written to, or worked with from) a directory on a hard disk. In most
+cases, you could write those archives to, or work with them on any other
+device, such as a tape drive. However, some of the later examples in
+the tutorial and next chapter will not work on tape drives.
+Additionally, working with tapes is much more complicated than working
+with hard disks. For these reasons, the tutorial does not cover working
+with tape drives. @xref{Media}, for complete information on using
+@command{tar} archives with tape drives.
+
+@FIXME{this is a cop out. need to add some simple tape drive info.}
+@end itemize
+
+@node stylistic conventions
+@section Stylistic Conventions
+
+In the examples, @samp{$} represents a typical shell prompt. It
+precedes lines you should type; to make this more clear, those lines are
+shown in @kbd{this font}, as opposed to lines which represent the
+computer's response; those lines are shown in @code{this font}, or
+sometimes @samp{like this}. When we have lines which are too long to be
+displayed in any other way, we will show them like this:
+
+@smallexample
+This is an example of a line which would otherwise not fit in this space.
+@end smallexample
+
+@FIXME{how often do we use smallexample?}
+
+@node basic tar options
+@section Basic @command{tar} Operations and Options
+
+@command{tar} can take a wide variety of arguments which specify and define
+the actions it will have on the particular set of files or the archive.
+The main types of arguments to @command{tar} fall into one of two classes:
+operations, and options.
+
+Some arguments fall into a class called @dfn{operations}; exactly one of
+these is both allowed and required for any instance of using @command{tar};
+you may @emph{not} specify more than one. People sometimes speak of
+@dfn{operating modes}. You are in a particular operating mode when you
+have specified the operation which specifies it; there are eight
+operations in total, and thus there are eight operating modes.
+
+The other arguments fall into the class known as @dfn{options}. You are
+not required to specify any options, and you are allowed to specify more
+than one at a time (depending on the way you are using @command{tar} at
+that time). Some options are used so frequently, and are so useful for
+helping you type commands more carefully that they are effectively
+``required''. We will discuss them in this chapter.
+
+You can write most of the @command{tar} operations and options in any of
+three forms: long (mnemonic) form, short form, and old style. Some of
+the operations and options have no short or ``old'' forms; however, the
+operations and options which we will cover in this tutorial have
+corresponding abbreviations. @FIXME{make sure this is still the case,
+at the end}We will indicate those abbreviations appropriately to get
+you used to seeing them. (Note that the ``old style'' option forms
+exist in @sc{gnu} @command{tar} for compatibility with Unix @command{tar}. We
+present a full discussion of this way of writing options and operations
+appears in @ref{Old Options}, and we discuss the other two styles of
+writing options in @ref{Mnemonic Options} and @ref{Short Options}.)
+
+In the examples and in the text of this tutorial, we usually use the
+long forms of operations and options; but the ``short'' forms produce
+the same result and can make typing long @command{tar} commands easier.
+For example, instead of typing
+
+@example
+@kbd{tar --create --verbose --file=afiles.tar apple angst aspic}
+@end example
+
+@noindent
+you can type
+@example
+@kbd{tar -c -v -f afiles.tar apple angst aspic}
+@end example
+
+@noindent
+or even
+@example
+@kbd{tar -cvf afiles.tar apple angst aspic}
+@end example
+
+@noindent
+For more information on option syntax, see @ref{Advanced tar}. In
+discussions in the text, when we name an option by its long form, we
+also give the corresponding short option in parentheses.
+
+The term, ``option'', can be confusing at times, since ``operations''
+are often lumped in with the actual, @emph{optional} ``options'' in certain
+general class statements. For example, we just talked about ``short and
+long forms of options and operations''. However, experienced @command{tar}
+users often refer to these by shorthand terms such as, ``short and long
+options''. This term assumes that the ``operations'' are included, also.
+Context will help you determine which definition of ``options'' to use.
+
+Similarly, the term ``command'' can be confusing, as it is often used in
+two different ways. People sometimes refer to @command{tar} ``commands''.
+A @command{tar} @dfn{command} is the entire command line of user input
+which tells @command{tar} what to do --- including the operation, options,
+and any arguments (file names, pipes, other commands, etc). However,
+you will also sometimes hear the term ``the @command{tar} command''. When
+the word ``command'' is used specifically like this, a person is usually
+referring to the @command{tar} @emph{operation}, not the whole line.
+Again, use context to figure out which of the meanings the speaker
+intends.
+
+@node frequent operations
+@section The Three Most Frequently Used Operations
+
+Here are the three most frequently used operations (both short and long
+forms), as well as a brief description of their meanings. The rest of
+this chapter will cover how to use these operations in detail. We will
+present the rest of the operations in the next chapter.
+
+@table @kbd
+@item --create
+@itemx -c
+Create a new @command{tar} archive.
+@item --list
+@itemx -t
+List the contents of an archive.
+@item --extract
+@itemx -x
+Extract one or more members from an archive.
+@end table
+
+@node Two Frequent Options
+@section Two Frequently Used Options
+
+To understand how to run @command{tar} in the three operating modes listed
+previously, you also need to understand how to use two of the options to
+@command{tar}: @samp{--file} (which takes an archive file as an argument)
+and @samp{--verbose}. (You are usually not @emph{required} to specify
+either of these options when you run @command{tar}, but they can be very
+useful in making things more clear and helping you avoid errors.)
+
+@menu
+* file tutorial::
+* verbose tutorial::
+* help tutorial::
+@end menu
+
+@node file tutorial
+@unnumberedsubsec The @samp{--file} Option
+
+@table @kbd
+@item --file=@var{archive-name}
+@itemx -f @var{archive-name}
+Specify the name of an archive file.
+@end table
+
+You can specify an argument for the @value{op-file} option whenever you
+use @command{tar}; this option determines the name of the archive file
+that @command{tar} will work on.
+
+If you don't specify this argument, then @command{tar} will use a
+default, usually some physical tape drive attached to your machine.
+If there is no tape drive attached, or the default is not meaningful,
+then @command{tar} will print an error message. The error message might
+look roughly like one of the following:
+
+@example
+tar: can't open /dev/rmt8 : No such device or address
+tar: can't open /dev/rsmt0 : I/O error
+@end example
+
+@noindent
+To avoid confusion, we recommend that you always specify an archive file
+name by using @value{op-file} when writing your @command{tar} commands.
+For more information on using the @value{op-file} option, see
+@ref{file}.
+
+@node verbose tutorial
+@unnumberedsubsec The @samp{--verbose} Option
+
+@table @kbd
+@item --verbose
+@itemx -v
+Show the files being worked on as @command{tar} is running.
+@end table
+
+@value{op-verbose} shows details about the results of running
+@command{tar}. This can be especially useful when the results might not be
+obvious. For example, if you want to see the progress of @command{tar} as
+it writes files into the archive, you can use the @samp{--verbose}
+option. In the beginning, you may find it useful to use
+@samp{--verbose} at all times; when you are more accustomed to
+@command{tar}, you will likely want to use it at certain times but not at
+others. We will use @samp{--verbose} at times to help make something
+clear, and we will give many examples both using and not using
+@samp{--verbose} to show the differences.
+
+Sometimes, a single instance of @samp{--verbose} on the command line
+will show a full, @samp{ls} style listing of an archive or files,
+giving sizes, owners, and similar information. Other times,
+@samp{--verbose} will only show files or members that the particular
+operation is operating on at the time. In the latter case, you can
+use @samp{--verbose} twice in a command to get a listing such as that
+in the former case. For example, instead of saying
+
+@example
+@kbd{tar -cvf afiles.tar apple angst aspic}
+@end example
+
+@noindent
+above, you might say
+
+@example
+@kbd{tar -cvvf afiles.tar apple angst aspic}
+@end example
+
+@noindent
+This works equally well using short or long forms of options. Using
+long forms, you would simply write out the mnemonic form of the option
+twice, like this:
+
+@example
+$ @kbd{tar --create --verbose --verbose @dots{}}
+@end example
+
+@noindent
+Note that you must double the hyphens properly each time.
+
+Later in the tutorial, we will give examples using @w{@samp{--verbose
+--verbose}}.
+
+@node help tutorial
+@unnumberedsubsec Getting Help: Using the @code{--help} Option
+
+@table @kbd
+@item --help
+
+The @samp{--help} option to @command{tar} prints out a very brief list of
+all operations and option available for the current version of
+@command{tar} available on your system.
+@end table
+
+@node create
+@section How to Create Archives
+@UNREVISED
+
+One of the basic operations of @command{tar} is @value{op-create}, which
+you use to create a @command{tar} archive. We will explain
+@samp{--create} first because, in order to learn about the other
+operations, you will find it useful to have an archive available to
+practice on.
+
+To make this easier, in this section you will first create a directory
+containing three files. Then, we will show you how to create an
+@emph{archive} (inside the new directory). Both the directory, and
+the archive are specifically for you to practice on. The rest of this
+chapter and the next chapter will show many examples using this
+directory and the files you will create: some of those files may be
+other directories and other archives.
+
+The three files you will archive in this example are called
+@file{blues}, @file{folk}, and @file{jazz}. The archive is called
+@file{collection.tar}.
+
+This section will proceed slowly, detailing how to use @samp{--create}
+in @code{verbose} mode, and showing examples using both short and long
+forms. In the rest of the tutorial, and in the examples in the next
+chapter, we will proceed at a slightly quicker pace. This section
+moves more slowly to allow beginning users to understand how
+@command{tar} works.
+
+@menu
+* prepare for examples::
+* Creating the archive::
+* create verbose::
+* short create::
+* create dir::
+@end menu
+
+@node prepare for examples
+@subsection Preparing a Practice Directory for Examples
+
+To follow along with this and future examples, create a new directory
+called @file{practice} containing files called @file{blues}, @file{folk}
+and @file{jazz}. The files can contain any information you like:
+ideally, they should contain information which relates to their names,
+and be of different lengths. Our examples assume that @file{practice}
+is a subdirectory of your home directory.
+
+Now @command{cd} to the directory named @file{practice}; @file{practice}
+is now your @dfn{working directory}. (@emph{Please note}: Although
+the full path name of this directory is
+@file{/@var{homedir}/practice}, in our examples we will refer to
+this directory as @file{practice}; the @var{homedir} is presumed.
+
+In general, you should check that the files to be archived exist where
+you think they do (in the working directory) by running @command{ls}.
+Because you just created the directory and the files and have changed to
+that directory, you probably don't need to do that this time.
+
+It is very important to make sure there isn't already a file in the
+working directory with the archive name you intend to use (in this case,
+@samp{collection.tar}), or that you don't care about its contents.
+Whenever you use @samp{create}, @command{tar} will erase the current
+contents of the file named by @value{op-file} if it exists. @command{tar}
+will not tell you if you are about to overwrite an archive unless you
+specify an option which does this. @FIXME{xref to the node for
+--backup!}To add files to an existing archive, you need to use a
+different option, such as @value{op-append}; see @ref{append} for
+information on how to do this.
+
+@node Creating the archive
+@subsection Creating the Archive
+
+To place the files @file{blues}, @file{folk}, and @file{jazz} into an
+archive named @file{collection.tar}, use the following command:
+
+@example
+$ @kbd{tar --create --file=collection.tar blues folk jazz}
+@end example
+
+The order of the arguments is not very important, @emph{when using long
+option forms}. You could also say:
+
+@example
+$ @kbd{tar blues --create folk --file=collection.tar jazz}
+@end example
+
+@noindent
+However, you can see that this order is harder to understand; this is
+why we will list the arguments in the order that makes the commands
+easiest to understand (and we encourage you to do the same when you use
+@command{tar}, to avoid errors).
+
+Note that the part of the command which says,
+@w{@kbd{--file=collection.tar}} is considered to be @emph{one} argument.
+If you substituted any other string of characters for
+@kbd{collection.tar}, then that string would become the name of the
+archive file you create.
+
+The order of the options becomes more important when you begin to use
+short forms. With short forms, if you type commands in the wrong order
+(even if you type them correctly in all other ways), you may end up with
+results you don't expect. For this reason, it is a good idea to get
+into the habit of typing options in the order that makes inherent sense.
+@xref{short create}, for more information on this.
+
+In this example, you type the command as shown above: @samp{--create}
+is the operation which creates the new archive
+(@file{collection.tar}), and @samp{--file} is the option which lets
+you give it the name you chose. The files, @file{blues}, @file{folk},
+and @file{jazz}, are now members of the archive, @file{collection.tar}
+(they are @dfn{file name arguments} to the @samp{--create} operation).
+@FIXME{xref here to the discussion of file name args?}Now that they are
+in the archive, they are called @emph{archive members}, not files.
+@FIXME{xref to definitions?}
+
+When you create an archive, you @emph{must} specify which files you want
+placed in the archive. If you do not specify any archive members, @sc{gnu}
+@command{tar} will complain.
+
+If you now list the contents of the working directory (@kbd{ls}), you will
+find the archive file listed as well as the files you saw previously:
+
+@example
+blues folk jazz collection.tar
+@end example
+
+@noindent
+Creating the archive @samp{collection.tar} did not destroy the copies of
+the files in the directory.
+
+Keep in mind that if you don't indicate an operation, @command{tar} will not
+run and will prompt you for one. If you don't name any files, @command{tar}
+will complain. You must have write access to the working directory,
+or else you will not be able to create an archive in that directory.
+
+@emph{Caution}: Do not attempt to use @value{op-create} to add files to
+an existing archive; it will delete the archive and write a new one.
+Use @value{op-append} instead. @xref{append}.
+
+@node create verbose
+@subsection Running @samp{--create} with @samp{--verbose}
+
+If you include the @value{op-verbose} option on the command line,
+@command{tar} will list the files it is acting on as it is working. In
+verbose mode, the @code{create} example above would appear as:
+
+@example
+$ @kbd{tar --create --verbose --file=collection.tar blues folk jazz}
+blues
+folk
+jazz
+@end example
+
+This example is just like the example we showed which did not use
+@samp{--verbose}, except that @command{tar} generated the remaining lines
+@iftex
+(note the different font styles).
+@end iftex
+@ifinfo
+.
+@end ifinfo
+
+In the rest of the examples in this chapter, we will frequently use
+@code{verbose} mode so we can show actions or @command{tar} responses that
+you would otherwise not see, and which are important for you to
+understand.
+
+@node short create
+@subsection Short Forms with @samp{create}
+
+As we said before, the @value{op-create} operation is one of the most
+basic uses of @command{tar}, and you will use it countless times.
+Eventually, you will probably want to use abbreviated (or ``short'')
+forms of options. A full discussion of the three different forms that
+options can take appears in @ref{Styles}; for now, here is what the
+previous example (including the @value{op-verbose} option) looks like
+using short option forms:
+
+@example
+$ @kbd{tar -cvf collection.tar blues folk jazz}
+blues
+folk
+jazz
+@end example
+
+@noindent
+As you can see, the system responds the same no matter whether you use
+long or short option forms.
+
+@FIXME{i don't like how this is worded:} One difference between using
+short and long option forms is that, although the exact placement of
+arguments following options is no more specific when using short forms,
+it is easier to become confused and make a mistake when using short
+forms. For example, suppose you attempted the above example in the
+following way:
+
+@example
+$ @kbd{tar -cfv collection.tar blues folk jazz}
+@end example
+
+@noindent
+In this case, @command{tar} will make an archive file called @file{v},
+containing the files @file{blues}, @file{folk}, and @file{jazz}, because
+the @samp{v} is the closest ``file name'' to the @samp{-f} option, and
+is thus taken to be the chosen archive file name. @command{tar} will try
+to add a file called @file{collection.tar} to the @file{v} archive file;
+if the file @file{collection.tar} did not already exist, @command{tar} will
+report an error indicating that this file does not exist. If the file
+@file{collection.tar} does already exist (e.g., from a previous command
+you may have run), then @command{tar} will add this file to the archive.
+Because the @samp{-v} option did not get registered, @command{tar} will not
+run under @samp{verbose} mode, and will not report its progress.
+
+The end result is that you may be quite confused about what happened,
+and possibly overwrite a file. To illustrate this further, we will show
+you how an example we showed previously would look using short forms.
+
+This example,
+
+@example
+$ @kbd{tar blues --create folk --file=collection.tar jazz}
+@end example
+
+@noindent
+is confusing as it is. When shown using short forms, however, it
+becomes much more so:
+
+@example
+$ @kbd{tar blues -c folk -f collection.tar jazz}
+@end example
+
+@noindent
+It would be very easy to put the wrong string of characters
+immediately following the @samp{-f}, but doing that could sacrifice
+valuable data.
+
+For this reason, we recommend that you pay very careful attention to
+the order of options and placement of file and archive names,
+especially when using short option forms. Not having the option name
+written out mnemonically can affect how well you remember which option
+does what, and therefore where different names have to be placed.
+(Placing options in an unusual order can also cause @command{tar} to
+report an error if you have set the shell environment variable
+@env{POSIXLY_CORRECT}; @pxref{posix compliance} for more information
+on this.)
+
+@node create dir
+@subsection Archiving Directories
+
+@cindex Archiving Directories
+@cindex Directories, Archiving
+You can archive a directory by specifying its directory name as a
+file name argument to @command{tar}. The files in the directory will be
+archived relative to the working directory, and the directory will be
+re-created along with its contents when the archive is extracted.
+
+To archive a directory, first move to its superior directory. If you
+have followed the previous instructions in this tutorial, you should
+type:
+
+@example
+$ @kbd{cd ..}
+$
+@end example
+
+@noindent
+This will put you into the directory which contains @file{practice},
+i.e. your home directory. Once in the superior directory, you can
+specify the subdirectory, @file{practice}, as a file name argument. To
+store @file{practice} in the new archive file @file{music.tar}, type:
+
+@example
+$ @kbd{tar --create --verbose --file=music.tar practice}
+@end example
+
+@noindent
+@command{tar} should output:
+
+@example
+practice/
+practice/blues
+practice/folk
+practice/jazz
+practice/collection.tar
+@end example
+
+Note that the archive thus created is not in the subdirectory
+@file{practice}, but rather in the current working directory---the
+directory from which @command{tar} was invoked. Before trying to archive a
+directory from its superior directory, you should make sure you have
+write access to the superior directory itself, not only the directory
+you are trying archive with @command{tar}. For example, you will probably
+not be able to store your home directory in an archive by invoking
+@command{tar} from the root directory; @value{xref-absolute-names}. (Note
+also that @file{collection.tar}, the original archive file, has itself
+been archived. @command{tar} will accept any file as a file to be
+archived, regardless of its content. When @file{music.tar} is
+extracted, the archive file @file{collection.tar} will be re-written
+into the file system).
+
+If you give @command{tar} a command such as
+
+@example
+$ @kbd{tar --create --file=foo.tar .}
+@end example
+
+@noindent
+@command{tar} will report @samp{tar: ./foo.tar is the archive; not dumped}.
+This happens because @command{tar} creates the archive @file{foo.tar} in
+the current directory before putting any files into it. Then, when
+@command{tar} attempts to add all the files in the directory @file{.} to
+the archive, it notices that the file @file{./foo.tar} is the same as the
+archive @file{foo.tar}, and skips it. (It makes no sense to put an archive
+into itself.) @sc{gnu} @command{tar} will continue in this case, and create the
+archive normally, except for the exclusion of that one file.
+(@emph{Please note:} Other versions of @command{tar} are not so clever;
+they will enter an infinite loop when this happens, so you should not
+depend on this behavior unless you are certain you are running @sc{gnu}
+@command{tar}.) @FIXME{bob doesn't like this sentence, since he does it
+all the time, and we've been doing it in the editing passes for this
+manual: In general, make sure that the archive is not inside a
+directory being dumped.}
+
+@node list
+@section How to List Archives
+
+Frequently, you will find yourself wanting to determine exactly what a
+particular archive contains. You can use the @value{op-list} operation
+to get the member names as they currently appear in the archive, as well
+as various attributes of the files at the time they were archived. For
+example, you can examine the archive @file{collection.tar} that you
+created in the last section with the command,
+
+@example
+$ @kbd{tar --list --file=collection.tar}
+@end example
+
+@noindent
+The output of @command{tar} would then be:
+
+@example
+blues
+folk
+jazz
+@end example
+
+@FIXME{we hope this will change. if it doesn't, need to show the
+creation of bfiles somewhere above!!! : }
+
+@noindent
+The archive @file{bfiles.tar} would list as follows:
+
+@example
+./birds
+baboon
+./box
+@end example
+
+@noindent
+Be sure to use a @value{op-file} option just as with @value{op-create}
+to specify the name of the archive.
+
+If you use the @value{op-verbose} option with @samp{--list}, then
+@command{tar} will print out a listing reminiscent of @w{@samp{ls -l}},
+showing owner, file size, and so forth.
+
+If you had used @value{op-verbose} mode, the example above would look
+like:
+
+@example
+$ @kbd{tar --list --verbose --file=collection.tar folk}
+-rw-rw-rw- myself user 62 1990-05-23 10:55 folk
+@end example
+
+@cindex File name arguments, using @code{--list} with
+@cindex @code{--list} with file name arguments
+You can specify one or more individual member names as arguments when
+using @samp{list}. In this case, @command{tar} will only list the
+names of members you identify. For example, @w{@kbd{tar --list
+--file=afiles.tar apple}} would only print @file{apple}.
+
+@FIXME{we hope the relevant aspects of this will change:}Because
+@command{tar} preserves paths, file names must be specified as they appear
+in the archive (ie., relative to the directory from which the archive
+was created). Therefore, it is essential when specifying member names
+to @command{tar} that you give the exact member names. For example,
+@w{@kbd{tar --list --file=bfiles birds}} would produce an error message
+something like @samp{tar: birds: Not found in archive}, because there is
+no member named @file{birds}, only one named @file{./birds}. While the
+names @file{birds} and @file{./birds} name the same file, @emph{member}
+names are compared using a simplistic name comparison, in which an exact
+match is necessary. @xref{absolute}.
+
+However, @w{@kbd{tar --list --file=collection.tar folk}} would respond
+with @file{folk}, because @file{folk} is in the archive file
+@file{collection.tar}. If you are not sure of the exact file name, try
+listing all the files in the archive and searching for the one you
+expect to find; remember that if you use @samp{--list} with no file
+names as arguments, @command{tar} will print the names of all the members
+stored in the specified archive.
+
+@menu
+* list dir::
+@end menu
+
+@node list dir
+@unnumberedsubsec Listing the Contents of a Stored Directory
+@UNREVISED
+
+@FIXME{i changed the order of these nodes around and haven't had a
+chance to play around with this node's example, yet. i have to play
+with it and see what it actually does for my own satisfaction, even if
+what it says *is* correct..}
+
+To get information about the contents of an archived directory,
+use the directory name as a file name argument in conjunction with
+@value{op-list}. To find out file attributes, include the
+@value{op-verbose} option.
+
+For example, to find out about files in the directory @file{practice}, in
+the archive file @file{music.tar}, type:
+
+@example
+$ @kbd{tar --list --verbose --file=music.tar practice}
+@end example
+
+@command{tar} responds:
+
+@example
+drwxrwxrwx myself user 0 1990-05-31 21:49 practice/
+-rw-rw-rw- myself user 42 1990-05-21 13:29 practice/blues
+-rw-rw-rw- myself user 62 1990-05-23 10:55 practice/folk
+-rw-rw-rw- myself user 40 1990-05-21 13:30 practice/jazz
+-rw-rw-rw- myself user 10240 1990-05-31 21:49 practice/collection.tar
+@end example
+
+When you use a directory name as a file name argument, @command{tar} acts on
+all the files (including sub-directories) in that directory.
+
+@node extract
+@section How to Extract Members from an Archive
+@UNREVISED
+@cindex Extraction
+@cindex Retrieving files from an archive
+@cindex Resurrecting files from an archive
+
+Creating an archive is only half the job---there is no point in storing
+files in an archive if you can't retrieve them. The act of retrieving
+members from an archive so they can be used and manipulated as
+unarchived files again is called @dfn{extraction}. To extract files
+from an archive, use the @value{op-extract} operation. As with
+@value{op-create}, specify the name of the archive with @value{op-file}.
+Extracting an archive does not modify the archive in any way; you can
+extract it multiple times if you want or need to.
+
+Using @samp{--extract}, you can extract an entire archive, or specific
+files. The files can be directories containing other files, or not. As
+with @value{op-create} and @value{op-list}, you may use the short or the
+long form of the operation without affecting the performance.
+
+@menu
+* extracting archives::
+* extracting files::
+* extract dir::
+* failing commands::
+@end menu
+
+@node extracting archives
+@subsection Extracting an Entire Archive
+
+To extract an entire archive, specify the archive file name only, with
+no individual file names as arguments. For example,
+
+@example
+$ @kbd{tar -xvf collection.tar}
+@end example
+
+@noindent
+produces this:
+
+@example
+-rw-rw-rw- me user 28 1996-10-18 16:31 jazz
+-rw-rw-rw- me user 21 1996-09-23 16:44 blues
+-rw-rw-rw- me user 20 1996-09-23 16:44 folk
+@end example
+
+@node extracting files
+@subsection Extracting Specific Files
+
+To extract specific archive members, give their exact member names as
+arguments, as printed by @value{op-list}. If you had mistakenly deleted
+one of the files you had placed in the archive @file{collection.tar}
+earlier (say, @file{blues}), you can extract it from the archive without
+changing the archive's structure. It will be identical to the original
+file @file{blues} that you deleted. @FIXME{check this; will the times,
+permissions, owner, etc be the same, also?}
+
+First, make sure you are in the @file{practice} directory, and list the
+files in the directory. Now, delete the file, @samp{blues}, and list
+the files in the directory again.
+
+You can now extract the member @file{blues} from the archive file
+@file{collection.tar} like this:
+
+@example
+$ @kbd{tar --extract --file=collection.tar blues}
+@end example
+
+@noindent
+If you list the files in the directory again, you will see that the file
+@file{blues} has been restored, with its original permissions, creation
+times, and owner.@FIXME{This is only accidentally true, but not in
+general. In most cases, one has to be root for restoring the owner, and
+use a special option for restoring permissions. Here, it just happens
+that the restoring user is also the owner of the archived members, and
+that the current @code{umask} is compatible with original permissions.}
+(These parameters will be identical to those which
+the file had when you originally placed it in the archive; any changes
+you may have made before deleting the file from the file system,
+however, will @emph{not} have been made to the archive member.) The
+archive file, @samp{collection.tar}, is the same as it was before you
+extracted @samp{blues}. You can confirm this by running @command{tar} with
+@value{op-list}.
+
+@FIXME{we hope this will change:}Remember that as with other operations,
+specifying the exact member name is important. @w{@kbd{tar --extract
+--file=bfiles.tar birds}} will fail, because there is no member named
+@file{birds}. To extract the member named @file{./birds}, you must
+specify @w{@kbd{tar --extract --file=bfiles.tar ./birds}}. To find the
+exact member names of the members of an archive, use @value{op-list}
+(@pxref{list}).
+
+You can extract a file to standard output by combining the above options
+with the @option{--to-stdout} option (@pxref{Writing to Standard
+Output}).
+
+If you give the @value{op-verbose} option, then @value{op-extract} will
+print the names of the archive members as it extracts them.
+
+@node extract dir
+@subsection Extracting Files that are Directories
+
+Extracting directories which are members of an archive is similar to
+extracting other files. The main difference to be aware of is that if
+the extracted directory has the same name as any directory already in
+the working directory, then files in the extracted directory will be
+placed into the directory of the same name. Likewise, if there are
+files in the pre-existing directory with the same names as the members
+which you extract, the files from the extracted archive will replace
+the files already in the working directory (and possible
+subdirectories). This will happen regardless of whether or not the
+files in the working directory were more recent than those extracted.
+
+However, if a file was stored with a directory name as part of its file
+name, and that directory does not exist under the working directory when
+the file is extracted, @command{tar} will create the directory.
+
+We can demonstrate how to use @samp{--extract} to extract a directory
+file with an example. Change to the @file{practice} directory if you
+weren't there, and remove the files @file{folk} and @file{jazz}. Then,
+go back to the parent directory and extract the archive
+@file{music.tar}. You may either extract the entire archive, or you may
+extract only the files you just deleted. To extract the entire archive,
+don't give any file names as arguments after the archive name
+@file{music.tar}. To extract only the files you deleted, use the
+following command:
+
+@example
+$ @kbd{tar -xvf music.tar practice/folk practice/jazz}
+@end example
+
+@FIXME{need to show tar's response; used verbose above. also, here's a
+good place to demonstrate the -v -v thing. have to write that up
+(should be trivial, but i'm too tired!).}
+
+@noindent
+Because you created the directory with @file{practice} as part of the
+file names of each of the files by archiving the @file{practice}
+directory as @file{practice}, you must give @file{practice} as part
+of the file names when you extract those files from the archive.
+
+@FIXME{IMPORTANT! show the final structure, here. figure out what it
+will be.}
+
+@node failing commands
+@subsection Commands That Will Fail
+
+Here are some sample commands you might try which will not work, and why
+they won't work.
+
+If you try to use this command,
+
+@example
+$ @kbd{tar -xvf music.tar folk jazz}
+@end example
+
+@noindent
+you will get the following response:
+
+@example
+tar: folk: Not found in archive
+tar: jazz: Not found in archive
+$
+@end example
+
+@noindent
+This is because these files were not originally @emph{in} the parent
+directory @file{..}, where the archive is located; they were in the
+@file{practice} directory, and their file names reflect this:
+
+@example
+$ @kbd{tar -tvf music.tar}
+practice/folk
+practice/jazz
+practice/rock
+@end example
+
+@FIXME{make sure the above works when going through the examples in
+order...}
+
+@noindent
+Likewise, if you try to use this command,
+
+@example
+$ @kbd{tar -tvf music.tar folk jazz}
+@end example
+
+@noindent
+you would get a similar response. Members with those names are not in the
+archive. You must use the correct member names in order to extract the
+files from the archive.
+
+If you have forgotten the correct names of the files in the archive,
+use @w{@kbd{tar --list --verbose}} to list them correctly.
+
+@FIXME{more examples, here? hag thinks it's a good idea.}
+
+@node going further
+@section Going Further Ahead in this Manual
+
+@FIXME{need to write up a node here about the things that are going to
+be in the rest of the manual.}
+
+@node tar invocation
+@chapter Invoking @sc{gnu} @command{tar}
+@UNREVISED
+
+This chapter is about how one invokes the @sc{gnu} @command{tar} command, from
+the command synopsis (@pxref{Synopsis}). There are numerous options,
+and many styles for writing them. One mandatory option specifies
+the operation @command{tar} should perform (@pxref{Operation Summary}),
+other options are meant to detail how this operation should be performed
+(@pxref{Option Summary}). Non-option arguments are not always interpreted
+the same way, depending on what the operation is.
+
+You will find in this chapter everything about option styles and rules for
+writing them (@pxref{Styles}). On the other hand, operations and options
+are fully described elsewhere, in other chapters. Here, you will find
+only synthetic descriptions for operations and options, together with
+pointers to other parts of the @command{tar} manual.
+
+Some options are so special they are fully described right in this
+chapter. They have the effect of inhibiting the normal operation of
+@command{tar} or else, they globally alter the amount of feedback the user
+receives about what is going on. These are the @value{op-help} and
+@value{op-version} (@pxref{help}), @value{op-verbose} (@pxref{verbose})
+and @value{op-interactive} options (@pxref{interactive}).
+
+@menu
+* Synopsis::
+* using tar options::
+* Styles::
+* All Options::
+* help::
+* verbose::
+* interactive::
+@end menu
+
+@node Synopsis
+@section General Synopsis of @command{tar}
+
+The @sc{gnu} @command{tar} program is invoked as either one of:
+
+@example
+@kbd{tar @var{option}@dots{} [@var{name}]@dots{}}
+@kbd{tar @var{letter}@dots{} [@var{argument}]@dots{} [@var{option}]@dots{} [@var{name}]@dots{}}
+@end example
+
+The second form is for when old options are being used.
+
+You can use @command{tar} to store files in an archive, to extract them from
+an archive, and to do other types of archive manipulation. The primary
+argument to @command{tar}, which is called the @dfn{operation}, specifies
+which action to take. The other arguments to @command{tar} are either
+@dfn{options}, which change the way @command{tar} performs an operation,
+or file names or archive members, which specify the files or members
+@command{tar} is to act on.
+
+You can actually type in arguments in any order, even if in this manual
+the options always precede the other arguments, to make examples easier
+to understand. Further, the option stating the main operation mode
+(the @command{tar} main command) is usually given first.
+
+Each @var{name} in the synopsis above is interpreted as an archive member
+name when the main command is one of @value{op-compare}, @value{op-delete},
+@value{op-extract}, @value{op-list} or @value{op-update}. When naming
+archive members, you must give the exact name of the member in the
+archive, as it is printed by @value{op-list}. For @value{op-append}
+and @value{op-create}, these @var{name} arguments specify the names
+of either files or directory hierarchies to place in the archive.
+These files or hierarchies should already exist in the file system,
+prior to the execution of the @command{tar} command.
+
+@command{tar} interprets relative file names as being relative to the
+working directory. @command{tar} will make all file names relative
+(by removing leading slashes when archiving or restoring files),
+unless you specify otherwise (using the @value{op-absolute-names}
+option). @value{xref-absolute-names}, for more information about
+@value{op-absolute-names}.
+
+If you give the name of a directory as either a file name or a member
+name, then @command{tar} acts recursively on all the files and directories
+beneath that directory. For example, the name @file{/} identifies all
+the files in the filesystem to @command{tar}.
+
+The distinction between file names and archive member names is especially
+important when shell globbing is used, and sometimes a source of confusion
+for newcomers. @xref{Wildcards}, for more information about globbing.
+The problem is that shells may only glob using existing files in the
+file system. Only @command{tar} itself may glob on archive members, so when
+needed, you must ensure that wildcard characters reach @command{tar} without
+being interpreted by the shell first. Using a backslash before @samp{*}
+or @samp{?}, or putting the whole argument between quotes, is usually
+sufficient for this.
+
+Even if @var{name}s are often specified on the command line, they
+can also be read from a text file in the file system, using the
+@value{op-files-from} option.
+
+If you don't use any file name arguments, @value{op-append},
+@value{op-delete} and @value{op-concatenate} will do nothing, while
+@value{op-create} will usually yield a diagnostic and inhibit @command{tar}
+execution. The other operations of @command{tar} (@value{op-list},
+@value{op-extract}, @value{op-compare}, and @value{op-update}) will act
+on the entire contents of the archive.
+
+@cindex exit status
+@cindex return status
+Besides successful exits, @sc{gnu} @command{tar} may fail for many reasons.
+Some reasons correspond to bad usage, that is, when the @command{tar}
+command is improperly written.
+Errors may be encountered later, while encountering an error
+processing the archive or the files. Some errors are recoverable,
+in which case the failure is delayed until @command{tar} has completed
+all its work. Some errors are such that it would not meaningful,
+or at least risky, to continue processing: @command{tar} then aborts
+processing immediately. All abnormal exits, whether immediate or
+delayed, should always be clearly diagnosed on @code{stderr}, after
+a line stating the nature of the error.
+
+@sc{gnu} @command{tar} returns only a few exit statuses. I'm really
+aiming simplicity in that area, for now. If you are not using the
+@value{op-compare} option, zero means that everything went well, besides
+maybe innocuous warnings. Nonzero means that something went wrong.
+Right now, as of today, ``nonzero'' is almost always 2, except for
+remote operations, where it may be 128.
+
+@node using tar options
+@section Using @command{tar} Options
+
+@sc{gnu} @command{tar} has a total of eight operating modes which allow you to
+perform a variety of tasks. You are required to choose one operating
+mode each time you employ the @command{tar} program by specifying one, and
+only one operation as an argument to the @command{tar} command (two lists
+of four operations each may be found at @ref{frequent operations} and
+@ref{Operations}). Depending on circumstances, you may also wish to
+customize how the chosen operating mode behaves. For example, you may
+wish to change the way the output looks, or the format of the files that
+you wish to archive may require you to do something special in order to
+make the archive look right.
+
+You can customize and control @command{tar}'s performance by running
+@command{tar} with one or more options (such as @value{op-verbose}, which
+we used in the tutorial). As we said in the tutorial, @dfn{options} are
+arguments to @command{tar} which are (as their name suggests) optional.
+Depending on the operating mode, you may specify one or more options.
+Different options will have different effects, but in general they all
+change details of the operation, such as archive format, archive name,
+or level of user interaction. Some options make sense with all
+operating modes, while others are meaningful only with particular modes.
+You will likely use some options frequently, while you will only use
+others infrequently, or not at all. (A full list of options is
+available in @pxref{All Options}.)
+
+The @env{TAR_OPTIONS} environment variable specifies default options to
+be placed in front of any explicit options. For example, if
+@code{TAR_OPTIONS} is @samp{-v --unlink-first}, @command{tar} behaves as
+if the two options @option{-v} and @option{--unlink-first} had been
+specified before any explicit options. Option specifications are
+separated by whitespace. A backslash escapes the next character, so it
+can be used to specify an option containing whitespace or a backslash.
+
+Note that @command{tar} options are case sensitive. For example, the
+options @samp{-T} and @samp{-t} are different; the first requires an
+argument for stating the name of a file providing a list of @var{name}s,
+while the second does not require an argument and is another way to
+write @value{op-list}.
+
+In addition to the eight operations, there are many options to
+@command{tar}, and three different styles for writing both: long (mnemonic)
+form, short form, and old style. These styles are discussed below.
+Both the options and the operations can be written in any of these three
+styles.
+
+@FIXME{menu at end of this node. need to think of an actual outline
+for this chapter; probably do that after stuff from chap. 4 is
+incorporated.}
+
+@node Styles
+@section The Three Option Styles
+
+There are three styles for writing operations and options to the command
+line invoking @command{tar}. The different styles were developed at
+different times during the history of @command{tar}. These styles will be
+presented below, from the most recent to the oldest.
+
+Some options must take an argument. (For example, @value{op-file} takes
+the name of an archive file as an argument. If you do not supply an
+archive file name, @command{tar} will use a default, but this can be
+confusing; thus, we recommend that you always supply a specific archive
+file name.) Where you @emph{place} the arguments generally depends on
+which style of options you choose. We will detail specific information
+relevant to each option style in the sections on the different option
+styles, below. The differences are subtle, yet can often be very
+important; incorrect option placement can cause you to overwrite a
+number of important files. We urge you to note these differences, and
+only use the option style(s) which makes the most sense to you until you
+feel comfortable with the others.
+
+@FIXME{hag to write a brief paragraph on the option(s) which can
+optionally take an argument}
+
+@menu
+* Mnemonic Options:: Mnemonic Option Style
+* Short Options:: Short Option Style
+* Old Options:: Old Option Style
+* Mixing:: Mixing Option Styles
+@end menu
+
+@node Mnemonic Options
+@subsection Mnemonic Option Style
+
+@FIXME{have to decide whether or ot to replace other occurrences of
+"mnemonic" with "long", or *ugh* vice versa.}
+
+Each option has at least one long (or mnemonic) name starting with two
+dashes in a row, e.g.@: @samp{--list}. The long names are more clear than
+their corresponding short or old names. It sometimes happens that a
+single mnemonic option has many different different names which are
+synonymous, such as @samp{--compare} and @samp{--diff}. In addition,
+long option names can be given unique abbreviations. For example,
+@samp{--cre} can be used in place of @samp{--create} because there is no
+other mnemonic option which begins with @samp{cre}. (One way to find
+this out is by trying it and seeing what happens; if a particular
+abbreviation could represent more than one option, @command{tar} will tell
+you that that abbreviation is ambiguous and you'll know that that
+abbreviation won't work. You may also choose to run @samp{tar --help}
+to see a list of options. Be aware that if you run @command{tar} with a
+unique abbreviation for the long name of an option you didn't want to
+use, you are stuck; @command{tar} will perform the command as ordered.)
+
+Mnemonic options are meant to be obvious and easy to remember, and their
+meanings are generally easier to discern than those of their
+corresponding short options (see below). For example:
+
+@example
+$ @kbd{tar --create --verbose --blocking-factor=20 --file=/dev/rmt0}
+@end example
+
+@noindent
+gives a fairly good set of hints about what the command does, even
+for those not fully acquainted with @command{tar}.
+
+Mnemonic options which require arguments take those arguments
+immediately following the option name; they are introduced by an equal
+sign. For example, the @samp{--file} option (which tells the name
+of the @command{tar} archive) is given a file such as @file{archive.tar}
+as argument by using the notation @samp{--file=archive.tar} for the
+mnemonic option.
+
+@node Short Options
+@subsection Short Option Style
+
+Most options also have a short option name. Short options start with
+a single dash, and are followed by a single character, e.g.@: @samp{-t}
+(which is equivalent to @samp{--list}). The forms are absolutely
+identical in function; they are interchangeable.
+
+The short option names are faster to type than long option names.
+
+Short options which require arguments take their arguments immediately
+following the option, usually separated by white space. It is also
+possible to stick the argument right after the short option name, using
+no intervening space. For example, you might write @w{@samp{-f
+archive.tar}} or @samp{-farchive.tar} instead of using
+@samp{--file=archive.tar}. Both @samp{--file=@var{archive-name}} and
+@w{@samp{-f @var{archive-name}}} denote the option which indicates a
+specific archive, here named @file{archive.tar}.
+
+Short options' letters may be clumped together, but you are not
+required to do this (as compared to old options; see below). When short
+options are clumped as a set, use one (single) dash for them all, e.g.@:
+@w{@samp{@command{tar} -cvf}}. Only the last option in such a set is allowed
+to have an argument@footnote{Clustering many options, the last of which
+has an argument, is a rather opaque way to write options. Some wonder if
+@sc{gnu} @code{getopt} should not even be made helpful enough for considering
+such usages as invalid.}.
+
+When the options are separated, the argument for each option which requires
+an argument directly follows that option, as is usual for Unix programs.
+For example:
+
+@example
+$ @kbd{tar -c -v -b 20 -f /dev/rmt0}
+@end example
+
+If you reorder short options' locations, be sure to move any arguments
+that belong to them. If you do not move the arguments properly, you may
+end up overwriting files.
+
+@node Old Options
+@subsection Old Option Style
+@UNREVISED
+
+Like short options, old options are single letters. However, old options
+must be written together as a single clumped set, without spaces separating
+them or dashes preceding them@footnote{Beware that if you precede options
+with a dash, you are announcing the short option style instead of the
+old option style; short options are decoded differently.}. This set
+of letters must be the first to appear on the command line, after the
+@command{tar} program name and some white space; old options cannot appear
+anywhere else. The letter of an old option is exactly the same letter as
+the corresponding short option. For example, the old option @samp{t} is
+the same as the short option @samp{-t}, and consequently, the same as the
+mnemonic option @samp{--list}. So for example, the command @w{@samp{tar
+cv}} specifies the option @samp{-v} in addition to the operation @samp{-c}.
+
+@FIXME{bob suggests having an uglier example. :-) }
+
+When options that need arguments are given together with the command,
+all the associated arguments follow, in the same order as the options.
+Thus, the example given previously could also be written in the old
+style as follows:
+
+@example
+$ @kbd{tar cvbf 20 /dev/rmt0}
+@end example
+
+@noindent
+Here, @samp{20} is the argument of @samp{-b} and @samp{/dev/rmt0} is
+the argument of @samp{-f}.
+
+On the other hand, this old style syntax makes it difficult to match
+option letters with their corresponding arguments, and is often
+confusing. In the command @w{@samp{tar cvbf 20 /dev/rmt0}}, for example,
+@samp{20} is the argument for @samp{-b}, @samp{/dev/rmt0} is the
+argument for @samp{-f}, and @samp{-v} does not have a corresponding
+argument. Even using short options like in @w{@samp{tar -c -v -b 20 -f
+/dev/rmt0}} is clearer, putting all arguments next to the option they
+pertain to.
+
+If you want to reorder the letters in the old option argument, be
+sure to reorder any corresponding argument appropriately.
+
+This old way of writing @command{tar} options can surprise even experienced
+users. For example, the two commands:
+
+@example
+@kbd{tar cfz archive.tar.gz file}
+@kbd{tar -cfz archive.tar.gz file}
+@end example
+
+@noindent
+are quite different. The first example uses @file{archive.tar.gz} as
+the value for option @samp{f} and recognizes the option @samp{z}. The
+second example, however, uses @file{z} as the value for option
+@samp{f}---probably not what was intended.
+
+Old options are kept for compatibility with old versions of @command{tar}.
+
+This second example could be corrected in many ways, among which the
+following are equivalent:
+
+@example
+@kbd{tar -czf archive.tar.gz file}
+@kbd{tar -cf archive.tar.gz -z file}
+@kbd{tar cf archive.tar.gz -z file}
+@end example
+
+@FIXME{still could explain this better; it's redundant:}
+
+@cindex option syntax, traditional
+As far as we know, all @command{tar} programs, @sc{gnu} and non-@sc{gnu}, support
+old options. @sc{gnu} @command{tar} supports them not only for historical
+reasons, but also because many people are used to them. For
+compatibility with Unix @command{tar}, the first argument is always
+treated as containing command and option letters even if it doesn't
+start with @samp{-}. Thus, @samp{tar c} is equivalent to @w{@samp{tar
+-c}:} both of them specify the @value{op-create} command to create an
+archive.
+
+@node Mixing
+@subsection Mixing Option Styles
+
+All three styles may be intermixed in a single @command{tar} command, so
+long as the rules for each style are fully respected@footnote{Before @sc{gnu}
+@command{tar} version 1.11.6, a bug prevented intermixing old style options
+with mnemonic options in some cases.}. Old style options and either of the
+modern styles of options may be mixed within a single @command{tar} command.
+However, old style options must be introduced as the first arguments only,
+following the rule for old options (old options must appear directly
+after the @command{tar} command and some white space). Modern options may
+be given only after all arguments to the old options have been collected.
+If this rule is not respected, a modern option might be falsely interpreted
+as the value of the argument to one of the old style options.
+
+For example, all the following commands are wholly equivalent, and
+illustrate the many combinations and orderings of option styles.
+
+@example
+@kbd{tar --create --file=archive.tar}
+@kbd{tar --create -f archive.tar}
+@kbd{tar --create -farchive.tar}
+@kbd{tar --file=archive.tar --create}
+@kbd{tar --file=archive.tar -c}
+@kbd{tar -c --file=archive.tar}
+@kbd{tar -c -f archive.tar}
+@kbd{tar -c -farchive.tar}
+@kbd{tar -cf archive.tar}
+@kbd{tar -cfarchive.tar}
+@kbd{tar -f archive.tar --create}
+@kbd{tar -f archive.tar -c}
+@kbd{tar -farchive.tar --create}
+@kbd{tar -farchive.tar -c}
+@kbd{tar c --file=archive.tar}
+@kbd{tar c -f archive.tar}
+@kbd{tar c -farchive.tar}
+@kbd{tar cf archive.tar}
+@kbd{tar f archive.tar --create}
+@kbd{tar f archive.tar -c}
+@kbd{tar fc archive.tar}
+@end example
+
+On the other hand, the following commands are @emph{not} equivalent to
+the previous set:
+
+@example
+@kbd{tar -f -c archive.tar}
+@kbd{tar -fc archive.tar}
+@kbd{tar -fcarchive.tar}
+@kbd{tar -farchive.tarc}
+@kbd{tar cfarchive.tar}
+@end example
+
+@noindent
+These last examples mean something completely different from what the
+user intended (judging based on the example in the previous set which
+uses long options, whose intent is therefore very clear). The first
+four specify that the @command{tar} archive would be a file named
+@samp{-c}, @samp{c}, @samp{carchive.tar} or @samp{archive.tarc},
+respectively. The first two examples also specify a single non-option,
+@var{name} argument having the value @samp{archive.tar}. The last
+example contains only old style option letters (repeating option
+@samp{c} twice), not all of which are meaningful (eg., @samp{.},
+@samp{h}, or @samp{i}), with no argument value. @FIXME{not sure i liked
+the first sentence of this paragraph..}
+
+@node All Options
+@section All @command{tar} Options
+
+The coming manual sections contain an alphabetical listing of all
+@command{tar} operations and options, with brief descriptions and cross
+references to more in-depth explanations in the body of the manual.
+They also contain an alphabetically arranged table of the short option
+forms with their corresponding long option. You can use this table as
+a reference for deciphering @command{tar} commands in scripts.
+
+@menu
+* Operation Summary::
+* Option Summary::
+* Short Option Summary::
+@end menu
+
+@node Operation Summary
+@subsection Operations
+
+@table @kbd
+
+@item --append
+@itemx -r
+
+Appends files to the end of the archive. @xref{append}.
+
+@item --catenate
+@itemx -A
+
+Same as @samp{--concatenate}. @xref{concatenate}.
+
+@item --compare
+@itemx -d
+
+Compares archive members with their counterparts in the file
+system, and reports differences in file size, mode, owner,
+modification date and contents. @xref{compare}.
+
+@item --concatenate
+@itemx -A
+
+Appends other @command{tar} archives to the end of the archive.
+@xref{concatenate}.
+
+@item --create
+@itemx -c
+
+Creates a new @command{tar} archive. @xref{create}.
+
+@item --delete
+
+Deletes members from the archive. Don't try this on a archive on a
+tape! @xref{delete}.
+
+@item --diff
+@itemx -d
+
+Same @samp{--compare}. @xref{compare}.
+
+@item --extract
+@itemx -x
+
+Extracts members from the archive into the file system. @xref{extract}.
+
+@item --get
+@itemx -x
+
+Same as @samp{--extract}. @xref{extract}.
+
+@item --list
+@itemx -t
+
+Lists the members in an archive. @xref{list}.
+
+@item --update
+@itemx -u
+
+@FIXME{It was: A combination of the @samp{--compare} and @samp{--append} operations.
+This is not true and rather misleading, as @value{op-compare}
+does a lot more than @value{op-update} for ensuring files are identical.}
+Adds files to the end of the archive, but only if they are newer than
+their counterparts already in the archive, or if they do not already
+exist in the archive.
+@xref{update}.
+
+@end table
+
+@node Option Summary
+@subsection @command{tar} Options
+
+@table @kbd
+
+@item --absolute-names
+@itemx -P
+
+Normally when creating an archive, @command{tar} strips an initial @samp{/} from
+member names. This option disables that behavior. @FIXME-xref{}
+
+@item --after-date
+
+(See @samp{--newer}.) @FIXME-pxref{}
+
+@item --anchored
+An exclude pattern must match an initial subsequence of the name's components.
+@FIXME-xref{}
+
+@item --atime-preserve
+
+Tells @command{tar} to preserve the access time field in a file's inode when
+reading it. Due to limitations in the @code{utimes} system call, the
+modification time field is also preserved, which may cause problems if
+the file is simultaneously being modified by another program.
+This option is incompatible with incremental backups, because
+preserving the access time involves updating the last-changed time.
+Also, this option does not work on files that you do not own,
+unless you're root.
+@FIXME-xref{}
+
+@item --backup=@var{backup-type}
+
+Rather than deleting files from the file system, @command{tar} will back them up
+using simple or numbered backups, depending upon @var{backup-type}.
+@FIXME-xref{}
+
+@item --block-number
+@itemx -R
+
+With this option present, @command{tar} prints error messages for read errors
+with the block number in the archive file. @FIXME-xref{}
+
+@item --blocking-factor=@var{blocking}
+@itemx -b @var{blocking}
+
+Sets the blocking factor @command{tar} uses to @var{blocking} x 512 bytes per
+record. @FIXME-xref{}
+
+@item --bzip2
+@itemx -j
+
+This option tells @command{tar} to read or write archives through @code{bzip2}.
+@FIXME-xref{}
+
+@item --checkpoint
+
+This option directs @command{tar} to print periodic checkpoint messages as it
+reads through the archive. Its intended for when you want a visual
+indication that @command{tar} is still running, but don't want to see
+@samp{--verbose} output. @FIXME-xref{}
+
+@item --compress
+@itemx --uncompress
+@itemx -Z
+
+@command{tar} will use the @command{compress} program when reading or writing the
+archive. This allows you to directly act on archives while saving
+space. @FIXME-xref{}
+
+@item --confirmation
+
+(See @samp{--interactive}.) @FIXME-pxref{}
+
+@item --dereference
+@itemx -h
+
+When creating a @command{tar} archive, @command{tar} will archive the file that a symbolic
+link points to, rather than archiving the symlink. @FIXME-xref{}
+
+@item --directory=@var{dir}
+@itemx -C @var{dir}
+
+When this option is specified, @command{tar} will change its current directory
+to @var{dir} before performing any operations. When this option is used
+during archive creation, it is order sensitive. @FIXME-xref{}
+
+@item --exclude=@var{pattern}
+
+When performing operations, @command{tar} will skip files that match
+@var{pattern}. @FIXME-xref{}
+
+@item --exclude-from=@var{file}
+@itemx -X @var{file}
+
+Similar to @samp{--exclude}, except @command{tar} will use the list of patterns
+in the file @var{file}. @FIXME-xref{}
+
+@item --file=@var{archive}
+@itemx -f @var{archive}
+
+@command{tar} will use the file @var{archive} as the @command{tar} archive it
+performs operations on, rather than @command{tar}'s compilation dependent
+default. @FIXME-xref{}
+
+@item --files-from=@var{file}
+@itemx -T @var{file}
+
+@command{tar} will use the contents of @var{file} as a list of archive members
+or files to operate on, in addition to those specified on the
+command-line. @FIXME-xref{}
+
+@item --force-local
+
+Forces @command{tar} to interpret the filename given to @samp{--file} as a local
+file, even if it looks like a remote tape drive name. @FIXME-xref{}
+
+@item --group=@var{group}
+
+Files added to the @command{tar} archive will have a group id of @var{group},
+rather than the group from the source file. @var{group} is first decoded
+as a group symbolic name, but if this interpretation fails, it has to be
+a decimal numeric group ID. @FIXME-xref{}
+
+Also see the comments for the @value{op-owner} option.
+
+@item --gunzip
+
+(See @samp{--gzip}.) @FIXME-pxref{}
+
+@item --gzip
+@itemx --gunzip
+@itemx --ungzip
+@itemx -z
+
+This option tells @command{tar} to read or write archives through @command{gzip},
+allowing @command{tar} to directly operate on several kinds of compressed
+archives transparently. @FIXME-xref{}
+
+@item --help
+
+@command{tar} will print out a short message summarizing the operations and
+options to @command{tar} and exit. @FIXME-xref{}
+
+@item --ignore-case
+Ignore case when excluding files.
+@FIXME-xref{}
+
+@item --ignore-failed-read
+
+Do not exit unsuccessfully merely because an unreadable file was encountered.
+@xref{Reading}.
+
+@item --ignore-zeros
+@itemx -i
+
+With this option, @command{tar} will ignore zeroed blocks in the archive, which
+normally signals EOF. @xref{Reading}.
+
+@item --incremental
+@itemx -G
+
+Used to inform @command{tar} that it is working with an old @sc{gnu}-format
+incremental backup archive. It is intended primarily for backwards
+compatibility only. @FIXME-xref{}
+
+@item --info-script=@var{script-file}
+@itemx --new-volume-script=@var{script-file}
+@itemx -F @var{script-file}
+
+When @command{tar} is performing multi-tape backups, @var{script-file} is run
+at the end of each tape. If @var{script-file} exits with nonzero status,
+@command{tar} fails immediately. @FIXME-xref{}
+
+@item --interactive
+@itemx --confirmation
+@itemx -w
+
+Specifies that @command{tar} should ask the user for confirmation before
+performing potentially destructive options, such as overwriting files.
+@FIXME-xref{}
+
+@item --keep-old-files
+@itemx -k
+
+Do not overwrite existing files when extracting files from an archive.
+@xref{Writing}.
+
+@item --label=@var{name}
+@itemx -V @var{name}
+
+When creating an archive, instructs @command{tar} to write @var{name} as a name
+record in the archive. When extracting or listing archives, @command{tar} will
+only operate on archives that have a label matching the pattern
+specified in @var{name}. @FIXME-xref{}
+
+@item --listed-incremental=@var{snapshot-file}
+@itemx -g @var{snapshot-file}
+
+During a @samp{--create} operation, specifies that the archive that
+@command{tar} creates is a new @sc{gnu}-format incremental backup, using
+@var{snapshot-file} to determine which files to backup.
+With other operations, informs @command{tar} that the archive is in incremental
+format. @FIXME-xref{}
+
+@item --mode=@var{permissions}
+
+When adding files to an archive, @command{tar} will use @var{permissions}
+for the archive members, rather than the permissions from the files.
+The program @command{chmod} and this @command{tar} option share the same syntax
+for what @var{permissions} might be. @xref{File permissions, Permissions,
+File permissions, fileutils, @sc{gnu} file utilities}. This reference also
+has useful information for those not being overly familiar with the Unix
+permission system.
+
+Of course, @var{permissions} might be plainly specified as an octal number.
+However, by using generic symbolic modifications to mode bits, this allows
+more flexibility. For example, the value @samp{a+rw} adds read and write
+permissions for everybody, while retaining executable bits on directories
+or on any other file already marked as executable.
+
+@item --multi-volume
+@itemx -M
+
+Informs @command{tar} that it should create or otherwise operate on a
+multi-volume @command{tar} archive. @FIXME-xref{}
+
+@item --new-volume-script
+
+(see --info-script)
+
+@item --newer=@var{date}
+@itemx --after-date=@var{date}
+@itemx -N
+
+When creating an archive, @command{tar} will only add files that have changed
+since @var{date}. If @var{date} begins with @samp{/} or @samp{.}, it
+is taken to be the name of a file whose last-modified time specifies
+the date. @FIXME-xref{}
+
+@item --newer-mtime=@var{date}
+
+Like @samp{--newer}, but add only files whose
+contents have changed (as opposed to just @samp{--newer}, which will
+also back up files for which any status information has changed).
+
+@item --no-anchored
+An exclude pattern can match any subsequence of the name's components.
+@FIXME-xref{}
+
+@item --no-ignore-case
+Use case-sensitive matching when excluding files.
+@FIXME-xref{}
+
+@item --no-recursion
+
+With this option, @command{tar} will not recurse into directories.
+@FIXME-xref{}
+
+@item --no-same-owner
+
+When extracting an archive, do not attempt to preserve the owner
+specified in the @command{tar} archive. This the default behavior
+for ordinary users; this option has an effect only for the superuser.
+
+@item --no-same-permissions
+
+When extracting an archive, subtract the user's umask from files from
+the permissions specified in the archive. This is the default behavior
+for ordinary users; this option has an effect only for the superuser.
+
+@item --no-wildcards
+Do not use wildcards when excluding files.
+@FIXME-xref{}
+
+@item --no-wildcards-match-slash
+Wildcards do not match @samp{/} when excluding files.
+@FIXME-xref{}
+
+@item --null
+
+When @command{tar} is using the @samp{--files-from} option, this option
+instructs @command{tar} to expect filenames terminated with @kbd{NUL}, so
+@command{tar} can correctly work with file names that contain newlines.
+@FIXME-xref{}
+
+@item --numeric-owner
+
+This option will notify @command{tar} that it should use numeric user and group
+IDs when creating a @command{tar} file, rather than names. @FIXME-xref{}
+
+@item --old-archive
+
+(See @samp{--portability}.) @FIXME-pxref{}
+
+@item --one-file-system
+@itemx -l
+
+Used when creating an archive. Prevents @command{tar} from recursing into
+directories that are on different file systems from the current
+directory. @FIXME-xref{}
+
+@item --overwrite
+
+Overwrite existing files and directory metadata when extracting files
+from an archive. @xref{Overwrite Old Files}.
+
+@item --overwrite-dir
+
+Overwrite the metadata of existing directories when extracting files
+from an archive. @xref{Overwrite Old Files}.
+
+@item --owner=@var{user}
+
+Specifies that @command{tar} should use @var{user} as the owner of members
+when creating archives, instead of the user associated with the source
+file. @var{user} is first decoded as a user symbolic name, but if
+this interpretation fails, it has to be a decimal numeric user ID.
+@FIXME-xref{}
+
+There is no value indicating a missing number, and @samp{0} usually means
+@code{root}. Some people like to force @samp{0} as the value to offer in
+their distributions for the owner of files, because the @code{root} user is
+anonymous anyway, so that might as well be the owner of anonymous archives.
+
+This option does not affect extraction from archives.
+
+@item --portability
+@itemx --old-archive
+@itemx -o
+
+Tells @command{tar} to create an archive that is compatible with Unix V7
+@command{tar}. @FIXME-xref{}
+
+@item --posix
+
+Instructs @command{tar} to create a @sc{posix} compliant @command{tar} archive. @FIXME-xref{}
+
+@item --preserve
+
+Synonymous with specifying both @samp{--preserve-permissions} and
+@samp{--same-order}. @FIXME-xref{}
+
+@item --preserve-order
+
+(See @samp{--same-order}; @pxref{Reading}.)
+
+@item --preserve-permissions
+@itemx --same-permissions
+@itemx -p
+
+When @command{tar} is extracting an archive, it normally subtracts the users'
+umask from the permissions specified in the archive and uses that
+number as the permissions to create the destination file. Specifying
+this option instructs @command{tar} that it should use the permissions directly
+from the archive. @xref{Writing}.
+
+@item --read-full-records
+@itemx -B
+
+Specifies that @command{tar} should reblock its input, for reading from pipes on
+systems with buggy implementations. @xref{Reading}.
+
+@item --record-size=@var{size}
+
+Instructs @command{tar} to use @var{size} bytes per record when accessing the
+archive. @FIXME-xref{}
+
+@item --recursion
+
+With this option, @command{tar} recurses into directories.
+@FIXME-xref{}
+
+@item --recursive-unlink
+
+Remove existing
+directory hierarchies before extracting directories of the same name
+from the archive. @xref{Writing}.
+
+@item --remove-files
+
+Directs @command{tar} to remove the source file from the file system after
+appending it to an archive. @FIXME-xref{}
+
+@item --rsh-command=@var{cmd}
+
+Notifies @command{tar} that is should use @var{cmd} to communicate with remote
+devices. @FIXME-xref{}
+
+@item --same-order
+@itemx --preserve-order
+@itemx -s
+
+This option is an optimization for @command{tar} when running on machines with
+small amounts of memory. It informs @command{tar} that the list of file
+arguments has already been sorted to match the order of files in the
+archive. @xref{Reading}.
+
+@item --same-owner
+
+When extracting an archive, @command{tar} will attempt to preserve the owner
+specified in the @command{tar} archive with this option present.
+This is the default behavior for the superuser; this option has an
+effect only for ordinary users. @FIXME-xref{}
+
+@item --same-permissions
+
+(See @samp{--preserve-permissions}; @pxref{Writing}.)
+
+@item --show-omitted-dirs
+
+Instructs @command{tar} to mention directories its skipping over when operating
+on a @command{tar} archive. @FIXME-xref{}
+
+@item --sparse
+@itemx -S
+
+Invokes a @sc{gnu} extension when adding files to an archive that handles
+sparse files efficiently. @FIXME-xref{}
+
+@item --starting-file=@var{name}
+@itemx -K @var{name}
+
+This option affects extraction only; @command{tar} will skip extracting
+files in the archive until it finds one that matches @var{name}.
+@xref{Scarce}.
+
+@item --suffix=@var{suffix}
+
+Alters the suffix @command{tar} uses when backing up files from the default
+@samp{~}. @FIXME-xref{}
+
+@item --tape-length=@var{num}
+@itemx -L @var{num}
+
+Specifies the length of tapes that @command{tar} is writing as being
+@w{@var{num} x 1024} bytes long. @FIXME-xref{}
+
+@item --to-stdout
+@itemx -O
+
+During extraction, @command{tar} will extract files to stdout rather than to the
+file system. @xref{Writing}.
+
+@item --totals
+
+Displays the total number of bytes written after creating an archive.
+@FIXME-xref{}
+
+@item --touch
+@itemx -m
+
+Sets the modification time of extracted files to the extraction time,
+rather than the modification time stored in the archive.
+@xref{Writing}.
+
+@item --uncompress
+
+(See @samp{--compress}.) @FIXME-pxref{}
+
+@item --ungzip
+
+(See @samp{--gzip}.) @FIXME-pxref{}
+
+@item --unlink-first
+@itemx -U
+
+Directs @command{tar} to remove the corresponding file from the file
+system before extracting it from the archive. @xref{Writing}.
+
+@item --use-compress-program=@var{prog}
+
+Instructs @command{tar} to access the archive through @var{prog}, which is
+presumed to be a compression program of some sort. @FIXME-xref{}
+
+@item --verbose
+@itemx -v
+
+Specifies that @command{tar} should be more verbose about the operations its
+performing. This option can be specified multiple times for some
+operations to increase the amount of information displayed. @FIXME-xref{}
+
+@item --verify
+@itemx -W
+
+Verifies that the archive was correctly written when creating an
+archive. @FIXME-xref{}
+
+@item --version
+
+@command{tar} will print an informational message about what version it is and a
+copyright message, some credits, and then exit. @FIXME-xref{}
+
+@item --volno-file=@var{file}
+
+Used in conjunction with @samp{--multi-volume}. @command{tar} will keep track
+of which volume of a multi-volume archive its working in @var{file}.
+@FIXME-xref{}
+
+@item --wildcards
+Use wildcards when excluding files.
+@FIXME-xref{}
+
+@item --wildcards-match-slash
+Wildcards match @samp{/} when excluding files.
+@FIXME-xref{}
+@end table
+
+@node Short Option Summary
+@subsection Short Options Cross Reference
+
+Here is an alphabetized list of all of the short option forms, matching
+them with the equivalent long option.
+
+@table @kbd
+
+@item -A
+
+@samp{--concatenate}
+
+@item -B
+
+@samp{--read-full-records}
+
+@item -C
+
+@samp{--directory}
+
+@item -F
+
+@samp{--info-script}
+
+@item -G
+
+@samp{--incremental}
+
+@item -K
+
+@samp{--starting-file}
+
+@item -L
+
+@samp{--tape-length}
+
+@item -M
+
+@samp{--multi-volume}
+
+@item -N
+
+@samp{--newer}
+
+@item -O
+
+@samp{--to-stdout}
+
+@item -P
+
+@samp{--absolute-names}
+
+@item -R
+
+@samp{--block-number}
+
+@item -S
+
+@samp{--sparse}
+
+@item -T
+
+@samp{--files-from}
+
+@item -U
+
+@samp{--unlink-first}
+
+@item -V
+
+@samp{--label}
+
+@item -W
+
+@samp{--verify}
+
+@item -X
+
+@samp{--exclude-from}
+
+@item -Z
+
+@samp{--compress}
+
+@item -b
+
+@samp{--blocking-factor}
+
+@item -c
+
+@samp{--create}
+
+@item -d
+
+@samp{--compare}
+
+@item -f
+
+@samp{--file}
+
+@item -g
+
+@samp{--listed-incremental}
+
+@item -h
+
+@samp{--dereference}
+
+@item -i
+
+@samp{--ignore-zeros}
+
+@item -k
+
+@samp{--keep-old-files}
+
+@item -l
+
+@samp{--one-file-system}
+
+@item -m
+
+@samp{--touch}
+
+@item -o
+
+@samp{--portability}
+
+@item -p
+
+@samp{--preserve-permissions}
+
+@item -r
+
+@samp{--append}
+
+@item -s
+
+@samp{--same-order}
+
+@item -t
+
+@samp{--list}
+
+@item -u
+
+@samp{--update}
+
+@item -v
+
+@samp{--verbose}
+
+@item -w
+
+@samp{--interactive}
+
+@item -x
+
+@samp{--extract}
+
+@item -z
+
+@samp{--gzip}
+
+@end table
+
+@node help
+@section @sc{gnu} @command{tar} documentation
+
+Being careful, the first thing is really checking that you are using @sc{gnu}
+@command{tar}, indeed. The @value{op-version} option will generate a message
+giving confirmation that you are using @sc{gnu} @command{tar}, with the precise
+version of @sc{gnu} @command{tar} you are using. @command{tar} identifies itself
+and prints the version number to the standard output, then immediately
+exits successfully, without doing anything else, ignoring all other
+options. For example, @w{@samp{tar --version}} might return:
+
+@example
+tar (@sc{gnu} tar) @value{VERSION}
+@end example
+
+@noindent
+The first occurrence of @samp{tar} in the result above is the program
+name in the package (for example, @command{rmt} is another program), while
+the second occurrence of @samp{tar} is the name of the package itself,
+containing possibly many programs. The package is currently named
+@samp{tar}, after the name of the main program it contains@footnote{There
+are plans to merge the @command{cpio} and @command{tar} packages into a single one
+which would be called @code{paxutils}. So, who knows if, one of this days,
+the @value{op-version} would not yield @w{@samp{tar (@sc{gnu} paxutils) 3.2}}}.
+
+Another thing you might want to do is checking the spelling or meaning
+of some particular @command{tar} option, without resorting to this manual,
+for once you have carefully read it. @sc{gnu} @command{tar} has a short help
+feature, triggerable through the @value{op-help} option. By using this
+option, @command{tar} will print a usage message listing all available
+options on standard output, then exit successfully, without doing
+anything else and ignoring all other options. Even if this is only a
+brief summary, it may be several screens long. So, if you are not
+using some kind of scrollable window, you might prefer to use something
+like:
+
+@example
+$ @kbd{tar --help | less}
+@end example
+
+@noindent
+presuming, here, that you like using @command{less} for a pager. Other
+popular pagers are @command{more} and @command{pg}. If you know about some
+@var{keyword} which interests you and do not want to read all the
+@value{op-help} output, another common idiom is doing:
+
+@example
+tar --help | grep @var{keyword}
+@end example
+
+@noindent
+for getting only the pertinent lines.
+
+The perceptive reader would have noticed some contradiction in the
+previous paragraphs. It is written that both @value{op-version} and
+@value{op-help} print something, and have all other options ignored. In
+fact, they cannot ignore each other, and one of them has to win. We do
+not specify which is stronger, here; experiment if you really wonder!
+
+The short help output is quite succinct, and you might have to get back
+to the full documentation for precise points. If you are reading this
+paragraph, you already have the @command{tar} manual in some form. This
+manual is available in printed form, as a kind of small book. It may
+printed out of the @sc{gnu} @command{tar} distribution, provided you have @TeX{}
+already installed somewhere, and a laser printer around. Just configure
+the distribution, execute the command @w{@samp{make dvi}}, then print
+@file{doc/tar.dvi} the usual way (contact your local guru to know how).
+If @sc{gnu} @command{tar} has been conveniently installed at your place, this
+manual is also available in interactive, hypertextual form as an Info
+file. Just call @w{@samp{info tar}} or, if you do not have the
+@command{info} program handy, use the Info reader provided within @sc{gnu}
+Emacs, calling @samp{tar} from the main Info menu.
+
+There is currently no @code{man} page for @sc{gnu} @command{tar}. If you observe
+such a @code{man} page on the system you are running, either it does not
+long to @sc{gnu} @command{tar}, or it has not been produced by @sc{gnu}. Currently,
+@sc{gnu} @command{tar} documentation is provided in Texinfo format only, if we
+except, of course, the short result of @kbd{tar --help}.
+
+@node verbose
+@section Checking @command{tar} progress
+
+@cindex Progress information
+@cindex Status information
+@cindex Information on progress and status of operations
+@cindex Verbose operation
+@cindex Block number where error occurred
+@cindex Error message, block number of
+@cindex Version of the @command{tar} program
+
+@cindex Getting more information during the operation
+@cindex Information during operation
+@cindex Feedback from @command{tar}
+
+Typically, @command{tar} performs most operations without reporting any
+information to the user except error messages. When using @command{tar}
+with many options, particularly ones with complicated or
+difficult-to-predict behavior, it is possible to make serious mistakes.
+@command{tar} provides several options that make observing @command{tar}
+easier. These options cause @command{tar} to print information as it
+progresses in its job, and you might want to use them just for being
+more careful about what is going on, or merely for entertaining
+yourself. If you have encountered a problem when operating on an
+archive, however, you may need more information than just an error
+message in order to solve the problem. The following options can be
+helpful diagnostic tools.
+
+Normally, the @value{op-list} command to list an archive prints just
+the file names (one per line) and the other commands are silent.
+When used with most operations, the @value{op-verbose} option causes
+@command{tar} to print the name of each file or archive member as it
+is processed. This and the other options which make @command{tar} print
+status information can be useful in monitoring @command{tar}.
+
+With @value{op-create} or @value{op-extract}, @value{op-verbose} used once
+just prints the names of the files or members as they are processed.
+Using it twice causes @command{tar} to print a longer listing (reminiscent
+of @samp{ls -l}) for each member. Since @value{op-list} already prints
+the names of the members, @value{op-verbose} used once with @value{op-list}
+causes @command{tar} to print an @samp{ls -l} type listing of the files
+in the archive. The following examples both extract members with
+long list output:
+
+@example
+$ @kbd{tar --extract --file=archive.tar --verbose --verbose}
+$ @kbd{tar xvv archive.tar}
+@end example
+
+Verbose output appears on the standard output except when an archive is
+being written to the standard output, as with @samp{tar --create
+--file=- --verbose} (@samp{tar cfv -}, or even @samp{tar cv}---if the
+installer let standard output be the default archive). In that case
+@command{tar} writes verbose output to the standard error stream.
+
+The @value{op-totals} option---which is only meaningful when used with
+@value{op-create}---causes @command{tar} to print the total
+amount written to the archive, after it has been fully created.
+
+The @value{op-checkpoint} option prints an occasional message
+as @command{tar} reads or writes the archive. In fact, it print
+directory names while reading the archive. It is designed for
+those who don't need the more detailed (and voluminous) output of
+@value{op-block-number}, but do want visual confirmation that @command{tar}
+is actually making forward progress.
+
+@FIXME{There is some confusion here. It seems that -R once wrote a
+message at @samp{every} record read or written.}
+
+The @value{op-show-omitted-dirs} option, when reading an archive---with
+@value{op-list} or @value{op-extract}, for example---causes a message
+to be printed for each directory in the archive which is skipped.
+This happens regardless of the reason for skipping: the directory might
+not have been named on the command line (implicitly or explicitly),
+it might be excluded by the use of the @value{op-exclude} option, or
+some other reason.
+
+If @value{op-block-number} is used, @command{tar} prints, along with every
+message it would normally produce, the block number within the archive
+where the message was triggered. Also, supplementary messages are
+triggered when reading blocks full of NULs, or when hitting end of file on
+the archive. As of now, if the archive if properly terminated with a NUL
+block, the reading of the file may stop before end of file is met, so the
+position of end of file will not usually show when @value{op-block-number}
+is used. Note that @sc{gnu} @command{tar} drains the archive before exiting when
+reading the archive from a pipe.
+
+This option is especially useful when reading damaged archives, since
+it helps pinpoint the damaged sections. It can also be used with
+@value{op-list} when listing a file-system backup tape, allowing you to
+choose among several backup tapes when retrieving a file later, in
+favor of the tape where the file appears earliest (closest to the
+front of the tape). @FIXME-xref{when the node name is set and the
+backup section written.}
+
+@node interactive
+@section Asking for Confirmation During Operations
+@cindex Interactive operation
+
+Typically, @command{tar} carries out a command without stopping for
+further instructions. In some situations however, you may want to
+exclude some files and archive members from the operation (for instance
+if disk or storage space is tight). You can do this by excluding
+certain files automatically (@pxref{Choosing}), or by performing
+an operation interactively, using the @value{op-interactive} option.
+@command{tar} also accepts @samp{--confirmation} for this option.
+
+When the @value{op-interactive} option is specified, before
+reading, writing, or deleting files, @command{tar} first prints a message
+for each such file, telling what operation it intends to take, then asks
+for confirmation on the terminal. The actions which require
+confirmation include adding a file to the archive, extracting a file
+from the archive, deleting a file from the archive, and deleting a file
+from disk. To confirm the action, you must type a line of input
+beginning with @samp{y}. If your input line begins with anything other
+than @samp{y}, @command{tar} skips that file.
+
+If @command{tar} is reading the archive from the standard input,
+@command{tar} opens the file @file{/dev/tty} to support the interactive
+communications.
+
+Verbose output is normally sent to standard output, separate from
+other error messages. However, if the archive is produced directly
+on standard output, then verbose output is mixed with errors on
+@code{stderr}. Producing the archive on standard output may be used
+as a way to avoid using disk space, when the archive is soon to be
+consumed by another process reading it, say. Some people felt the need
+of producing an archive on stdout, still willing to segregate between
+verbose output and error output. A possible approach would be using a
+named pipe to receive the archive, and having the consumer process to
+read from that named pipe. This has the advantage of letting standard
+output free to receive verbose output, all separate from errors.
+
+@node operations
+@chapter @sc{gnu} @command{tar} Operations
+
+@menu
+* Basic tar::
+* Advanced tar::
+* create options::
+* extract options::
+* backup::
+* Applications::
+* looking ahead::
+@end menu
+
+@node Basic tar
+@section Basic @sc{gnu} @command{tar} Operations
+
+The basic @command{tar} operations, @value{op-create}, @value{op-list} and
+@value{op-extract}, are currently presented and described in the tutorial
+chapter of this manual. This section provides some complementary notes
+for these operations.
+
+@table @asis
+@item @value{op-create}
+
+Creating an empty archive would have some kind of elegance. One can
+initialize an empty archive and later use @value{op-append} for adding
+all members. Some applications would not welcome making an exception
+in the way of adding the first archive member. On the other hand,
+many people reported that it is dangerously too easy for @command{tar}
+to destroy a magnetic tape with an empty archive@footnote{This is well
+described in @cite{Unix-haters Handbook}, by Simson Garfinkel, Daniel
+Weise & Steven Strassmann, IDG Books, ISBN 1-56884-203-1.}. The two most
+common errors are:
+
+@enumerate
+@item
+Mistakingly using @code{create} instead of @code{extract}, when the
+intent was to extract the full contents of an archive. This error
+is likely: keys @kbd{c} and @kbd{x} are right next ot each other on
+the QWERTY keyboard. Instead of being unpacked, the archive then
+gets wholly destroyed. When users speak about @dfn{exploding} an
+archive, they usually mean something else :-).
+
+@item
+Forgetting the argument to @code{file}, when the intent was to create
+an archive with a single file in it. This error is likely because a
+tired user can easily add the @kbd{f} key to the cluster of option
+letters, by the mere force of habit, without realizing the full
+consequence of doing so. The usual consequence is that the single
+file, which was meant to be saved, is rather destroyed.
+@end enumerate
+
+So, recognizing the likelihood and the catastrophical nature of these
+errors, @sc{gnu} @command{tar} now takes some distance from elegance, and
+cowardly refuses to create an archive when @value{op-create} option is
+given, there are no arguments besides options, and @value{op-files-from}
+option is @emph{not} used. To get around the cautiousness of @sc{gnu}
+@command{tar} and nevertheless create an archive with nothing in it,
+one may still use, as the value for the @value{op-files-from} option,
+a file with no names in it, as shown in the following commands:
+
+@example
+@kbd{tar --create --file=empty-archive.tar --files-from=/dev/null}
+@kbd{tar cfT empty-archive.tar /dev/null}
+@end example
+
+@item @value{op-extract}
+
+A socket is stored, within a @sc{gnu} @command{tar} archive, as a pipe.
+
+@item @value{op-list}
+
+@sc{gnu} @command{tar} now shows dates as @samp{1996-08-30}, while it used to
+show them as @samp{Aug 30 1996}. (One can revert to the old behavior by
+defining @code{USE_OLD_CTIME} in @file{src/list.c} before reinstalling.)
+But preferably, people should get used to ISO 8601 dates. Local
+American dates should be made available again with full date localization
+support, once ready. In the meantime, programs not being localizable
+for dates should prefer international dates, that's really the way to go.
+
+Look up @url{http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html} if you
+are curious, it contains a detailed explanation of the ISO 8601 standard.
+
+@end table
+
+@node Advanced tar
+@section Advanced @sc{gnu} @command{tar} Operations
+
+Now that you have learned the basics of using @sc{gnu} @command{tar}, you may
+want to learn about further ways in which @command{tar} can help you.
+
+This chapter presents five, more advanced operations which you probably
+won't use on a daily basis, but which serve more specialized functions.
+We also explain the different styles of options and why you might want
+to use one or another, or a combination of them in your @command{tar}
+commands. Additionally, this chapter includes options which allow you to
+define the output from @command{tar} more carefully, and provide help and
+error correction in special circumstances.
+
+@FIXME{check this after the chapter is actually revised to make sure
+it still introduces the info in the chapter correctly : ).}
+
+@menu
+* Operations::
+* current state::
+* append::
+* update::
+* concatenate::
+* delete::
+* compare::
+@end menu
+
+@node Operations
+@subsection The Five Advanced @command{tar} Operations
+@UNREVISED
+
+In the last chapter, you learned about the first three operations to
+@command{tar}. This chapter presents the remaining five operations to
+@command{tar}: @samp{--append}, @samp{--update}, @samp{--concatenate},
+@samp{--delete}, and @samp{--compare}.
+
+You are not likely to use these operations as frequently as those
+covered in the last chapter; however, since they perform specialized
+functions, they are quite useful when you do need to use them. We
+will give examples using the same directory and files that you created
+in the last chapter. As you may recall, the directory is called
+@file{practice}, the files are @samp{jazz}, @samp{blues}, @samp{folk},
+@samp{rock}, and the two archive files you created are
+@samp{collection.tar} and @samp{music.tar}.
+
+We will also use the archive files @samp{afiles.tar} and
+@samp{bfiles.tar}. @samp{afiles.tar} contains the members @samp{apple},
+@samp{angst}, and @samp{aspic}. @samp{bfiles.tar} contains the members
+@samp{./birds}, @samp{baboon}, and @samp{./box}.
+
+Unless we state otherwise, all practicing you do and examples you follow
+in this chapter will take place in the @file{practice} directory that
+you created in the previous chapter; see @ref{prepare for examples}.
+(Below in this section, we will remind you of the state of the examples
+where the last chapter left them.)
+
+The five operations that we will cover in this chapter are:
+
+@table @kbd
+@item --append
+@itemx -r
+Add new entries to an archive that already exists.
+@item --update
+@itemx -r
+Add more recent copies of archive members to the end of an archive, if
+they exist.
+@item --concatenate
+@itemx --catenate
+@itemx -A
+Add one or more pre-existing archives to the end of another archive.
+@item --delete
+Delete items from an archive (does not work on tapes).
+@item --compare
+@itemx --diff
+@itemx -d
+Compare archive members to their counterparts in the file system.
+@end table
+
+@node current state
+@subsection The Current State of the Practice Files
+
+Currently, the listing of the directory using @command{ls} is as follows:
+
+@example
+
+@end example
+
+@noindent
+The archive file @samp{collection.tar} looks like this:
+
+@example
+$ @kbd{tar -tvf collection.tar}
+
+@end example
+
+@noindent
+The archive file @samp{music.tar} looks like this:
+
+@example
+$ @kbd{tar -tvf music.tar}
+
+@end example
+
+@FIXME{need to fill in the above!!!}
+
+@node append
+@subsection How to Add Files to Existing Archives: @code{--append}
+@UNREVISED
+
+If you want to add files to an existing archive, you don't need to
+create a new archive; you can use @value{op-append}. The archive must
+already exist in order to use @samp{--append}. (A related operation
+is the @samp{--update} operation; you can use this to add newer
+versions of archive members to an existing archive. To learn how to
+do this with @samp{--update}, @pxref{update}.)
+
+@FIXME{Explain in second paragraph whether you can get to the previous
+version -- explain whole situation somewhat more clearly.}
+
+If you use @value{op-append} to add a file that has the same name as an
+archive member to an archive containing that archive member, then the
+old member is not deleted. What does happen, however, is somewhat
+complex. @command{tar} @emph{allows} you to have infinite numbers of files
+with the same name. Some operations treat these same-named members no
+differently than any other set of archive members: for example, if you
+view an archive with @value{op-list}, you will see all of those members
+listed, with their modification times, owners, etc.
+
+Other operations don't deal with these members as perfectly as you might
+prefer; if you were to use @value{op-extract} to extract the archive,
+only the most recently added copy of a member with the same name as four
+other members would end up in the working directory. This is because
+@samp{--extract} extracts an archive in the order the members appeared
+in the archive; the most recently archived members will be extracted
+last. Additionally, an extracted member will @emph{replace} a file of
+the same name which existed in the directory already, and @command{tar}
+will not prompt you about this. Thus, only the most recently archived
+member will end up being extracted, as it will replace the one
+extracted before it, and so on.
+
+@FIXME{ hag -- you might want to incorporate some of the above into the
+MMwtSN node; not sure. i didn't know how to make it simpler...}
+
+There are a few ways to get around this. @FIXME-xref{Multiple Members
+with the Same Name.}
+
+@cindex Members, replacing with other members
+@cindex Replacing members with other members
+If you want to replace an archive member, use @value{op-delete} to
+delete the member you want to remove from the archive, , and then use
+@samp{--append} to add the member you want to be in the archive. Note
+that you can not change the order of the archive; the most recently
+added member will still appear last. In this sense, you cannot truly
+``replace'' one member with another. (Replacing one member with another
+will not work on certain types of media, such as tapes; see @ref{delete}
+and @ref{Media}, for more information.)
+
+@menu
+* appending files:: Appending Files to an Archive
+* multiple::
+@end menu
+
+@node appending files
+@subsubsection Appending Files to an Archive
+@UNREVISED
+@cindex Adding files to an Archive
+@cindex Appending files to an Archive
+@cindex Archives, Appending files to
+
+The simplest way to add a file to an already existing archive is the
+@value{op-append} operation, which writes specified files into the
+archive whether or not they are already among the archived files.
+When you use @samp{--append}, you @emph{must} specify file name
+arguments, as there is no default. If you specify a file that already
+exists in the archive, another copy of the file will be added to the
+end of the archive. As with other operations, the member names of the
+newly added files will be exactly the same as their names given on the
+command line. The @value{op-verbose} option will print out the names
+of the files as they are written into the archive.
+
+@samp{--append} cannot be performed on some tape drives, unfortunately,
+due to deficiencies in the formats those tape drives use. The archive
+must be a valid @command{tar} archive, or else the results of using this
+operation will be unpredictable. @xref{Media}.
+
+To demonstrate using @samp{--append} to add a file to an archive,
+create a file called @file{rock} in the @file{practice} directory.
+Make sure you are in the @file{practice} directory. Then, run the
+following @command{tar} command to add @file{rock} to
+@file{collection.tar}:
+
+@example
+$ @kbd{tar --append --file=collection.tar rock}
+@end example
+
+@noindent
+If you now use the @value{op-list} operation, you will see that
+@file{rock} has been added to the archive:
+
+@example
+$ @kbd{tar --list --file=collection.tar}
+-rw-rw-rw- me user 28 1996-10-18 16:31 jazz
+-rw-rw-rw- me user 21 1996-09-23 16:44 blues
+-rw-rw-rw- me user 20 1996-09-23 16:44 folk
+-rw-rw-rw- me user 20 1996-09-23 16:44 rock
+@end example
+
+@FIXME{in theory, dan will (soon) try to turn this node into what it's
+title claims it will become...}
+
+@node multiple
+@subsubsection Multiple Files with the Same Name
+
+You can use @value{op-append} to add copies of files which have been
+updated since the archive was created. (However, we do not recommend
+doing this since there is another @command{tar} option called
+@samp{--update}; @pxref{update} for more information. We describe this
+use of @samp{--append} here for the sake of completeness.) @FIXME{is
+this really a good idea, to give this whole description for something
+which i believe is basically a Stupid way of doing something? certain
+aspects of it show ways in which tar is more broken than i'd personally
+like to admit to, specifically the last sentence. On the other hand, i
+don't think it's a good idea to be saying that re explicitly don't
+recommend using something, but i can't see any better way to deal with
+the situation.}When you extract the archive, the older version will be
+effectively lost. This works because files are extracted from an
+archive in the order in which they were archived. Thus, when the
+archive is extracted, a file archived later in time will replace a
+file of the same name which was archived earlier, even though the older
+version of the file will remain in the archive unless you delete all
+versions of the file.
+
+Supposing you change the file @file{blues} and then append the changed
+version to @file{collection.tar}. As you saw above, the original
+@file{blues} is in the archive @file{collection.tar}. If you change the
+file and append the new version of the file to the archive, there will
+be two copies in the archive. When you extract the archive, the older
+version of the file will be extracted first, and then replaced by the
+newer version when it is extracted.
+
+You can append the new, changed copy of the file @file{blues} to the
+archive in this way:
+
+@example
+$ @kbd{tar --append --verbose --file=collection.tar blues}
+blues
+@end example
+
+@noindent
+Because you specified the @samp{--verbose} option, @command{tar} has
+printed the name of the file being appended as it was acted on. Now
+list the contents of the archive:
+
+@example
+$ @kbd{tar --list --verbose --file=collection.tar}
+-rw-rw-rw- me user 28 1996-10-18 16:31 jazz
+-rw-rw-rw- me user 21 1996-09-23 16:44 blues
+-rw-rw-rw- me user 20 1996-09-23 16:44 folk
+-rw-rw-rw- me user 20 1996-09-23 16:44 rock
+-rw-rw-rw- me user 58 1996-10-24 18:30 blues
+@end example
+
+@noindent
+The newest version of @file{blues} is now at the end of the archive
+(note the different creation dates and file sizes). If you extract
+the archive, the older version of the file @file{blues} will be
+replaced by the newer version. You can confirm this by extracting
+the archive and running @samp{ls} on the directory. @xref{Writing},
+for more information. (@emph{Please note:} This is the case unless
+you employ the @value{op-backup} option. @FIXME-ref{Multiple Members
+with the Same Name}.)
+
+@node update
+@subsection Updating an Archive
+@UNREVISED
+@cindex Updating an archive
+
+In the previous section, you learned how to use @value{op-append} to add
+a file to an existing archive. A related operation is
+@value{op-update}. The @samp{--update} operation updates a @command{tar}
+archive by comparing the date of the specified archive members against
+the date of the file with the same name. If the file has been modified
+more recently than the archive member, then the newer version of the
+file is added to the archive (as with @value{op-append}).
+
+Unfortunately, you cannot use @samp{--update} with magnetic tape drives.
+The operation will fail.
+
+@FIXME{other examples of media on which --update will fail? need to ask
+charles and/or mib/thomas/dave shevett..}
+
+Both @samp{--update} and @samp{--append} work by adding to the end
+of the archive. When you extract a file from the archive, only the
+version stored last will wind up in the file system, unless you use
+the @value{op-backup} option. @FIXME-ref{Multiple Members with the
+Same Name}
+
+@menu
+* how to update::
+@end menu
+
+@node how to update
+@subsubsection How to Update an Archive Using @code{--update}
+
+You must use file name arguments with the @value{op-update} operation.
+If you don't specify any files, @command{tar} won't act on any files and
+won't tell you that it didn't do anything (which may end up confusing
+you).
+
+@FIXME{note: the above parenthetical added because in fact, this
+behavior just confused the author. :-) }
+
+To see the @samp{--update} option at work, create a new file,
+@file{classical}, in your practice directory, and some extra text to the
+file @file{blues}, using any text editor. Then invoke @command{tar} with
+the @samp{update} operation and the @value{op-verbose} option specified,
+using the names of all the files in the practice directory as file name
+arguments:
+
+@example
+$ @kbd{tar --update -v -f collection.tar blues folk rock classical}
+blues
+classical
+$
+@end example
+
+@noindent
+Because we have specified verbose mode, @command{tar} prints out the names
+of the files it is working on, which in this case are the names of the
+files that needed to be updated. If you run @samp{tar --list} and look
+at the archive, you will see @file{blues} and @file{classical} at its
+end. There will be a total of two versions of the member @samp{blues};
+the one at the end will be newer and larger, since you added text before
+updating it.
+
+(The reason @command{tar} does not overwrite the older file when updating
+it is because writing to the middle of a section of tape is a difficult
+process. Tapes are not designed to go backward. @xref{Media}, for more
+information about tapes.
+
+@value{op-update} is not suitable for performing backups for two
+reasons: it does not change directory content entries, and it lengthens
+the archive every time it is used. The @sc{gnu} @command{tar} options intended
+specifically for backups are more efficient. If you need to run
+backups, please consult @ref{Backups}.
+
+@node concatenate
+@subsection Combining Archives with @code{--concatenate}
+
+@cindex Adding archives to an archive
+@cindex Concatenating Archives
+Sometimes it may be convenient to add a second archive onto the end of
+an archive rather than adding individual files to the archive. To add
+one or more archives to the end of another archive, you should use the
+@value{op-concatenate} operation.
+
+To use @samp{--concatenate}, name the archives to be concatenated on the
+command line. (Nothing happens if you don't list any.) The members,
+and their member names, will be copied verbatim from those archives. If
+this causes multiple members to have the same name, it does not delete
+any members; all the members with the same name coexist. @FIXME-ref{For
+information on how this affects reading the archive, Multiple
+Members with the Same Name.}
+
+To demonstrate how @samp{--concatenate} works, create two small archives
+called @file{bluesrock.tar} and @file{folkjazz.tar}, using the relevant
+files from @file{practice}:
+
+@example
+$ @kbd{tar -cvf bluesrock.tar blues rock}
+blues
+classical
+$ @kbd{tar -cvf folkjazz.tar folk jazz}
+folk
+jazz
+@end example
+
+@noindent
+If you like, You can run @samp{tar --list} to make sure the archives
+contain what they are supposed to:
+
+@example
+$ @kbd{tar -tvf bluesrock.tar}
+-rw-rw-rw- melissa user 105 1997-01-21 19:42 blues
+-rw-rw-rw- melissa user 33 1997-01-20 15:34 rock
+$ @kbd{tar -tvf folkjazz.tar}
+-rw-rw-rw- melissa user 20 1996-09-23 16:44 folk
+-rw-rw-rw- melissa user 65 1997-01-30 14:15 jazz
+@end example
+
+We can concatenate these two archives with @command{tar}:
+
+@example
+$ @kbd{cd ..}
+$ @kbd{tar --concatenate --file=bluesrock.tar jazzfolk.tar}
+@end example
+
+If you now list the contents of the @file{bluesclass.tar}, you will see
+that now it also contains the archive members of @file{jazzfolk.tar}:
+
+@example
+$ @kbd{tar --list --file=bluesrock.tar}
+blues
+rock
+jazz
+folk
+@end example
+
+When you use @samp{--concatenate}, the source and target archives must
+already exist and must have been created using compatible format
+parameters. @FIXME-pxref{Matching Format Parameters}The new,
+concatenated archive will be called by the same name as the first
+archive listed on the command line. @FIXME{is there a way to specify a
+new name?}
+
+Like @value{op-append}, this operation cannot be performed on some
+tape drives, due to deficiencies in the formats those tape drives use.
+
+@cindex @code{concatenate} vs @command{cat}
+@cindex @command{cat} vs @code{concatenate}
+It may seem more intuitive to you to want or try to use @command{cat} to
+concatenate two archives instead of using the @samp{--concatenate}
+operation; after all, @command{cat} is the utility for combining files.
+
+However, @command{tar} archives incorporate an end-of-file marker which
+must be removed if the concatenated archives are to be read properly as
+one archive. @samp{--concatenate} removes the end-of-archive marker
+from the target archive before each new archive is appended. If you use
+@command{cat} to combine the archives, the result will not be a valid
+@command{tar} format archive. If you need to retrieve files from an
+archive that was added to using the @command{cat} utility, use the
+@value{op-ignore-zeros} option. @xref{Ignore Zeros}, for further
+information on dealing with archives improperly combined using the
+@command{cat} shell utility.
+
+@FIXME{this shouldn't go here. where should it go?} You must specify
+the source archives using @value{op-file} (@value{pxref-file}). If you
+do not specify the target archive, @command{tar} uses the value of the
+environment variable @env{TAPE}, or, if this has not been set, the
+default archive name.
+
+@node delete
+@subsection Removing Archive Members Using @samp{--delete}
+@UNREVISED
+@cindex Deleting files from an archive
+@cindex Removing files from an archive
+
+You can remove members from an archive by using the @value{op-delete}
+option. Specify the name of the archive with @value{op-file} and then
+specify the names of the members to be deleted; if you list no member
+names, nothing will be deleted. The @value{op-verbose} option will
+cause @command{tar} to print the names of the members as they are deleted.
+As with @value{op-extract}, you must give the exact member names when
+using @samp{tar --delete}. @samp{--delete} will remove all versions of
+the named file from the archive. The @samp{--delete} operation can run
+very slowly.
+
+Unlike other operations, @samp{--delete} has no short form.
+
+@cindex Tapes, using @code{--delete} and
+@cindex Deleting from tape archives
+This operation will rewrite the archive. You can only use
+@samp{--delete} on an archive if the archive device allows you to
+write to any point on the media, such as a disk; because of this, it
+does not work on magnetic tapes. Do not try to delete an archive member
+from a magnetic tape; the action will not succeed, and you will be
+likely to scramble the archive and damage your tape. There is no safe
+way (except by completely re-writing the archive) to delete files from
+most kinds of magnetic tape. @xref{Media}.
+
+To delete all versions of the file @file{blues} from the archive
+@file{collection.tar} in the @file{practice} directory, make sure you
+are in that directory, and then,
+
+@example
+$ @kbd{tar --list --file=collection.tar}
+blues
+folk
+jazz
+rock
+practice/blues
+practice/folk
+practice/jazz
+practice/rock
+practice/blues
+$ @kbd{tar --delete --file=collection.tar blues}
+$ @kbd{tar --list --file=collection.tar}
+folk
+jazz
+rock
+$
+@end example
+
+@FIXME{I changed the order of these nodes around and haven't had a chance
+to fix the above example's results, yet. I have to play with this and
+follow it and see what it actually does!}
+
+The @value{op-delete} option has been reported to work properly when
+@command{tar} acts as a filter from @code{stdin} to @code{stdout}.
+
+@node compare
+@subsection Comparing Archive Members with the File System
+@cindex Verifying the currency of an archive
+@UNREVISED
+
+The @samp{--compare} (@samp{-d}), or @samp{--diff} operation compares
+specified archive members against files with the same names, and then
+reports differences in file size, mode, owner, modification date and
+contents. You should @emph{only} specify archive member names, not file
+names. If you do not name any members, then @command{tar} will compare the
+entire archive. If a file is represented in the archive but does not
+exist in the file system, @command{tar} reports a difference.
+
+You have to specify the record size of the archive when modifying an
+archive with a non-default record size.
+
+@command{tar} ignores files in the file system that do not have
+corresponding members in the archive.
+
+The following example compares the archive members @file{rock},
+@file{blues} and @file{funk} in the archive @file{bluesrock.tar} with
+files of the same name in the file system. (Note that there is no file,
+@file{funk}; @command{tar} will report an error message.)
+
+@example
+$ @kbd{tar --compare --file=bluesrock.tar rock blues funk}
+rock
+blues
+tar: funk not found in archive
+@end example
+
+@noindent
+@FIXME{what does this actually depend on? i'm making a guess,
+here.}Depending on the system where you are running @command{tar} and the
+version you are running, @command{tar} may have a different error message,
+such as:
+
+@example
+funk: does not exist
+@end example
+
+@FIXME-xref{somewhere, for more information about format parameters.
+Melissa says: such as "format variations"? But why? Clearly I don't
+get it yet; I'll deal when I get to that section.}
+
+The spirit behind the @value{op-compare} option is to check whether the
+archive represents the current state of files on disk, more than validating
+the integrity of the archive media. For this later goal, @xref{verify}.
+
+@node create options
+@section Options Used by @code{--create}
+
+The previous chapter described the basics of how to use
+@value{op-create} to create an archive from a set of files.
+@xref{create}. This section described advanced options to be used with
+@samp{--create}.
+
+@menu
+* Ignore Failed Read::
+@end menu
+
+@node Ignore Failed Read
+@subsection Ignore Fail Read
+
+@table @kbd
+@item --ignore-failed-read
+Do not exit with nonzero on unreadable files or directories.
+@end table
+
+@node extract options
+@section Options Used by @code{--extract}
+@UNREVISED
+
+@FIXME{i need to get dan to go over these options with me and see if
+there's a better way of organizing them.}
+
+The previous chapter showed how to use @value{op-extract} to extract
+an archive into the filesystem. Various options cause @command{tar} to
+extract more information than just file contents, such as the owner,
+the permissions, the modification date, and so forth. This section
+presents options to be used with @samp{--extract} when certain special
+considerations arise. You may review the information presented in
+@ref{extract} for more basic information about the
+@samp{--extract} operation.
+
+@menu
+* Reading:: Options to Help Read Archives
+* Writing:: Changing How @command{tar} Writes Files
+* Scarce:: Coping with Scarce Resources
+@end menu
+
+@node Reading
+@subsection Options to Help Read Archives
+@cindex Options when reading archives
+@cindex Reading incomplete records
+@cindex Records, incomplete
+@cindex End-of-archive entries, ignoring
+@cindex Ignoring end-of-archive entries
+@cindex Large lists of file names on small machines
+@cindex Small memory
+@cindex Running out of space
+@UNREVISED
+
+Normally, @command{tar} will request data in full record increments from
+an archive storage device. If the device cannot return a full record,
+@command{tar} will report an error. However, some devices do not always
+return full records, or do not require the last record of an archive to
+be padded out to the next record boundary. To keep reading until you
+obtain a full record, or to accept an incomplete record if it contains
+an end-of-archive marker, specify the @value{op-read-full-records} option
+in conjunction with the @value{op-extract} or @value{op-list} operations.
+@value{xref-read-full-records}.
+
+The @value{op-read-full-records} option is turned on by default when
+@command{tar} reads an archive from standard input, or from a remote
+machine. This is because on BSD Unix systems, attempting to read a
+pipe returns however much happens to be in the pipe, even if it is
+less than was requested. If this option were not enabled, @command{tar}
+would fail as soon as it read an incomplete record from the pipe.
+
+If you're not sure of the blocking factor of an archive, you can
+read the archive by specifying @value{op-read-full-records} and
+@value{op-blocking-factor}, using a blocking factor larger than what the
+archive uses. This lets you avoid having to determine the blocking factor
+of an archive. @value{xref-blocking-factor}.
+
+@menu
+* read full records::
+* Ignore Zeros::
+@end menu
+
+@node read full records
+@unnumberedsubsubsec Reading Full Records
+
+@FIXME{need sentence or so of intro here}
+
+@table @kbd
+@item --read-full-records
+@item -B
+Use in conjunction with @value{op-extract} to read an archive which
+contains incomplete records, or one which has a blocking factor less
+than the one specified.
+@end table
+
+@node Ignore Zeros
+@unnumberedsubsubsec Ignoring Blocks of Zeros
+
+Normally, @command{tar} stops reading when it encounters a block of zeros
+between file entries (which usually indicates the end of the archive).
+@value{op-ignore-zeros} allows @command{tar} to completely read an archive
+which contains a block of zeros before the end (i.e.@: a damaged
+archive, or one which was created by concatenating several archives
+together).
+
+The @value{op-ignore-zeros} option is turned off by default because many
+versions of @command{tar} write garbage after the end-of-archive entry,
+since that part of the media is never supposed to be read. @sc{gnu}
+@command{tar} does not write after the end of an archive, but seeks to
+maintain compatiblity among archiving utilities.
+
+@table @kbd
+@item --ignore-zeros
+@itemx -i
+To ignore blocks of zeros (ie.@: end-of-archive entries) which may be
+encountered while reading an archive. Use in conjunction with
+@value{op-extract} or @value{op-list}.
+@end table
+
+@node Writing
+@subsection Changing How @command{tar} Writes Files
+@cindex Overwriting old files, prevention
+@cindex Protecting old files
+@cindex Modification times of extracted files
+@cindex Permissions of extracted files
+@cindex Modes of extracted files
+@cindex Writing extracted files to standard output
+@cindex Standard output, writing extracted files to
+@UNREVISED
+
+@FIXME{need to mention the brand new option, --backup}
+
+@menu
+* Dealing with Old Files::
+* Overwrite Old Files::
+* Keep Old Files::
+* Unlink First::
+* Recursive Unlink::
+* Modification Times::
+* Setting Access Permissions::
+* Writing to Standard Output::
+* remove files::
+@end menu
+
+@node Dealing with Old Files
+@unnumberedsubsubsec Options Controlling the Overwriting of Existing Files
+
+When extracting files, if @command{tar} discovers that the extracted
+file already exists, it normally replaces the file by removing it before
+extracting it, to prevent confusion in the presence of hard or symbolic
+links. (If the existing file is a symbolic link, it is removed, not
+followed.) However, if a directory cannot be removed because it is
+nonempty, @command{tar} neither removes it nor modifies its ownership,
+permissions, or time stamps.
+
+To be more cautious and prevent existing files from being replaced, use
+the @value{op-keep-old-files} option. It causes @command{tar} to refuse
+to replace or update a file that already exists, i.e., a file with the
+same name as an archive member prevents extraction of that archive
+member. Instead, it reports an error.
+
+To be more aggressive about altering existing files, use the
+@value{op-overwrite} option. It causes @command{tar} to overwrite
+existing files and to follow existing symbolic links when extracting.
+The @option{--overwrite-dir} option is somewhat more conservative than
+@value{op-overwrite}: it overwrites metadata (ownership, permission,
+etc.) for directories, but removes other files before extracting them.
+
+Some people argue that @sc{gnu} @command{tar} should not hesitate to overwrite
+files with other files when extracting. When extracting a @command{tar}
+archive, they expect to see a faithful copy of the state of the filesystem
+when the archive was created. It is debatable that this would always
+be a proper behavior. For example, suppose one has an archive in
+which @file{usr/local} is a link to @file{usr/local2}. Since then,
+maybe the site removed the link and renamed the whole hierarchy from
+@file{/usr/local2} to @file{/usr/local}. Such things happen all the time.
+I guess it would not be welcome at all that @sc{gnu} @command{tar} removes the
+whole hierarchy just to make room for the link to be reinstated (unless it
+@emph{also} simultaneously restores the full @file{/usr/local2}, of course!
+@sc{gnu} @command{tar} is indeed able to remove a whole hierarchy to reestablish a
+symbolic link, for example, but @emph{only if} @value{op-recursive-unlink}
+is specified to allow this behavior. In any case, single files are
+silently removed.
+
+Finally, the @value{op-unlink-first} option can improve performance in
+some cases by causing @command{tar} to remove files unconditionally
+before extracting them.
+
+@node Overwrite Old Files
+@unnumberedsubsubsec Overwrite Old Files
+
+@table @kbd
+@item --overwrite
+Overwrite existing files and directory metadata when extracting files
+from an archive.
+
+This
+causes @command{tar} to write extracted files into the file system without
+regard to the files already on the system; i.e., files with the same
+names as archive members are overwritten when the archive is extracted.
+It also causes @command{tar} to extract the ownership, permissions,
+and time stamps onto any preexisting files or directories.
+If the name of a corresponding file name is a symbolic link, the file
+pointed to by the symbolic link will be overwritten instead of the
+symbolic link itself (if this is possible). Moreover, special devices,
+empty directories and even symbolic links are automatically removed if
+they are in the way of extraction.
+
+Be careful when using the @value{op-overwrite} option, particularly when
+combined with the @value{op-absolute-names} option, as this combination
+can change the contents, ownership or permissions of any file on your
+system. Also, many systems do not take kindly to overwriting files that
+are currently being executed.
+
+@item --overwrite-dir
+Overwrite the metadata of directories when extracting files from an
+archive, but remove other files before extracting.
+@end table
+
+@node Keep Old Files
+@unnumberedsubsubsec Keep Old Files
+
+@table @kbd
+@item --keep-old-files
+@itemx -k
+Do not replace existing files from archive. The
+@value{op-keep-old-files} option prevents @command{tar} from replacing
+existing files with files with the same name from the archive.
+The @value{op-keep-old-files} option is meaningless with @value{op-list}.
+Prevents @command{tar} from replacing files in the file system during
+extraction.
+@end table
+
+@node Unlink First
+@unnumberedsubsubsec Unlink First
+
+@table @kbd
+@item --unlink-first
+@itemx -U
+Remove files before extracting over them.
+This can make @command{tar} run a bit faster if you know in advance
+that the extracted files all need to be removed. Normally this option
+slows @command{tar} down slightly, so it is disabled by default.
+@end table
+
+@node Recursive Unlink
+@unnumberedsubsubsec Recursive Unlink
+
+@table @kbd
+@item --recursive-unlink
+When this option is specified, try removing files and directory hierarchies
+before extracting over them. @emph{This is a dangerous option!}
+@end table
+
+If you specify the @value{op-recursive-unlink} option,
+@command{tar} removes @emph{anything} that keeps you from extracting a file
+as far as current permissions will allow it. This could include removal
+of the contents of a full directory hierarchy.
+
+@node Modification Times
+@unnumberedsubsubsec Setting Modification Times
+
+Normally, @command{tar} sets the modification times of extracted files to
+the modification times recorded for the files in the archive, but
+limits the permissions of extracted files by the current @code{umask}
+setting.
+
+To set the modification times of extracted files to the time when
+the files were extracted, use the @value{op-touch} option in
+conjunction with @value{op-extract}.
+
+@table @kbd
+@item --touch
+@itemx -m
+Sets the modification time of extracted archive members to the time
+they were extracted, not the time recorded for them in the archive.
+Use in conjunction with @value{op-extract}.
+@end table
+
+@node Setting Access Permissions
+@unnumberedsubsubsec Setting Access Permissions
+
+To set the modes (access permissions) of extracted files to those
+recorded for those files in the archive, use @samp{--same-permissions}
+in conjunction with the @value{op-extract} operation. @FIXME{Should be
+aliased to ignore-umask.}
+
+@table @kbd
+@item --preserve-permission
+@itemx --same-permission
+@itemx --ignore-umask
+@itemx -p
+Set modes of extracted archive members to those recorded in the
+archive, instead of current umask settings. Use in conjunction with
+@value{op-extract}.
+@end table
+
+@FIXME{Following paragraph needs to be rewritten: why doesn't this cat
+files together, why is this useful. is it really useful with
+more than one file?}
+
+@node Writing to Standard Output
+@unnumberedsubsubsec Writing to Standard Output
+
+To write the extracted files to the standard output, instead of
+creating the files on the file system, use @value{op-to-stdout} in
+conjunction with @value{op-extract}. This option is useful if you are
+extracting files to send them through a pipe, and do not need to
+preserve them in the file system. If you extract multiple members,
+they appear on standard output concatenated, in the order they are
+found in the archive.
+
+@table @kbd
+@item --to-stdout
+@itemx -O
+Writes files to the standard output. Used in conjunction with
+@value{op-extract}. Extract files to standard output. When this option
+is used, instead of creating the files specified, @command{tar} writes
+the contents of the files extracted to its standard output. This may
+be useful if you are only extracting the files in order to send them
+through a pipe. This option is meaningless with @value{op-list}.
+@end table
+
+@FIXME{Why would you want to do such a thing, how are files separated on
+the standard output? is this useful with more that one file? Are
+pipes the real reason?}
+
+@node remove files
+@unnumberedsubsubsec Removing Files
+
+@FIXME{the various macros in the front of the manual think that this
+option goes in this section. i have no idea; i only know it's nowhere
+else in the book...}
+
+@table @kbd
+@item --remove-files
+Remove files after adding them to the archive.
+@end table
+
+@node Scarce
+@subsection Coping with Scarce Resources
+@cindex Middle of the archive, starting in the
+@cindex Running out of space during extraction
+@cindex Disk space, running out of
+@cindex Space on the disk, recovering from lack of
+@UNREVISED
+
+@menu
+* Starting File::
+* Same Order::
+@end menu
+
+@node Starting File
+@unnumberedsubsubsec Starting File
+
+@table @kbd
+@item --starting-file=@var{name}
+@itemx -K @var{name}
+Starts an operation in the middle of an archive. Use in conjunction
+with @value{op-extract} or @value{op-list}.
+@end table
+
+If a previous attempt to extract files failed due to lack of disk
+space, you can use @value{op-starting-file} to start extracting only
+after member @var{name} of the archive. This assumes, of course, that
+there is now free space, or that you are now extracting into a
+different file system. (You could also choose to suspend @command{tar},
+remove unnecessary files from the file system, and then restart the
+same @command{tar} operation. In this case, @value{op-starting-file} is
+not necessary. @value{xref-incremental}, @value{xref-interactive},
+and @value{ref-exclude}.)
+
+@node Same Order
+@unnumberedsubsubsec Same Order
+
+@table @kbd
+@item --same-order
+@itemx --preserve-order
+@itemx -s
+To process large lists of file names on machines with small amounts of
+memory. Use in conjunction with @value{op-compare},
+@value{op-list}
+or @value{op-extract}.
+@end table
+
+@FIXME{we don't need/want --preserve to exist any more (from melissa:
+ie, don't want that *version* of the option to exist, or don't want
+the option to exist in either version?}
+
+@FIXME{i think this explanation is lacking.}
+
+The @value{op-same-order} option tells @command{tar} that the list of file
+names to be listed or extracted is sorted in the same order as the
+files in the archive. This allows a large list of names to be used,
+even on a small machine that would not otherwise be able to hold all
+the names in memory at the same time. Such a sorted list can easily be
+created by running @samp{tar -t} on the archive and editing its output.
+
+This option is probably never needed on modern computer systems.
+
+@node backup
+@section Backup options
+
+@cindex backup options
+
+@sc{gnu} @command{tar} offers options for making backups of files before writing
+new versions. These options control the details of these backups.
+They may apply to the archive itself before it is created or rewritten,
+as well as individual extracted members. Other @sc{gnu} programs (@command{cp},
+@command{install}, @command{ln}, and @command{mv}, for example) offer similar
+options.
+
+Backup options may prove unexpectedly useful when extracting archives
+containing many members having identical name, or when extracting archives
+on systems having file name limitations, making different members appear
+has having similar names through the side-effect of name truncation.
+(This is true only if we have a good scheme for truncated backup names,
+which I'm not sure at all: I suspect work is needed in this area.)
+When any existing file is backed up before being overwritten by extraction,
+then clashing files are automatically be renamed to be unique, and the
+true name is kept for only the last file of a series of clashing files.
+By using verbose mode, users may track exactly what happens.
+
+At the detail level, some decisions are still experimental, and may
+change in the future, we are waiting comments from our users. So, please
+do not learn to depend blindly on the details of the backup features.
+For example, currently, directories themselves are never renamed through
+using these options, so, extracting a file over a directory still has
+good chances to fail. Also, backup options apply to created archives,
+not only to extracted members. For created archives, backups will not
+be attempted when the archive is a block or character device, or when it
+refers to a remote file.
+
+For the sake of simplicity and efficiency, backups are made by renaming old
+files prior to creation or extraction, and not by copying. The original
+name is restored if the file creation fails. If a failure occurs after a
+partial extraction of a file, both the backup and the partially extracted
+file are kept.
+
+@table @samp
+
+@item --backup[=@var{method}]
+@opindex --backup
+@vindex VERSION_CONTROL
+@cindex backups
+Back up files that are about to be overwritten or removed.
+Without this option, the original versions are destroyed.
+
+Use @var{method} to determine the type of backups made.
+If @var{method} is not specified, use the value of the @env{VERSION_CONTROL}
+environment variable. And if @env{VERSION_CONTROL} is not set,
+use the @samp{existing} method.
+
+@vindex version-control @r{Emacs variable}
+This option corresponds to the Emacs variable @samp{version-control};
+the same values for @var{method} are accepted as in Emacs. This option
+also allows more descriptive names. The valid @var{method}s are:
+
+@table @samp
+@item t
+@itemx numbered
+@opindex numbered @r{backup method}
+Always make numbered backups.
+
+@item nil
+@itemx existing
+@opindex existing @r{backup method}
+Make numbered backups of files that already have them, simple backups
+of the others.
+
+@item never
+@itemx simple
+@opindex simple @r{backup method}
+Always make simple backups.
+
+@end table
+
+@item --suffix=@var{suffix}
+@opindex --suffix
+@cindex backup suffix
+@vindex SIMPLE_BACKUP_SUFFIX
+Append @var{suffix} to each backup file made with @samp{--backup}. If this
+option is not specified, the value of the @env{SIMPLE_BACKUP_SUFFIX}
+environment variable is used. And if @env{SIMPLE_BACKUP_SUFFIX} is not
+set, the default is @samp{~}, just as in Emacs.
+
+@end table
+
+Some people express the desire to @emph{always} use the @value{op-backup}
+option, by defining some kind of alias or script. This is not as easy
+as one may think, due to the fact that old style options should appear first
+and consume arguments a bit unpredictably for an alias or script. But,
+if you are ready to give up using old style options, you may resort to
+using something like (a Bourne shell function here):
+
+@example
+tar () @{ /usr/local/bin/tar --backup $*; @}
+@end example
+
+@node Applications
+@section Notable @command{tar} Usages
+@UNREVISED
+
+@FIXME{Using Unix file linking capability to recreate directory
+structures---linking files into one subdirectory and then
+@command{tar}ring that directory.}
+
+@FIXME{Nice hairy example using absolute-names, newer, etc.}
+
+@findex uuencode
+You can easily use archive files to transport a group of files from
+one system to another: put all relevant files into an archive on one
+computer system, transfer the archive to another system, and extract
+the contents there. The basic transfer medium might be magnetic tape,
+Internet FTP, or even electronic mail (though you must encode the
+archive with @command{uuencode} in order to transport it properly by
+mail). Both machines do not have to use the same operating system, as
+long as they both support the @command{tar} program.
+
+For example, here is how you might copy a directory's contents from
+one disk to another, while preserving the dates, modes, owners and
+link-structure of all the files therein. In this case, the transfer
+medium is a @dfn{pipe}, which is one a Unix redirection mechanism:
+
+@smallexample
+$ @kbd{cd sourcedir; tar -cf - . | (cd targetdir; tar -xf -)}
+@end smallexample
+
+@noindent
+The command also works using short option forms:
+
+@FIXME{The following using standard input/output correct??}
+@smallexample
+$ @w{@kbd{cd sourcedir; tar --create --file=- . | (cd targetdir; tar --extract --file=-)}}
+@end smallexample
+
+@noindent
+This is one of the easiest methods to transfer a @command{tar} archive.
+
+@node looking ahead
+@section Looking Ahead: The Rest of this Manual
+
+You have now seen how to use all eight of the operations available to
+@command{tar}, and a number of the possible options. The next chapter
+explains how to choose and change file and archive names, how to use
+files to store names of other files which you can then call as
+arguments to @command{tar} (this can help you save time if you expect to
+archive the same list of files a number of times), and so forth.
+@FIXME{in case it's not obvious, i'm making this up in some sense
+based on my imited memory of what the next chapter *really* does. i
+just wanted to flesh out this final section a little bit so i'd
+remember to sitck it in here. :-)}
+
+If there are too many files to conveniently list on the command line,
+you can list the names in a file, and @command{tar} will read that file.
+@value{xref-files-from}.
+
+There are various ways of causing @command{tar} to skip over some files,
+and not archive them. @xref{Choosing}.
+
+@node Backups
+@chapter Performing Backups and Restoring Files
+@UNREVISED
+
+@sc{gnu} @command{tar} is distributed along with the scripts which the Free
+Software Foundation uses for performing backups. There is no corresponding
+scripts available yet for doing restoration of files. Even if there is
+a good chance those scripts may be satisfying to you, they are not the
+only scripts or methods available for doing backups and restore. You may
+well create your own, or use more sophisticated packages dedicated to
+that purpose.
+
+Some users are enthusiastic about @code{Amanda} (The Advanced Maryland
+Automatic Network Disk Archiver), a backup system developed by James
+da Silva @file{jds@@cs.umd.edu} and available on many Unix systems.
+This is free software, and it is available at these places:
+
+@example
+http://www.cs.umd.edu/projects/amanda/amanda.html
+ftp://ftp.cs.umd.edu/pub/amanda
+@end example
+
+@ifclear PUBLISH
+
+Here is a possible plan for a future documentation about the backuping
+scripts which are provided within the @sc{gnu} @command{tar} distribution.
+
+@example
+.* dumps
+. + what are dumps
+
+. + different levels of dumps
+. - full dump = dump everything
+. - level 1, level 2 dumps etc, -
+ A level n dump dumps everything changed since the last level
+ n-1 dump (?)
+
+. + how to use scripts for dumps (ie, the concept)
+. - scripts to run after editing backup specs (details)
+
+. + Backup Specs, what is it.
+. - how to customize
+. - actual text of script [/sp/dump/backup-specs]
+
+. + Problems
+. - rsh doesn't work
+. - rtape isn't installed
+. - (others?)
+
+. + the --incremental option of tar
+
+. + tapes
+. - write protection
+. - types of media
+. : different sizes and types, useful for different things
+. - files and tape marks
+ one tape mark between files, two at end.
+. - positioning the tape
+ MT writes two at end of write,
+ backspaces over one when writing again.
+@end example
+
+@end ifclear
+
+This chapter documents both the provided FSF scripts and @command{tar}
+options which are more specific to usage as a backup tool.
+
+To @dfn{back up} a file system means to create archives that contain
+all the files in that file system. Those archives can then be used to
+restore any or all of those files (for instance if a disk crashes or a
+file is accidentally deleted). File system @dfn{backups} are also
+called @dfn{dumps}.
+
+@menu
+* Full Dumps:: Using @command{tar} to Perform Full Dumps
+* Inc Dumps:: Using @command{tar} to Perform Incremental Dumps
+* incremental and listed-incremental:: The Incremental Options
+* Backup Levels:: Levels of Backups
+* Backup Parameters:: Setting Parameters for Backups and Restoration
+* Scripted Backups:: Using the Backup Scripts
+* Scripted Restoration:: Using the Restore Script
+@end menu
+
+@node Full Dumps
+@section Using @command{tar} to Perform Full Dumps
+@UNREVISED
+
+@cindex full dumps
+@cindex dumps, full
+
+@cindex corrupted archives
+Full dumps should only be made when no other people or programs
+are modifying files in the filesystem. If files are modified while
+@command{tar} is making the backup, they may not be stored properly in
+the archive, in which case you won't be able to restore them if you
+have to. (Files not being modified are written with no trouble, and do
+not corrupt the entire archive.)
+
+You will want to use the @value{op-label} option to give the archive a
+volume label, so you can tell what this archive is even if the label
+falls off the tape, or anything like that.
+
+Unless the filesystem you are dumping is guaranteed to fit on
+one volume, you will need to use the @value{op-multi-volume} option.
+Make sure you have enough tapes on hand to complete the backup.
+
+If you want to dump each filesystem separately you will need to use
+the @value{op-one-file-system} option to prevent @command{tar} from crossing
+filesystem boundaries when storing (sub)directories.
+
+The @value{op-incremental} option is not needed, since this is a complete
+copy of everything in the filesystem, and a full restore from this
+backup would only be done onto a completely empty disk.
+
+Unless you are in a hurry, and trust the @command{tar} program (and your
+tapes), it is a good idea to use the @value{op-verify} option, to make
+sure your files really made it onto the dump properly. This will
+also detect cases where the file was modified while (or just after)
+it was being archived. Not all media (notably cartridge tapes) are
+capable of being verified, unfortunately.
+
+@value{op-listed-incremental} take a file name argument always. If the
+file doesn't exist, run a level zero dump, creating the file. If the
+file exists, uses that file to see what has changed.
+
+@value{op-incremental} @FIXME{look it up}
+
+@value{op-incremental} handle old @sc{gnu}-format incremental backup.
+
+This option should only be used when creating an incremental backup of
+a filesystem. When the @value{op-incremental} option is used, @command{tar}
+writes, at the beginning of the archive, an entry for each of the
+directories that will be operated on. The entry for a directory
+includes a list of all the files in the directory at the time the
+dump was done, and a flag for each file indicating whether the file
+is going to be put in the archive. This information is used when
+doing a complete incremental restore.
+
+Note that this option causes @command{tar} to create a non-standard
+archive that may not be readable by non-@sc{gnu} versions of the @command{tar}
+program.
+
+The @value{op-incremental} option means the archive is an incremental
+backup. Its meaning depends on the command that it modifies.
+
+If the @value{op-incremental} option is used with @value{op-list}, @command{tar}
+will list, for each directory in the archive, the list of files in
+that directory at the time the archive was created. This information
+is put out in a format that is not easy for humans to read, but which
+is unambiguous for a program: each file name is preceded by either a
+@samp{Y} if the file is present in the archive, an @samp{N} if the
+file is not included in the archive, or a @samp{D} if the file is
+a directory (and is included in the archive). Each file name is
+terminated by a null character. The last file is followed by an
+additional null and a newline to indicate the end of the data.
+
+If the @value{op-incremental} option is used with @value{op-extract}, then
+when the entry for a directory is found, all files that currently
+exist in that directory but are not listed in the archive @emph{are
+deleted from the directory}.
+
+This behavior is convenient when you are restoring a damaged file
+system from a succession of incremental backups: it restores the
+entire state of the file system to that which obtained when the backup
+was made. If you don't use @value{op-incremental}, the file system will
+probably fill up with files that shouldn't exist any more.
+
+@value{op-listed-incremental} handle new @sc{gnu}-format incremental backup.
+This option handles new @sc{gnu}-format incremental backup. It has much the
+same effect as @value{op-incremental}, but also the time when the dump
+is done and the list of directories dumped is written to the given
+@var{file}. When restoring, only files newer than the saved time are
+restored, and the directory list is used to speed up operations.
+
+@value{op-listed-incremental} acts like @value{op-incremental}, but when
+used in conjunction with @value{op-create} will also cause @command{tar} to
+use the file @var{file}, which contains information about the state
+of the filesystem at the time of the last backup, to decide which
+files to include in the archive being created. That file will then
+be updated by @command{tar}. If the file @var{file} does not exist when
+this option is specified, @command{tar} will create it, and include all
+appropriate files in the archive.
+
+The file, which is archive independent, contains the date it was last
+modified and a list of devices, inode numbers and directory names.
+@command{tar} will archive files with newer mod dates or inode change
+times, and directories with an unchanged inode number and device but
+a changed directory name. The file is updated after the files to
+be archived are determined, but before the new archive is actually
+created.
+
+@sc{gnu} @command{tar} actually writes the file twice: once before the data
+and written, and once after.
+
+@node Inc Dumps
+@section Using @command{tar} to Perform Incremental Dumps
+@UNREVISED
+
+@cindex incremental dumps
+@cindex dumps, incremental
+
+Performing incremental dumps is similar to performing full dumps,
+although a few more options will usually be needed.
+
+A standard scheme is to do a @emph{monthly} (full) dump once a month,
+a @emph{weekly} dump once a week of everything since the last monthly
+and a @emph{daily} every day of everything since the last (weekly or
+monthly) dump.
+
+Here is a sample script to dump the directory hierarchies @samp{/usr}
+and @samp{/var}.
+
+@example
+#! /bin/sh
+tar --create \
+ --blocking-factor=126 \
+ --file=/dev/rmt/0 \
+ --label="`hostname` /usr /var `date +%Y-%m-%d`" \
+ --listed-incremental=/var/log/usr-var.snar \
+ --verbose \
+ /usr /var
+@end example
+
+This script uses the file @file{/var/log/usr-var.snar} as a snapshot to
+store information about the previous tar dump.
+
+The blocking factor 126 is an attempt to make the tape drive stream.
+Some tape devices cannot handle 64 kB blocks or larger, and require the
+block size to be a multiple of 1 kB; for these devices, 126 is the
+largest blocking factor that can be used.
+
+@node incremental and listed-incremental
+@section The Incremental Options
+@UNREVISED
+
+@value{op-incremental} is used in conjunction with @value{op-create},
+@value{op-extract} or @value{op-list} when backing up and restoring file
+systems. An archive cannot be extracted or listed with the
+@value{op-incremental} option specified unless it was created with the
+option specified. This option should only be used by a script, not by
+the user, and is usually disregarded in favor of
+@value{op-listed-incremental}, which is described below.
+
+@value{op-incremental} in conjunction with @value{op-create} causes
+@command{tar} to write, at the beginning of the archive, an entry for
+each of the directories that will be archived. The entry for a
+directory includes a list of all the files in the directory at the
+time the archive was created and a flag for each file indicating
+whether or not the file is going to be put in the archive.
+
+Note that this option causes @command{tar} to create a non-standard
+archive that may not be readable by non-@sc{gnu} versions of the @command{tar}
+program.
+
+@value{op-incremental} in conjunction with @value{op-extract} causes
+@command{tar} to read the lists of directory contents previously stored
+in the archive, @emph{delete} files in the file system that did not
+exist in their directories when the archive was created, and then
+extract the files in the archive.
+
+This behavior is convenient when restoring a damaged file system from
+a succession of incremental backups: it restores the entire state of
+the file system to that which obtained when the backup was made. If
+@value{op-incremental} isn't specified, the file system will probably
+fill up with files that shouldn't exist any more.
+
+@value{op-incremental} in conjunction with @value{op-list} causes
+@command{tar} to print, for each directory in the archive, the list of
+files in that directory at the time the archive was created. This
+information is put out in a format that is not easy for humans to
+read, but which is unambiguous for a program: each file name is
+preceded by either a @samp{Y} if the file is present in the archive,
+an @samp{N} if the file is not included in the archive, or a @samp{D}
+if the file is a directory (and is included in the archive). Each
+file name is terminated by a null character. The last file is followed
+by an additional null and a newline to indicate the end of the data.
+
+@value{op-listed-incremental} acts like @value{op-incremental}, but when
+used in conjunction with @value{op-create} will also cause @command{tar}
+to use the file @var{snapshot-file}, which contains information about
+the state of the file system at the time of the last backup, to decide
+which files to include in the archive being created. That file will
+then be updated by @command{tar}. If the file @var{file} does not exist
+when this option is specified, @command{tar} will create it, and include
+all appropriate files in the archive.
+
+The file @var{file}, which is archive independent, contains the date
+it was last modified and a list of devices, inode numbers and
+directory names. @command{tar} will archive files with newer mod dates
+or inode change times, and directories with an unchanged inode number
+and device but a changed directory name. The file is updated after
+the files to be archived are determined, but before the new archive is
+actually created.
+
+Incremental dumps depend crucially on time stamps, so the results are
+unreliable if you modify a file's time stamps during dumping (e.g.@:
+with the @samp{--atime-preserve} option), or if you set the clock
+backwards.
+
+Despite it should be obvious that a device has a non-volatile value, NFS
+devices have non-dependable values when an automounter gets in the picture.
+This led to a great deal of spurious redumping in incremental dumps,
+so it is somewhat useless to compare two NFS devices numbers over time.
+So @command{tar} now considers all NFS devices as being equal when it comes
+to comparing directories; this is fairly gross, but there does not seem
+to be a better way to go.
+
+@FIXME{this section needs to be written}
+
+@node Backup Levels
+@section Levels of Backups
+@UNREVISED
+
+An archive containing all the files in the file system is called a
+@dfn{full backup} or @dfn{full dump}. You could insure your data by
+creating a full dump every day. This strategy, however, would waste a
+substantial amount of archive media and user time, as unchanged files
+are daily re-archived.
+
+It is more efficient to do a full dump only occasionally. To back up
+files between full dumps, you can a incremental dump. A @dfn{level
+one} dump archives all the files that have changed since the last full
+dump.
+
+A typical dump strategy would be to perform a full dump once a week,
+and a level one dump once a day. This means some versions of files
+will in fact be archived more than once, but this dump strategy makes
+it possible to restore a file system to within one day of accuracy by
+only extracting two archives---the last weekly (full) dump and the
+last daily (level one) dump. The only information lost would be in
+files changed or created since the last daily backup. (Doing dumps
+more than once a day is usually not worth the trouble).
+
+@sc{gnu} @command{tar} comes with scripts you can use to do full and level-one
+dumps. Using scripts (shell programs) to perform backups and
+restoration is a convenient and reliable alternative to typing out
+file name lists and @command{tar} commands by hand.
+
+Before you use these scripts, you need to edit the file
+@file{backup-specs}, which specifies parameters used by the backup
+scripts and by the restore script. @FIXME{There is no such restore
+script!}@FIXME-xref{Script Syntax}Once the backup parameters
+are set, you can perform backups or restoration by running the
+appropriate script.
+
+The name of the restore script is @code{restore}. @FIXME{There is
+no such restore script!}The names of the level one and full backup
+scripts are, respectively, @code{level-1} and @code{level-0}.
+The @code{level-0} script also exists under the name @code{weekly}, and
+the @code{level-1} under the name @code{daily}---these additional names
+can be changed according to your backup schedule. @FIXME-xref{Scripted
+Restoration, for more information on running the restoration script.}
+@FIXME-xref{Scripted Backups, for more information on running the
+backup scripts.}
+
+@emph{Please Note:} The backup scripts and the restoration scripts are
+designed to be used together. While it is possible to restore files by
+hand from an archive which was created using a backup script, and to create
+an archive by hand which could then be extracted using the restore script,
+it is easier to use the scripts.@FIXME{There is no such restore script!}
+@value{xref-incremental}, and @value{xref-listed-incremental},
+before making such an attempt.
+
+@FIXME{shorten node names}
+
+@node Backup Parameters
+@section Setting Parameters for Backups and Restoration
+@UNREVISED
+
+The file @file{backup-specs} specifies backup parameters for the
+backup and restoration scripts provided with @command{tar}. You must
+edit @file{backup-specs} to fit your system configuration and schedule
+before using these scripts.
+
+@FIXME{This about backup scripts needs to be written: BS is a shell
+script .... thus ... @file{backup-specs} is in shell script syntax.}
+
+@FIXME-xref{Script Syntax, for an explanation of this syntax.}
+
+@FIXME{Whats a parameter .... looked at by the backup scripts
+... which will be expecting to find ... now syntax ... value is linked
+to lame ... @file{backup-specs} specifies the following parameters:}
+
+@table @samp
+@item ADMINISTRATOR
+The user name of the backup administrator.
+
+@item BACKUP_HOUR
+The hour at which the backups are done. This can be a number from 0
+to 23, or the string @samp{now}.
+
+@item TAPE_FILE
+The device @command{tar} writes the archive to. This device should be
+attached to the host on which the dump scripts are run.
+
+@FIXME{examples for all ...}
+
+@item TAPE_STATUS
+The command to use to obtain the status of the archive device,
+including error count. On some tape drives there may not be such a
+command; in that case, simply use @samp{TAPE_STATUS=false}.
+
+@item BLOCKING
+The blocking factor @command{tar} will use when writing the dump archive.
+@value{xref-blocking-factor}.
+
+@item BACKUP_DIRS
+A list of file systems to be dumped. You can include any directory
+name in the list---subdirectories on that file system will be
+included, regardless of how they may look to other networked machines.
+Subdirectories on other file systems will be ignored.
+
+The host name specifies which host to run @command{tar} on, and should
+normally be the host that actually contains the file system. However,
+the host machine must have @sc{gnu} @command{tar} installed, and must be able
+to access the directory containing the backup scripts and their
+support files using the same file name that is used on the machine
+where the scripts are run (ie. what @command{pwd} will print when in that
+directory on that machine). If the host that contains the file system
+does not have this capability, you can specify another host as long as
+it can access the file system through NFS.
+
+@item BACKUP_FILES
+A list of individual files to be dumped. These should be accessible
+from the machine on which the backup script is run.
+
+@FIXME{Same file name, be specific. Through NFS ...}
+
+@end table
+
+@menu
+* backup-specs example:: An Example Text of @file{Backup-specs}
+* Script Syntax:: Syntax for @file{Backup-specs}
+@end menu
+
+@node backup-specs example
+@subsection An Example Text of @file{Backup-specs}
+@UNREVISED
+
+The following is the text of @file{backup-specs} as it appears at FSF:
+
+@example
+# site-specific parameters for file system backup.
+
+ADMINISTRATOR=friedman
+BACKUP_HOUR=1
+TAPE_FILE=/dev/nrsmt0
+TAPE_STATUS="mts -t $TAPE_FILE"
+BLOCKING=124
+BACKUP_DIRS="
+ albert:/fs/fsf
+ apple-gunkies:/gd
+ albert:/fs/gd2
+ albert:/fs/gp
+ geech:/usr/jla
+ churchy:/usr/roland
+ albert:/
+ albert:/usr
+ apple-gunkies:/
+ apple-gunkies:/usr
+ gnu:/hack
+ gnu:/u
+ apple-gunkies:/com/mailer/gnu
+ apple-gunkies:/com/archive/gnu"
+
+BACKUP_FILES="/com/mailer/aliases /com/mailer/league*[a-z]"
+
+@end example
+
+@node Script Syntax
+@subsection Syntax for @file{Backup-specs}
+@UNREVISED
+
+@file{backup-specs} is in shell script syntax. The following
+conventions should be considered when editing the script:
+@FIXME{"conventions?"}
+
+A quoted string is considered to be contiguous, even if it is on more
+than one line. Therefore, you cannot include commented-out lines
+within a multi-line quoted string. BACKUP_FILES and BACKUP_DIRS are
+the two most likely parameters to be multi-line.
+
+A quoted string typically cannot contain wildcards. In
+@file{backup-specs}, however, the parameters BACKUP_DIRS and
+BACKUP_FILES can contain wildcards.
+
+@node Scripted Backups
+@section Using the Backup Scripts
+@UNREVISED
+
+The syntax for running a backup script is:
+
+@example
+@file{script-name} [@var{time-to-be-run}]
+@end example
+
+where @var{time-to-be-run} can be a specific system time, or can be
+@kbd{now}. If you do not specify a time, the script runs at the time
+specified in @file{backup-specs}. @FIXME-pxref{Script Syntax}
+
+You should start a script with a tape or disk mounted. Once you
+start a script, it prompts you for new tapes or disks as it
+needs them. Media volumes don't have to correspond to archive
+files---a multi-volume archive can be started in the middle of a
+tape that already contains the end of another multi-volume archive.
+The @code{restore} script prompts for media by its archive volume,
+so to avoid an error message you should keep track of which tape
+(or disk) contains which volume of the archive. @FIXME{There is
+no such restore script!} @FIXME-xref{Scripted Restoration}
+@FIXME{Have file names changed?}
+
+The backup scripts write two files on the file system. The first is a
+record file in @file{/etc/tar-backup/}, which is used by the scripts
+to store and retrieve information about which files were dumped. This
+file is not meant to be read by humans, and should not be deleted by
+them. @FIXME-xref{incremental and listed-incremental, for a more
+detailed explanation of this file.}
+
+The second file is a log file containing the names of the file systems
+and files dumped, what time the backup was made, and any error
+messages that were generated, as well as how much space was left in
+the media volume after the last volume of the archive was written.
+You should check this log file after every backup. The file name is
+@file{log-@var{mmm-ddd-yyyy}-level-1} or
+@file{log-@var{mmm-ddd-yyyy}-full}.
+
+The script also prints the name of each system being dumped to the
+standard output.
+
+@node Scripted Restoration
+@section Using the Restore Script
+@UNREVISED
+
+@ifset PUBLISH
+
+The @command{tar} distribution does not provide restoring scripts.
+
+@end ifset
+
+@ifclear PUBLISH
+
+@quotation
+@strong{Warning:} The @sc{gnu} @command{tar} distribution does @emph{not}
+provide any such @code{restore} script yet. This section is only
+listed here for documentation maintenance purposes. In any case,
+all contents is subject to change as things develop.
+@end quotation
+
+@FIXME{A section on non-scripted restore may be a good idea.}
+
+To restore files that were archived using a scripted backup, use the
+@code{restore} script. The syntax for the script is:
+
+where ***** are the file systems to restore from, and
+***** is a regular expression which specifies which files to
+restore. If you specify --all, the script restores all the files
+in the file system.
+
+You should start the restore script with the media containing the
+first volume of the archive mounted. The script will prompt for other
+volumes as they are needed. If the archive is on tape, you don't need
+to rewind the tape to to its beginning---if the tape head is
+positioned past the beginning of the archive, the script will rewind
+the tape as needed. @FIXME-xref{Media, for a discussion of tape
+positioning.}
+
+If you specify @samp{--all} as the @var{files} argument, the
+@code{restore} script extracts all the files in the archived file
+system into the active file system.
+
+@quotation
+@strong{Warning:} The script will delete files from the active file
+system if they were not in the file system when the archive was made.
+@end quotation
+
+@value{xref-incremental}, and @value{ref-listed-incremental},
+for an explanation of how the script makes that determination.
+
+@FIXME{this may be an option, not a given}
+
+@end ifclear
+
+@node Choosing
+@chapter Choosing Files and Names for @command{tar}
+@UNREVISED
+
+@FIXME{Melissa (still) Doesn't Really Like This ``Intro'' Paragraph!!!}
+
+Certain options to @command{tar} enable you to specify a name for your
+archive. Other options let you decide which files to include or exclude
+from the archive, based on when or whether files were modified, whether
+the file names do or don't match specified patterns, or whether files
+are in specified directories.
+
+@menu
+* file:: Choosing the Archive's Name
+* Selecting Archive Members::
+* files:: Reading Names from a File
+* exclude:: Excluding Some Files
+* Wildcards::
+* after:: Operating Only on New Files
+* recurse:: Descending into Directories
+* one:: Crossing Filesystem Boundaries
+@end menu
+
+@node file
+@section Choosing and Naming Archive Files
+@cindex Naming an archive
+@cindex Archive Name
+@cindex Directing output
+@cindex Choosing an archive file
+@cindex Where is the archive?
+@UNREVISED
+
+@FIXME{should the title of this section actually be, "naming an
+archive"?}
+
+By default, @command{tar} uses an archive file name that was compiled when
+it was built on the system; usually this name refers to some physical
+tape drive on the machine. However, the person who installed @command{tar}
+on the system may not set the default to a meaningful value as far as
+most users are concerned. As a result, you will usually want to tell
+@command{tar} where to find (or create) the archive. The @value{op-file}
+option allows you to either specify or name a file to use as the archive
+instead of the default archive file location.
+
+@table @kbd
+@item --file=@var{archive-name}
+@itemx -f @var{archive-name}
+Name the archive to create or operate on. Use in conjunction with
+any operation.
+@end table
+
+For example, in this @command{tar} command,
+
+@example
+$ @kbd{tar -cvf collection.tar blues folk jazz}
+@end example
+
+@noindent
+@file{collection.tar} is the name of the archive. It must directly
+follow the @samp{-f} option, since whatever directly follows @samp{-f}
+@emph{will} end up naming the archive. If you neglect to specify an
+archive name, you may end up overwriting a file in the working directory
+with the archive you create since @command{tar} will use this file's name
+for the archive name.
+
+An archive can be saved as a file in the file system, sent through a
+pipe or over a network, or written to an I/O device such as a tape,
+floppy disk, or CD write drive.
+
+@cindex Writing new archives
+@cindex Archive creation
+If you do not name the archive, @command{tar} uses the value of the
+environment variable @env{TAPE} as the file name for the archive. If
+that is not available, @command{tar} uses a default, compiled-in archive
+name, usually that for tape unit zero (ie. @file{/dev/tu00}).
+@command{tar} always needs an archive name.
+
+If you use @file{-} as an @var{archive-name}, @command{tar} reads the
+archive from standard input (when listing or extracting files), or
+writes it to standard output (when creating an archive). If you use
+@file{-} as an @var{archive-name} when modifying an archive,
+@command{tar} reads the original archive from its standard input and
+writes the entire new archive to its standard output.
+
+@FIXME{might want a different example here; this is already used in
+"notable tar usages".}
+
+@example
+$ @kbd{cd sourcedir; tar -cf - . | (cd targetdir; tar -xf -)}
+@end example
+
+@FIXME{help!}
+
+@cindex Standard input and output
+@cindex tar to standard input and output
+To specify an archive file on a device attached to a remote machine,
+use the following:
+
+@example
+@kbd{--file=@var{hostname}:/@var{dev}/@var{file name}}
+@end example
+
+@noindent
+@command{tar} will complete the remote connection, if possible, and
+prompt you for a username and password. If you use
+@samp{--file=@@@var{hostname}:/@var{dev}/@var{file name}}, @command{tar}
+will complete the remote connection, if possible, using your username
+as the username on the remote machine.
+
+If the archive file name includes a colon (@samp{:}), then it is assumed
+to be a file on another machine. If the archive file is
+@samp{@var{user}@@@var{host}:@var{file}}, then @var{file} is used on the
+host @var{host}. The remote host is accessed using the @command{rsh}
+program, with a username of @var{user}. If the username is omitted
+(along with the @samp{@@} sign), then your user name will be used.
+(This is the normal @command{rsh} behavior.) It is necessary for the
+remote machine, in addition to permitting your @command{rsh} access, to
+have the @file{/usr/ucb/rmt} program installed. If you need to use a
+file whose name includes a colon, then the remote tape drive behavior
+can be inhibited by using the @value{op-force-local} option.
+
+@FIXME{i know we went over this yesterday, but bob (and now i do again,
+too) thinks it's out of the middle of nowhere. it doesn't seem to tie
+into what came before it well enough <<i moved it now, is it better
+here?>>. bob also comments that if Amanda isn't free software, we
+shouldn't mention it..}
+
+When the archive is being created to @file{/dev/null}, @sc{gnu} @command{tar}
+tries to minimize input and output operations. The Amanda backup
+system, when used with @sc{gnu} @command{tar}, has an initial sizing pass which
+uses this feature.
+
+@node Selecting Archive Members
+@section Selecting Archive Members
+@cindex Specifying files to act on
+@cindex Specifying archive members
+
+@dfn{File Name arguments} specify which files in the file system
+@command{tar} operates on, when creating or adding to an archive, or which
+archive members @command{tar} operates on, when reading or deleting from
+an archive. @xref{Operations}.
+
+To specify file names, you can include them as the last arguments on
+the command line, as follows:
+@smallexample
+@kbd{tar} @var{operation} [@var{option1} @var{option2} @dots{}] [@var{file name-1} @var{file name-2} @dots{}]
+@end smallexample
+
+If you specify a directory name as a file name argument, all the files
+in that directory are operated on by @command{tar}.
+
+If you do not specify files when @command{tar} is invoked with
+@value{op-create}, @command{tar} operates on all the non-directory files in
+the working directory. If you specify either @value{op-list} or
+@value{op-extract}, @command{tar} operates on all the archive members in the
+archive. If you specify any operation other than one of these three,
+@command{tar} does nothing.
+
+By default, @command{tar} takes file names from the command line. However,
+there are other ways to specify file or member names, or to modify the
+manner in which @command{tar} selects the files or members upon which to
+operate. @FIXME{add xref here}In general, these methods work both for
+specifying the names of files and archive members.
+
+@node files
+@section Reading Names from a File
+@UNREVISED
+
+@cindex Reading file names from a file
+@cindex Lists of file names
+@cindex File Name arguments, alternatives
+Instead of giving the names of files or archive members on the command
+line, you can put the names into a file, and then use the
+@value{op-files-from} option to @command{tar}. Give the name of the file
+which contains the list of files to include as the argument to
+@samp{--files-from}. In the list, the file names should be separated by
+newlines. You will frequently use this option when you have generated
+the list of files to archive with the @command{find} utility.
+
+@table @kbd
+@item --files-from=@var{file name}
+@itemx -T @var{file name}
+Get names to extract or create from file @var{file name}.
+@end table
+
+If you give a single dash as a file name for @samp{--files-from}, (i.e.,
+you specify either @samp{--files-from=-} or @samp{-T -}), then the file
+names are read from standard input.
+
+Unless you are running @command{tar} with @samp{--create}, you can not use
+both @samp{--files-from=-} and @samp{--file=-} (@samp{-f -}) in the same
+command.
+
+@FIXME{add bob's example, from his message on 2-10-97}
+
+The following example shows how to use @command{find} to generate a list of
+files smaller than 400K in length and put that list into a file
+called @file{small-files}. You can then use the @samp{-T} option to
+@command{tar} to specify the files from that file, @file{small-files}, to
+create the archive @file{little.tgz}. (The @samp{-z} option to
+@command{tar} compresses the archive with @command{gzip}; @pxref{gzip} for
+more information.)
+
+@example
+$ @kbd{find . -size -400 -print > small-files}
+$ @kbd{tar -c -v -z -T small-files -f little.tgz}
+@end example
+
+@noindent
+@FIXME{say more here to conclude the example/section?}
+
+@menu
+* nul::
+@end menu
+
+@node nul
+@subsection @kbd{NUL} Terminated File Names
+
+@cindex File names, terminated by @kbd{NUL}
+@cindex @kbd{NUL} terminated file names
+The @value{op-null} option causes @value{op-files-from} to read file
+names terminated by a @code{NUL} instead of a newline, so files whose
+names contain newlines can be archived using @samp{--files-from}.
+
+@table @kbd
+@item --null
+Only consider @kbd{NUL} terminated file names, instead of files that
+terminate in a newline.
+@end table
+
+The @samp{--null} option is just like the one in @sc{gnu} @command{xargs} and
+@command{cpio}, and is useful with the @samp{-print0} predicate of @sc{gnu}
+@command{find}. In @command{tar}, @samp{--null} also causes
+@value{op-directory} options to be treated as file names to archive, in
+case there are any files out there called @file{-C}.
+
+This example shows how to use @command{find} to generate a list of files
+larger than 800K in length and put that list into a file called
+@file{long-files}. The @samp{-print0} option to @command{find} just just
+like @samp{-print}, except that it separates files with a @kbd{NUL}
+rather than with a newline. You can then run @command{tar} with both the
+@samp{--null} and @samp{-T} options to specify that @command{tar} get the
+files from that file, @file{long-files}, to create the archive
+@file{big.tgz}. The @samp{--null} option to @command{tar} will cause
+@command{tar} to recognize the @kbd{NUL} separator between files.
+
+@example
+$ @kbd{find . -size +800 -print0 > long-files}
+$ @kbd{tar -c -v --null --files-from=long-files --file=big.tar}
+@end example
+
+@FIXME{say anything else here to conclude the section?}
+
+@node exclude
+@section Excluding Some Files
+@cindex File names, excluding files by
+@cindex Excluding files by name and pattern
+@cindex Excluding files by file system
+@UNREVISED
+
+To avoid operating on files whose names match a particular pattern,
+use the @value{op-exclude} or @value{op-exclude-from} options.
+
+@table @kbd
+@item --exclude=@var{pattern}
+Causes @command{tar} to ignore files that match the @var{pattern}.
+@end table
+
+@findex exclude
+The @value{op-exclude} option prevents any file or member whose name
+matches the shell wildcard (@var{pattern}) from being operated on.
+For example, to create an archive with all the contents of the directory
+@file{src} except for files whose names end in @file{.o}, use the
+command @samp{tar -cf src.tar --exclude='*.o' src}.
+
+You may give multiple @samp{--exclude} options.
+
+@table @kbd
+@item --exclude-from=@var{file}
+@itemx -X @var{file}
+Causes @command{tar} to ignore files that match the patterns listed in
+@var{file}.
+@end table
+
+@findex exclude-from
+Use the @samp{--exclude-from=@var{file-of-patterns}} option to read a
+list of patterns, one per line, from @var{file}; @command{tar} will
+ignore files matching those patterns. Thus if @command{tar} is
+called as @w{@samp{tar -c -X foo .}} and the file @file{foo} contains a
+single line @file{*.o}, no files whose names end in @file{.o} will be
+added to the archive.
+
+@FIXME{do the exclude options files need to have stuff separated by
+newlines the same as the files-from option does?}
+
+@menu
+* controlling pattern-patching with exclude::
+* problems with exclude::
+@end menu
+
+@node controlling pattern-patching with exclude
+@unnumberedsubsec Controlling Pattern-Matching with the @code{exclude} Options
+
+Normally, a pattern matches a name if an initial subsequence of the
+name's components matches the pattern, where @samp{*}, @samp{?}, and
+@samp{[...]} are the usual shell wildcards, @samp{\} escapes wildcards,
+and wildcards can match @samp{/}.
+
+Other than optionally stripping leading @samp{/} from names
+(@pxref{absolute}), patterns and names are used as-is. For
+example, trailing @samp{/} is not trimmed from a user-specified name
+before deciding whether to exclude it.
+
+However, this matching procedure can be altered by the options listed
+below. These options accumulate. For example:
+
+@example
+--ignore-case --exclude='makefile' --no-ignore-case ---exclude='readme'
+@end example
+
+ignores case when excluding @samp{makefile}, but not when excluding
+@samp{readme}.
+
+@table @option
+@item --anchored
+@itemx --no-anchored
+If anchored (the default), a pattern must match an initial subsequence
+of the name's components. Otherwise, the pattern can match any subsequence.
+
+@item --ignore-case
+@itemx --no-ignore-case
+When ignoring case, upper-case patterns match lower-case names and vice versa.
+When not ignoring case (the default), matching is case-sensitive.
+
+@item --wildcards
+@itemx --no-wildcards
+When using wildcards (the default), @samp{*}, @samp{?}, and @samp{[...]}
+are the usual shell wildcards, and @samp{\} escapes wildcards.
+Otherwise, none of these characters are special, and patterns must match
+names literally.
+
+@item --wildcards-match-slash
+@itemx --no-wildcards-match-slash
+When wildcards match slash (the default), a wildcard like @samp{*} in
+the pattern can match a @samp{/} in the name. Otherwise, @samp{/} is
+matched only by @samp{/}.
+
+@end table
+
+The @option{--recursion} and @option{--no-recursion} options
+(@pxref{recurse}) also affect how exclude patterns are interpreted. If
+recursion is in effect, a pattern excludes a name if it matches any of
+the name's parent directories.
+
+@node problems with exclude
+@unnumberedsubsec Problems with Using the @code{exclude} Options
+
+Some users find @samp{exclude} options confusing. Here are some common
+pitfalls:
+
+@itemize @bullet
+@item
+The main operating mode of @command{tar} does not act on a path name
+explicitly listed on the command line if one of its file name
+components is excluded. In the example above, if
+you create an archive and exclude files that end with @samp{*.o}, but
+explicitly name the file @samp{dir.o/foo} after all the options have been
+listed, @samp{dir.o/foo} will be excluded from the archive.
+
+@item
+You can sometimes confuse the meanings of @value{op-exclude} and
+@value{op-exclude-from}. Be careful: use @value{op-exclude} when files
+to be excluded are given as a pattern on the command line. Use
+@samp{--exclude-from=@var{file-of-patterns}} to introduce the name of a
+file which contains a list of patterns, one per line; each of these
+patterns can exclude zero, one, or many files.
+
+@item
+When you use @value{op-exclude}, be sure to quote the @var{pattern}
+parameter, so @sc{gnu} @command{tar} sees wildcard characters like @samp{*}.
+If you do not do this, the shell might expand the @samp{*} itself
+using files at hand, so @command{tar} might receive a list of files
+instead of one pattern, or none at all, making the command somewhat
+illegal. This might not correspond to what you want.
+
+For example, write:
+
+@example
+$ @kbd{tar -c -f @var{archive.tar} --exclude '*.o' @var{directory}}
+@end example
+
+@noindent
+rather than:
+
+@example
+$ @kbd{tar -c -f @var{archive.tar} --exclude *.o @var{directory}}
+@end example
+
+@item
+You must use use shell syntax, or globbing, rather than @code{regexp}
+syntax, when using exclude options in @command{tar}. If you try to use
+@code{regexp} syntax to describe files to be excluded, your command
+might fail.
+
+@item
+In earlier versions of @command{tar}, what is now the
+@samp{--exclude-from=@var{file-of-patterns}} option was called
+@samp{--exclude=@var{pattern}} instead. Now,
+@samp{--exclude=@var{pattern}} applies to patterns listed on the command
+line and @samp{--exclude-from=@var{file-of-patterns}} applies to
+patterns listed in a file.
+
+@end itemize
+
+@node Wildcards
+@section Wildcards Patterns and Matching
+
+@dfn{Globbing} is the operation by which @dfn{wildcard} characters,
+@samp{*} or @samp{?} for example, are replaced and expanded into all
+existing files matching the given pattern. However, @command{tar} often
+uses wildcard patterns for matching (or globbing) archive members instead
+of actual files in the filesystem. Wildcard patterns are also used for
+verifying volume labels of @command{tar} archives. This section has the
+purpose of explaining wildcard syntax for @command{tar}.
+
+@FIXME{the next few paragraphs need work.}
+
+A @var{pattern} should be written according to shell syntax, using wildcard
+characters to effect globbing. Most characters in the pattern stand
+for themselves in the matched string, and case is significant: @samp{a}
+will match only @samp{a}, and not @samp{A}. The character @samp{?} in the
+pattern matches any single character in the matched string. The character
+@samp{*} in the pattern matches zero, one, or more single characters in
+the matched string. The character @samp{\} says to take the following
+character of the pattern @emph{literally}; it is useful when one needs to
+match the @samp{?}, @samp{*}, @samp{[} or @samp{\} characters, themselves.
+
+The character @samp{[}, up to the matching @samp{]}, introduces a character
+class. A @dfn{character class} is a list of acceptable characters
+for the next single character of the matched string. For example,
+@samp{[abcde]} would match any of the first five letters of the alphabet.
+Note that within a character class, all of the ``special characters''
+listed above other than @samp{\} lose their special meaning; for example,
+@samp{[-\\[*?]]} would match any of the characters, @samp{-}, @samp{\},
+@samp{[}, @samp{*}, @samp{?}, or @samp{]}. (Due to parsing constraints,
+the characters @samp{-} and @samp{]} must either come @emph{first} or
+@emph{last} in a character class.)
+
+@cindex Excluding characters from a character class
+@cindex Character class, excluding characters from
+If the first character of the class after the opening @samp{[}
+is @samp{!} or @samp{^}, then the meaning of the class is reversed.
+Rather than listing character to match, it lists those characters which
+are @emph{forbidden} as the next single character of the matched string.
+
+Other characters of the class stand for themselves. The special
+construction @samp{[@var{a}-@var{e}]}, using an hyphen between two
+letters, is meant to represent all characters between @var{a} and
+@var{e}, inclusive.
+
+@FIXME{need to add a sentence or so here to make this clear for those
+who don't have dan around.}
+
+Periods (@samp{.}) or forward slashes (@samp{/}) are not considered
+special for wildcard matches. However, if a pattern completely matches
+a directory prefix of a matched string, then it matches the full matched
+string: excluding a directory also excludes all the files beneath it.
+
+There are some discussions floating in the air and asking for modifications
+in the way @sc{gnu} @command{tar} accomplishes wildcard matches. We perceive
+any change of semantics in this area as a delicate thing to impose on
+@sc{gnu} @command{tar} users. On the other hand, the @sc{gnu} project should be
+progressive enough to correct any ill design: compatibility at all price
+is not always a good attitude. In conclusion, it is @emph{possible}
+that slight amendments be later brought to the previous description.
+Your opinions on the matter are welcome.
+
+@node after
+@section Operating Only on New Files
+@cindex Excluding file by age
+@cindex Modification time, excluding files by
+@cindex Age, excluding files by
+@UNREVISED
+
+The @value{op-after-date} option causes @command{tar} to only work on files
+whose modification or inode-changed times are newer than the @var{date}
+given. If @var{date} starts with @samp{/} or @samp{.}, it is taken to
+be a file name; the last-modified time of that file is used as the date.
+If you use this option when creating or appending to an archive,
+the archive will only include new files. If you use @samp{--after-date}
+when extracting an archive, @command{tar} will only extract files newer
+than the @var{date} you specify.
+
+If you only want @command{tar} to make the date comparison based on
+modification of the actual contents of the file (rather than inode
+changes), then use the @value{op-newer-mtime} option.
+
+You may use these options with any operation. Note that these options
+differ from the @value{op-update} operation in that they allow you to
+specify a particular date against which @command{tar} can compare when
+deciding whether or not to archive the files.
+
+@table @kbd
+@item --after-date=@var{date}
+@itemx --newer=@var{date}
+@itemx -N @var{date}
+Only store files newer than @var{date}.
+
+Acts on files only if their modification or inode-changed times are
+later than @var{date}. Use in conjunction with any operation.
+
+If @var{date} starts with @samp{/} or @samp{.}, it is taken to be a file
+name; the last-modified time of that file is used as the date.
+
+@item --newer-mtime=@var{date}
+Acts like @value{op-after-date}, but only looks at modification times.
+@end table
+
+These options limit @command{tar} to only operating on files which have
+been modified after the date specified. A file is considered to have
+changed if the contents have been modified, or if the owner,
+permissions, and so forth, have been changed. (For more information on
+how to specify a date, see @ref{Date input formats}; remember that the
+entire date argument must be quoted if it contains any spaces.)
+
+Gurus would say that @value{op-after-date} tests both the @code{mtime}
+(time the contents of the file were last modified) and @code{ctime}
+(time the file's status was last changed: owner, permissions, etc)
+fields, while @value{op-newer-mtime} tests only @code{mtime} field.
+
+To be precise, @value{op-after-date} checks @emph{both} @code{mtime} and
+@code{ctime} and processes the file if either one is more recent than
+@var{date}, while @value{op-newer-mtime} only checks @code{mtime} and
+disregards @code{ctime}. Neither uses @code{atime} (the last time the
+contents of the file were looked at).
+
+Date specifiers can have embedded spaces. Because of this, you may need
+to quote date arguments to keep the shell from parsing them as separate
+arguments.
+
+@FIXME{Need example of --newer-mtime with quoted argument.}
+
+@quotation
+@strong{Please Note:} @value{op-after-date} and @value{op-newer-mtime}
+should not be used for incremental backups. Some files (such as those
+in renamed directories) are not selected properly by these options.
+@xref{incremental and listed-incremental}.
+@end quotation
+
+@noindent
+@FIXME{which tells -- need to fill this in!}
+
+@node recurse
+@section Descending into Directories
+@cindex Avoiding recursion in directories
+@cindex Descending directories, avoiding
+@cindex Directories, avoiding recursion
+@cindex Recursion in directories, avoiding
+@UNREVISED
+
+@FIXME{arrggh! this is still somewhat confusing to me. :-< }
+
+@FIXME{show dan bob's comments, from 2-10-97}
+
+Usually, @command{tar} will recursively explore all directories (either
+those given on the command line or through the @value{op-files-from}
+option) for the various files they contain. However, you may not always
+want @command{tar} to act this way.
+
+The @value{op-no-recursion} option inhibits @command{tar}'s recursive descent
+into specified directories. If you specify @samp{--no-recursion}, you can
+use the @command{find} utility for hunting through levels of directories to
+construct a list of file names which you could then pass to @command{tar}.
+@command{find} allows you to be more selective when choosing which files to
+archive; see @ref{files} for more information on using @command{find} with
+@command{tar}, or look.
+
+@table @kbd
+@item --no-recursion
+Prevents @command{tar} from recursively descending directories.
+
+@item --recursion
+Requires @command{tar} to recursively descend directories.
+This is the default.
+@end table
+
+When you use @samp{--no-recursion}, @sc{gnu} @command{tar} grabs directory entries
+themselves, but does not descend on them recursively. Many people use
+@command{find} for locating files they want to back up, and since
+@command{tar} @emph{usually} recursively descends on directories, they have
+to use the @samp{@w{! -d}} option to @command{find} @FIXME{needs more
+explanation or a cite to another info file}as they usually do not want
+all the files in a directory. They then use the @value{op-files-from}
+option to archive the files located via @command{find}.
+
+The problem when restoring files archived in this manner is that the
+directories themselves are not in the archive; so the
+@value{op-same-permissions} option does not affect them---while users
+might really like it to. Specifying @value{op-no-recursion} is a way to
+tell @command{tar} to grab only the directory entries given to it, adding
+no new files on its own.
+
+The @value{op-no-recursion} option also applies when extracting: it
+causes @command{tar} to extract only the matched directory entries, not
+the files under those directories.
+
+The @value{op-no-recursion} option also affects how exclude patterns
+are interpreted (@pxref{controlling pattern-patching with exclude}).
+
+@FIXME{example here}
+
+@node one
+@section Crossing Filesystem Boundaries
+@cindex File system boundaries, not crossing
+@UNREVISED
+
+@command{tar} will normally automatically cross file system boundaries in
+order to archive files which are part of a directory tree. You can
+change this behavior by running @command{tar} and specifying
+@value{op-one-file-system}. This option only affects files that are
+archived because they are in a directory that is being archived;
+@command{tar} will still archive files explicitly named on the command line
+or through @value{op-files-from}, regardless of where they reside.
+
+@table @kbd
+@item --one-file-system
+@itemx -l
+Prevents @command{tar} from crossing file system boundaries when
+archiving. Use in conjunction with any write operation.
+@end table
+
+The @samp{--one-file-system} option causes @command{tar} to modify its
+normal behavior in archiving the contents of directories. If a file in
+a directory is not on the same filesystem as the directory itself, then
+@command{tar} will not archive that file. If the file is a directory
+itself, @command{tar} will not archive anything beneath it; in other words,
+@command{tar} will not cross mount points.
+
+It is reported that using this option, the mount point is is archived,
+but nothing under it.
+
+This option is useful for making full or incremental archival backups of
+a file system. If this option is used in conjunction with
+@value{op-verbose}, files that are excluded are mentioned by name on the
+standard error.
+
+@menu
+* directory:: Changing Directory
+* absolute:: Absolute File Names
+@end menu
+
+@node directory
+@subsection Changing the Working Directory
+
+@FIXME{need to read over this node now for continuity; i've switched
+things around some.}
+
+@cindex Changing directory mid-stream
+@cindex Directory, changing mid-stream
+@cindex Working directory, specifying
+@UNREVISED
+
+To change the working directory in the middle of a list of file names,
+either on the command line or in a file specified using
+@value{op-files-from}, use @value{op-directory}. This will change the
+working directory to the directory @var{directory} after that point in
+the list.
+
+@table @kbd
+@item --directory=@var{directory}
+@itemx -C @var{directory}
+Changes the working directory in the middle of a command line.
+@end table
+
+For example,
+
+@example
+$ @kbd{tar -c -f jams.tar grape prune -C food cherry}
+@end example
+
+@noindent
+will place the files @file{grape} and @file{prune} from the current
+directory into the archive @file{jams.tar}, followed by the file
+@file{cherry} from the directory @file{food}. This option is especially
+useful when you have several widely separated files that you want to
+store in the same archive.
+
+Note that the file @file{cherry} is recorded in the archive under the
+precise name @file{cherry}, @emph{not} @file{food/cherry}. Thus, the
+archive will contain three files that all appear to have come from the
+same directory; if the archive is extracted with plain @samp{tar
+--extract}, all three files will be written in the current directory.
+
+Contrast this with the command,
+
+@example
+$ @kbd{tar -c -f jams.tar grape prune -C food red/cherry}
+@end example
+
+@noindent
+which records the third file in the archive under the name
+@file{red/cherry} so that, if the archive is extracted using
+@samp{tar --extract}, the third file will be written in a subdirectory
+named @file{orange-colored}.
+
+You can use the @samp{--directory} option to make the archive
+independent of the original name of the directory holding the files.
+The following command places the files @file{/etc/passwd},
+@file{/etc/hosts}, and @file{/lib/libc.a} into the archive
+@file{foo.tar}:
+
+@example
+$ @kbd{tar -c -f foo.tar -C /etc passwd hosts -C /lib libc.a}
+@end example
+
+@noindent
+However, the names of the archive members will be exactly what they were
+on the command line: @file{passwd}, @file{hosts}, and @file{libc.a}.
+They will not appear to be related by file name to the original
+directories where those files were located.
+
+Note that @samp{--directory} options are interpreted consecutively. If
+@samp{--directory} specifies a relative file name, it is interpreted
+relative to the then current directory, which might not be the same as
+the original current working directory of @command{tar}, due to a previous
+@samp{--directory} option.
+
+@FIXME{dan: does this mean that you *can* use the short option form, but
+you can *not* use the long option form with --files-from? or is this
+totally screwed?}
+
+When using @samp{--files-from} (@pxref{files}), you can put @samp{-C}
+options in the file list. Unfortunately, you cannot put
+@samp{--directory} options in the file list. (This interpretation can
+be disabled by using the @value{op-null} option.)
+
+@node absolute
+@subsection Absolute File Names
+@UNREVISED
+
+@table @kbd
+@item -P
+@itemx --absolute-names
+Do not strip leading slashes from file names, and permit file names
+containing a @file{..} file name component.
+@end table
+
+By default, @sc{gnu} @command{tar} drops a leading @samp{/} on input or output,
+and complains about file names containing a @file{..} component.
+This option turns off this behavior.
+
+When @command{tar} extracts archive members from an archive, it strips any
+leading slashes (@samp{/}) from the member name. This causes absolute
+member names in the archive to be treated as relative file names. This
+allows you to have such members extracted wherever you want, instead of
+being restricted to extracting the member in the exact directory named
+in the archive. For example, if the archive member has the name
+@file{/etc/passwd}, @command{tar} will extract it as if the name were
+really @file{etc/passwd}.
+
+File names containing @file{..} can cause problems when extracting, so
+@command{tar} normally warns you about such files when creating an
+archive, and rejects attempts to extracts such files.
+
+Other @command{tar} programs do not do this. As a result, if you create an
+archive whose member names start with a slash, they will be difficult
+for other people with a non-@sc{gnu} @command{tar} program to use. Therefore,
+@sc{gnu} @command{tar} also strips leading slashes from member names when
+putting members into the archive. For example, if you ask @command{tar} to
+add the file @file{/bin/ls} to an archive, it will do so, but the member
+name will be @file{bin/ls}.
+
+If you use the @value{op-absolute-names} option, @command{tar} will do
+none of these transformations.
+
+To archive or extract files relative to the root directory, specify
+the @value{op-absolute-names} option.
+
+Normally, @command{tar} acts on files relative to the working
+directory---ignoring superior directory names when archiving, and
+ignoring leading slashes when extracting.
+
+When you specify @value{op-absolute-names}, @command{tar} stores file names
+including all superior directory names, and preserves leading slashes.
+If you only invoked @command{tar} from the root directory you would never
+need the @value{op-absolute-names} option, but using this option may be
+more convenient than switching to root.
+
+@FIXME{Should be an example in the tutorial/wizardry section using this
+to transfer files between systems.}
+
+@FIXME{Is write access an issue?}
+
+@table @kbd
+@item --absolute-names
+Preserves full file names (including superior directory names) when
+archiving files. Preserves leading slash when extracting files.
+
+@end table
+
+@FIXME{this is still horrible; need to talk with dan on monday.}
+
+@command{tar} prints out a message about removing the @samp{/} from file
+names. This message appears once per @sc{gnu} @command{tar} invocation. It
+represents something which ought to be told; ignoring what it means can
+cause very serious surprises, later.
+
+Some people, nevertheless, do not want to see this message. Wanting to
+play really dangerously, one may of course redirect @command{tar} standard
+error to the sink. For example, under @command{sh}:
+
+@example
+$ @kbd{tar -c -f archive.tar /home 2> /dev/null}
+@end example
+
+@noindent
+Another solution, both nicer and simpler, would be to change to
+the @file{/} directory first, and then avoid absolute notation.
+For example:
+
+@example
+$ @kbd{(cd / && tar -c -f archive.tar home)}
+$ @kbd{tar -c -f archive.tar -C / home}
+@end example
+
+@include getdate.texi
+
+@node Formats
+@chapter Controlling the Archive Format
+
+@FIXME{need an intro here}
+
+@menu
+* Portability:: Making @command{tar} Archives More Portable
+* Compression:: Using Less Space through Compression
+* Attributes:: Handling File Attributes
+* Standard:: The Standard Format
+* Extensions:: @sc{gnu} Extensions to the Archive Format
+* cpio:: Comparison of @command{tar} and @command{cpio}
+@end menu
+
+@node Portability
+@section Making @command{tar} Archives More Portable
+
+Creating a @command{tar} archive on a particular system that is meant to be
+useful later on many other machines and with other versions of @command{tar}
+is more challenging than you might think. @command{tar} archive formats
+have been evolving since the first versions of Unix. Many such formats
+are around, and are not always compatible with each other. This section
+discusses a few problems, and gives some advice about making @command{tar}
+archives more portable.
+
+One golden rule is simplicity. For example, limit your @command{tar}
+archives to contain only regular files and directories, avoiding
+other kind of special files. Do not attempt to save sparse files or
+contiguous files as such. Let's discuss a few more problems, in turn.
+
+@menu
+* Portable Names:: Portable Names
+* dereference:: Symbolic Links
+* old:: Old V7 Archives
+* posix:: @sc{posix} archives
+* Checksumming:: Checksumming Problems
+* Large or Negative Values:: Large files, negative time stamps, etc.
+@end menu
+
+@node Portable Names
+@subsection Portable Names
+
+Use portable file and member names. A name is portable if it contains
+only ASCII letters and digits, @samp{/}, @samp{.}, @samp{_}, and
+@samp{-}; it cannot be empty, start with @samp{-} or @samp{//}, or
+contain @samp{/-}. Avoid deep directory nesting. For portability to
+old Unix hosts, limit your file name components to 14 characters or
+less.
+
+If you intend to have your @command{tar} archives to be read under MSDOS,
+you should not rely on case distinction for file names, and you might
+use the @sc{gnu} @command{doschk} program for helping you further diagnosing
+illegal MSDOS names, which are even more limited than System V's.
+
+@node dereference
+@subsection Symbolic Links
+@cindex File names, using symbolic links
+@cindex Symbolic link as file name
+
+Normally, when @command{tar} archives a symbolic link, it writes a
+block to the archive naming the target of the link. In that way, the
+@command{tar} archive is a faithful record of the filesystem contents.
+@value{op-dereference} is used with @value{op-create}, and causes @command{tar}
+to archive the files symbolic links point to, instead of the links
+themselves. When this option is used, when @command{tar} encounters a
+symbolic link, it will archive the linked-to file, instead of simply
+recording the presence of a symbolic link.
+
+The name under which the file is stored in the file system is not
+recorded in the archive. To record both the symbolic link name and
+the file name in the system, archive the file under both names. If
+all links were recorded automatically by @command{tar}, an extracted file
+might be linked to a file name that no longer exists in the file
+system.
+
+If a linked-to file is encountered again by @command{tar} while creating
+the same archive, an entire second copy of it will be stored. (This
+@emph{might} be considered a bug.)
+
+So, for portable archives, do not archive symbolic links as such,
+and use @value{op-dereference}: many systems do not support
+symbolic links, and moreover, your distribution might be unusable if
+it contains unresolved symbolic links.
+
+@node old
+@subsection Old V7 Archives
+@cindex Format, old style
+@cindex Old style format
+@cindex Old style archives
+
+Certain old versions of @command{tar} cannot handle additional
+information recorded by newer @command{tar} programs. To create an
+archive in V7 format (not ANSI), which can be read by these old
+versions, specify the @value{op-old-archive} option in
+conjunction with the @value{op-create}. @command{tar} also
+accepts @samp{--portability} for this option. When you specify it,
+@command{tar} leaves out information about directories, pipes, fifos,
+contiguous files, and device files, and specifies file ownership by
+group and user IDs instead of group and user names.
+
+When updating an archive, do not use @value{op-old-archive}
+unless the archive was created with using this option.
+
+In most cases, a @emph{new} format archive can be read by an @emph{old}
+@command{tar} program without serious trouble, so this option should
+seldom be needed. On the other hand, most modern @command{tar}s are
+able to read old format archives, so it might be safer for you to
+always use @value{op-old-archive} for your distributions.
+
+@node posix
+@subsection @sc{gnu} @command{tar} and @sc{posix} @command{tar}
+
+@sc{gnu} @command{tar} was based on an early draft of the @sc{posix} 1003.1
+@code{ustar} standard. @sc{gnu} extensions to @command{tar}, such as the
+support for file names longer than 100 characters, use portions of the
+@command{tar} header record which were specified in that @sc{posix} draft as
+unused. Subsequent changes in @sc{posix} have allocated the same parts of
+the header record for other purposes. As a result, @sc{gnu} @command{tar} is
+incompatible with the current @sc{posix} spec, and with @command{tar} programs
+that follow it.
+
+We plan to reimplement these @sc{gnu} extensions in a new way which is
+upward compatible with the latest @sc{posix} @command{tar} format, but we
+don't know when this will be done.
+
+In the mean time, there is simply no telling what might happen if you
+read a @sc{gnu} @command{tar} archive, which uses the @sc{gnu} extensions, using
+some other @command{tar} program. So if you want to read the archive
+with another @command{tar} program, be sure to write it using the
+@samp{--old-archive} option (@samp{-o}).
+
+@FIXME{is there a way to tell which flavor of tar was used to write a
+particular archive before you try to read it?}
+
+Traditionally, old @command{tar}s have a limit of 100 characters. @sc{gnu}
+@command{tar} attempted two different approaches to overcome this limit,
+using and extending a format specified by a draft of some P1003.1.
+The first way was not that successful, and involved @file{@@MaNgLeD@@}
+file names, or such; while a second approach used @file{././@@LongLink}
+and other tricks, yielding better success. In theory, @sc{gnu} @command{tar}
+should be able to handle file names of practically unlimited length.
+So, if @sc{gnu} @command{tar} fails to dump and retrieve files having more
+than 100 characters, then there is a bug in @sc{gnu} @command{tar}, indeed.
+
+But, being strictly @sc{posix}, the limit was still 100 characters.
+For various other purposes, @sc{gnu} @command{tar} used areas left unassigned
+in the @sc{posix} draft. @sc{posix} later revised P1003.1 @code{ustar} format by
+assigning previously unused header fields, in such a way that the upper
+limit for file name length was raised to 256 characters. However, the
+actual @sc{posix} limit oscillates between 100 and 256, depending on the
+precise location of slashes in full file name (this is rather ugly).
+Since @sc{gnu} @command{tar} use the same fields for quite other purposes,
+it became incompatible with the latest @sc{posix} standards.
+
+For longer or non-fitting file names, we plan to use yet another set
+of @sc{gnu} extensions, but this time, complying with the provisions @sc{posix}
+offers for extending the format, rather than conflicting with it.
+Whenever an archive uses old @sc{gnu} @command{tar} extension format or @sc{posix}
+extensions, would it be for very long file names or other specialities,
+this archive becomes non-portable to other @command{tar} implementations.
+In fact, anything can happen. The most forgiving @command{tar}s will
+merely unpack the file using a wrong name, and maybe create another
+file named something like @file{@@LongName}, with the true file name
+in it. @command{tar}s not protecting themselves may segment violate!
+
+Compatibility concerns make all this thing more difficult, as we
+will have to support @emph{all} these things together, for a while.
+@sc{gnu} @command{tar} should be able to produce and read true @sc{posix} format
+files, while being able to detect old @sc{gnu} @command{tar} formats, besides
+old V7 format, and process them conveniently. It would take years
+before this whole area stabilizes@dots{}
+
+There are plans to raise this 100 limit to 256, and yet produce @sc{posix}
+conforming archives. Past 256, I do not know yet if @sc{gnu} @command{tar}
+will go non-@sc{posix} again, or merely refuse to archive the file.
+
+There are plans so @sc{gnu} @command{tar} support more fully the latest @sc{posix}
+format, while being able to read old V7 format, @sc{gnu} (semi-@sc{posix} plus
+extension), as well as full @sc{posix}. One may ask if there is part of
+the @sc{posix} format that we still cannot support. This simple question
+has a complex answer. Maybe that, on intimate look, some strong
+limitations will pop up, but until now, nothing sounds too difficult
+(but see below). I only have these few pages of @sc{posix} telling about
+``Extended tar Format'' (P1003.1-1990 -- section 10.1.1), and there are
+references to other parts of the standard I do not have, which should
+normally enforce limitations on stored file names (I suspect things
+like fixing what @kbd{/} and @kbd{@key{NUL}} means). There are also
+some points which the standard does not make clear, Existing practice
+will then drive what I should do.
+
+@sc{posix} mandates that, when a file name cannot fit within 100 to
+256 characters (the variance comes from the fact a @kbd{/} is
+ideally needed as the 156'th character), or a link name cannot
+fit within 100 characters, a warning should be issued and the file
+@emph{not} be stored. Unless some @value{op-posix} option is given
+(or @env{POSIXLY_CORRECT} is set), I suspect that @sc{gnu} @command{tar}
+should disobey this specification, and automatically switch to using
+@sc{gnu} extensions to overcome file name or link name length limitations.
+
+There is a problem, however, which I did not intimately studied yet.
+Given a truly @sc{posix} archive with names having more than 100 characters,
+I guess that @sc{gnu} @command{tar} up to 1.11.8 will process it as if it were an
+old V7 archive, and be fooled by some fields which are coded differently.
+So, the question is to decide if the next generation of @sc{gnu} @command{tar}
+should produce @sc{posix} format by default, whenever possible, producing
+archives older versions of @sc{gnu} @command{tar} might not be able to read
+correctly. I fear that we will have to suffer such a choice one of these
+days, if we want @sc{gnu} @command{tar} to go closer to @sc{posix}. We can rush it.
+Another possibility is to produce the current @sc{gnu} @command{tar} format
+by default for a few years, but have @sc{gnu} @command{tar} versions from some
+1.@var{POSIX} and up able to recognize all three formats, and let older
+@sc{gnu} @command{tar} fade out slowly. Then, we could switch to producing @sc{posix}
+format by default, with not much harm to those still having (very old at
+that time) @sc{gnu} @command{tar} versions prior to 1.@var{POSIX}.
+
+@sc{posix} format cannot represent very long names, volume headers,
+splitting of files in multi-volumes, sparse files, and incremental
+dumps; these would be all disallowed if @value{op-posix} or
+@env{POSIXLY_CORRECT}. Otherwise, if @command{tar} is given long
+names, or @samp{-[VMSgG]}, then it should automatically go non-@sc{posix}.
+I think this is easily granted without much discussion.
+
+Another point is that only @code{mtime} is stored in @sc{posix}
+archives, while @sc{gnu} @command{tar} currently also store @code{atime}
+and @code{ctime}. If we want @sc{gnu} @command{tar} to go closer to @sc{posix},
+my choice would be to drop @code{atime} and @code{ctime} support on
+average. On the other hand, I perceive that full dumps or incremental
+dumps need @code{atime} and @code{ctime} support, so for those special
+applications, @sc{posix} has to be avoided altogether.
+
+A few users requested that @value{op-sparse} be always active by
+default, I think that before replying to them, we have to decide
+if we want @sc{gnu} @command{tar} to go closer to @sc{posix} on average, while
+producing files. My choice would be to go closer to @sc{posix} in the
+long run. Besides possible double reading, I do not see any point
+of not trying to save files as sparse when creating archives which
+are neither @sc{posix} nor old-V7, so the actual @value{op-sparse} would
+become selected by default when producing such archives, whatever
+the reason is. So, @value{op-sparse} alone might be redefined to force
+@sc{gnu}-format archives, and recover its previous meaning from this fact.
+
+@sc{gnu}-format as it exists now can easily fool other @sc{posix} @command{tar},
+as it uses fields which @sc{posix} considers to be part of the file name
+prefix. I wonder if it would not be a good idea, in the long run,
+to try changing @sc{gnu}-format so any added field (like @code{ctime},
+@code{atime}, file offset in subsequent volumes, or sparse file
+descriptions) be wholly and always pushed into an extension block,
+instead of using space in the @sc{posix} header block. I could manage
+to do that portably between future @sc{gnu} @command{tar}s. So other @sc{posix}
+@command{tar}s might be at least able to provide kind of correct listings
+for the archives produced by @sc{gnu} @command{tar}, if not able to process
+them otherwise.
+
+Using these projected extensions might induce older @command{tar}s to fail.
+We would use the same approach as for @sc{posix}. I'll put out a @command{tar}
+capable of reading @sc{posix}ier, yet extended archives, but will not produce
+this format by default, in @sc{gnu} mode. In a few years, when newer @sc{gnu}
+@command{tar}s will have flooded out @command{tar} 1.11.X and previous, we
+could switch to producing @sc{posix}ier extended archives, with no real harm
+to users, as almost all existing @sc{gnu} @command{tar}s will be ready to read
+@sc{posix}ier format. In fact, I'll do both changes at the same time, in a
+few years, and just prepare @command{tar} for both changes, without effecting
+them, from 1.@var{POSIX}. (Both changes: 1---using @sc{posix} convention for
+getting over 100 characters; 2---avoiding mangling @sc{posix} headers for @sc{gnu}
+extensions, using only @sc{posix} mandated extension techniques).
+
+So, a future @command{tar} will have a @value{op-posix}
+flag forcing the usage of truly @sc{posix} headers, and so, producing
+archives previous @sc{gnu} @command{tar} will not be able to read.
+So, @emph{once} pretest will announce that feature, it would be
+particularly useful that users test how exchangeable will be archives
+between @sc{gnu} @command{tar} with @value{op-posix} and other @sc{posix} @command{tar}.
+
+In a few years, when @sc{gnu} @command{tar} will produce @sc{posix} headers by
+default, @value{op-posix} will have a strong meaning and will disallow
+@sc{gnu} extensions. But in the meantime, for a long while, @value{op-posix}
+in @sc{gnu} tar will not disallow @sc{gnu} extensions like @value{op-label},
+@value{op-multi-volume}, @value{op-sparse}, or very long file or link names.
+However, @value{op-posix} with @sc{gnu} extensions will use @sc{posix}
+headers with reserved-for-users extensions to headers, and I will be
+curious to know how well or bad @sc{posix} @command{tar}s will react to these.
+
+@sc{gnu} @command{tar} prior to 1.@var{POSIX}, and after 1.@var{POSIX} without
+@value{op-posix}, generates and checks @samp{ustar@w{ }@w{ }}, with two
+suffixed spaces. This is sufficient for older @sc{gnu} @command{tar} not to
+recognize @sc{posix} archives, and consequently, wrongly decide those archives
+are in old V7 format. It is a useful bug for me, because @sc{gnu} @command{tar}
+has other @sc{posix} incompatibilities, and I need to segregate @sc{gnu} @command{tar}
+semi-@sc{posix} archives from truly @sc{posix} archives, for @sc{gnu} @command{tar} should
+be somewhat compatible with itself, while migrating closer to latest
+@sc{posix} standards. So, I'll be very careful about how and when I will do
+the correction.
+
+@node Checksumming
+@subsection Checksumming Problems
+
+SunOS and HP-UX @command{tar} fail to accept archives created using @sc{gnu}
+@command{tar} and containing non-ASCII file names, that is, file names
+having characters with the eight bit set, because they use signed
+checksums, while @sc{gnu} @command{tar} uses unsigned checksums while creating
+archives, as per @sc{posix} standards. On reading, @sc{gnu} @command{tar} computes
+both checksums and accept any. It is somewhat worrying that a lot of
+people may go around doing backup of their files using faulty (or at
+least non-standard) software, not learning about it until it's time
+to restore their missing files with an incompatible file extractor,
+or vice versa.
+
+@sc{gnu} @command{tar} compute checksums both ways, and accept any on read,
+so @sc{gnu} tar can read Sun tapes even with their wrong checksums.
+@sc{gnu} @command{tar} produces the standard checksum, however, raising
+incompatibilities with Sun. That is to say, @sc{gnu} @command{tar} has not
+been modified to @emph{produce} incorrect archives to be read by buggy
+@command{tar}'s. I've been told that more recent Sun @command{tar} now
+read standard archives, so maybe Sun did a similar patch, after all?
+
+The story seems to be that when Sun first imported @command{tar}
+sources on their system, they recompiled it without realizing that
+the checksums were computed differently, because of a change in
+the default signing of @code{char}'s in their compiler. So they
+started computing checksums wrongly. When they later realized their
+mistake, they merely decided to stay compatible with it, and with
+themselves afterwards. Presumably, but I do not really know, HP-UX
+has chosen that their @command{tar} archives to be compatible with Sun's.
+The current standards do not favor Sun @command{tar} format. In any
+case, it now falls on the shoulders of SunOS and HP-UX users to get
+a @command{tar} able to read the good archives they receive.
+
+@node Large or Negative Values
+@subsection Large or Negative Values
+@cindex large values
+@cindex future time stamps
+@cindex negative time stamps
+
+@sc{posix} @command{tar} format uses fixed-sized unsigned octal strings
+to represent numeric values. User and group IDs and device major and
+minor numbers have unsigned 21-bit representations, and file sizes and
+times have unsigned 33-bit representations. @sc{gnu} @command{tar}
+generates @sc{posix} representations when possible, but for values
+outside the @sc{posix} range it generates two's-complement base-256
+strings: uids, gids, and device numbers have signed 57-bit
+representations, and file sizes and times have signed 89-bit
+representations. These representations are an extension to @sc{posix}
+@command{tar} format, so they are not universally portable.
+
+The most common portability problems with out-of-range numeric values
+are large files and future or negative time stamps.
+
+Portable archives should avoid members of 8 GB or larger, as @sc{posix}
+@command{tar} format cannot represent them.
+
+Portable archives should avoid time stamps from the future. @sc{posix}
+@command{tar} format can represent time stamps in the range 1970-01-01
+00:00:00 through 2242-03-16 12:56:31 @sc{utc}. However, many current
+hosts use a signed 32-bit @code{time_t}, or internal time stamp format,
+and cannot represent time stamps after 2038-01-19 03:14:07 @sc{utc}; so
+portable archives must avoid these time stamps for many years to come.
+
+Portable archives should also avoid time stamps before 1970. These time
+stamps are a common @sc{posix} extension but their @code{time_t}
+representations are negative. Many traditional @command{tar}
+implementations generate a two's complement representation for negative
+time stamps that assumes a signed 32-bit @code{time_t}; hence they
+generate archives that are not portable to hosts with differing
+@code{time_t} representations. @sc{gnu} @command{tar} recognizes this
+situation when it is run on host with a signed 32-bit @code{time_t}, but
+it issues a warning, as these time stamps are nonstandard and unportable.
+
+@node Compression
+@section Using Less Space through Compression
+
+@menu
+* gzip:: Creating and Reading Compressed Archives
+* sparse:: Archiving Sparse Files
+@end menu
+
+@node gzip
+@subsection Creating and Reading Compressed Archives
+@cindex Compressed archives
+@cindex Storing archives in compressed format
+@UNREVISED
+
+@table @kbd
+@item -z
+@itemx --gzip
+@itemx --ungzip
+Filter the archive through @command{gzip}.
+@end table
+
+@FIXME{ach; these two bits orig from "compare" (?). where to put?} Some
+format parameters must be taken into consideration when modifying an
+archive.@FIXME{???} Compressed archives cannot be modified.
+
+You can use @samp{--gzip} and @samp{--gunzip} on physical devices
+(tape drives, etc.) and remote files as well as on normal files; data
+to or from such devices or remote files is reblocked by another copy
+of the @command{tar} program to enforce the specified (or default) record
+size. The default compression parameters are used; if you need to
+override them, avoid the @value{op-gzip} option and run @command{gzip}
+explicitly. (Or set the @env{GZIP} environment variable.)
+
+The @value{op-gzip} option does not work with the @value{op-multi-volume}
+option, or with the @value{op-update}, @value{op-append},
+@value{op-concatenate}, or @value{op-delete} operations.
+
+It is not exact to say that @sc{gnu} @command{tar} is to work in concert
+with @command{gzip} in a way similar to @command{zip}, say. Surely, it is
+possible that @command{tar} and @command{gzip} be done with a single call,
+like in:
+
+@example
+$ @kbd{tar cfz archive.tar.gz subdir}
+@end example
+
+@noindent
+to save all of @samp{subdir} into a @code{gzip}'ed archive. Later you
+can do:
+
+@example
+$ @kbd{tar xfz archive.tar.gz}
+@end example
+
+@noindent
+to explode and unpack.
+
+The difference is that the whole archive is compressed. With
+@command{zip}, archive members are archived individually. @command{tar}'s
+method yields better compression. On the other hand, one can view the
+contents of a @command{zip} archive without having to decompress it. As
+for the @command{tar} and @command{gzip} tandem, you need to decompress the
+archive to see its contents. However, this may be done without needing
+disk space, by using pipes internally:
+
+@example
+$ @kbd{tar tfz archive.tar.gz}
+@end example
+
+@cindex corrupted archives
+About corrupted compressed archives: @command{gzip}'ed files have no
+redundancy, for maximum compression. The adaptive nature of the
+compression scheme means that the compression tables are implicitly
+spread all over the archive. If you lose a few blocks, the dynamic
+construction of the compression tables becomes unsynchronized, and there
+is little chance that you could recover later in the archive.
+
+There are pending suggestions for having a per-volume or per-file
+compression in @sc{gnu} @command{tar}. This would allow for viewing the
+contents without decompression, and for resynchronizing decompression at
+every volume or file, in case of corrupted archives. Doing so, we might
+lose some compressibility. But this would have make recovering easier.
+So, there are pros and cons. We'll see!
+
+@table @kbd
+@item -j
+@itemx --bzip2
+Filter the archive through @code{bzip2}. Otherwise like @value{op-gzip}.
+
+@item -Z
+@itemx --compress
+@itemx --uncompress
+Filter the archive through @command{compress}. Otherwise like @value{op-gzip}.
+
+@item --use-compress-program=@var{prog}
+Filter through @var{prog} (must accept @samp{-d}).
+@end table
+
+@value{op-compress} stores an archive in compressed format. This
+option is useful in saving time over networks and space in pipes, and
+when storage space is at a premium. @value{op-compress} causes
+@command{tar} to compress when writing the archive, or to uncompress when
+reading the archive.
+
+To perform compression and uncompression on the archive, @command{tar}
+runs the @command{compress} utility. @command{tar} uses the default
+compression parameters; if you need to override them, avoid the
+@value{op-compress} option and run the @command{compress} utility
+explicitly. It is useful to be able to call the @command{compress}
+utility from within @command{tar} because the @command{compress} utility by
+itself cannot access remote tape drives.
+
+The @value{op-compress} option will not work in conjunction with the
+@value{op-multi-volume} option or the @value{op-append}, @value{op-update}
+and @value{op-delete} operations. @xref{Operations}, for
+more information on these operations.
+
+If there is no compress utility available, @command{tar} will report an error.
+@strong{Please note} that the @command{compress} program may be covered by
+a patent, and therefore we recommend you stop using it.
+
+@value{op-bzip2} acts like @value{op-compress}, except that it uses
+the @code{bzip2} utility.
+
+@table @kbd
+@item --compress
+@itemx --uncompress
+@itemx -z
+@itemx -Z
+When this option is specified, @command{tar} will compress (when writing
+an archive), or uncompress (when reading an archive). Used in
+conjunction with the @value{op-create}, @value{op-extract}, @value{op-list} and
+@value{op-compare} operations.
+@end table
+
+You can have archives be compressed by using the @value{op-gzip} option.
+This will arrange for @command{tar} to use the @command{gzip} program to be
+used to compress or uncompress the archive wren writing or reading it.
+
+To use the older, obsolete, @command{compress} program, use the
+@value{op-compress} option. The @sc{gnu} Project recommends you not use
+@command{compress}, because there is a patent covering the algorithm it
+uses. You could be sued for patent infringement merely by running
+@command{compress}.
+
+I have one question, or maybe it's a suggestion if there isn't a way
+to do it now. I would like to use @value{op-gzip}, but I'd also like the
+output to be fed through a program like @sc{gnu} @command{ecc} (actually, right
+now that's @samp{exactly} what I'd like to use :-)), basically adding
+ECC protection on top of compression. It seems as if this should be
+quite easy to do, but I can't work out exactly how to go about it.
+Of course, I can pipe the standard output of @command{tar} through
+@command{ecc}, but then I lose (though I haven't started using it yet,
+I confess) the ability to have @command{tar} use @command{rmt} for it's I/O
+(I think).
+
+I think the most straightforward thing would be to let me specify a
+general set of filters outboard of compression (preferably ordered,
+so the order can be automatically reversed on input operations, and
+with the options they require specifiable), but beggars shouldn't be
+choosers and anything you decide on would be fine with me.
+
+By the way, I like @command{ecc} but if (as the comments say) it can't
+deal with loss of block sync, I'm tempted to throw some time at adding
+that capability. Supposing I were to actually do such a thing and
+get it (apparently) working, do you accept contributed changes to
+utilities like that? (Leigh Clayton @file{loc@@soliton.com}, May 1995).
+
+Isn't that exactly the role of the @value{op-use-compress-prog} option?
+I never tried it myself, but I suspect you may want to write a
+@var{prog} script or program able to filter stdin to stdout to
+way you want. It should recognize the @samp{-d} option, for when
+extraction is needed rather than creation.
+
+It has been reported that if one writes compressed data (through the
+@value{op-gzip} or @value{op-compress} options) to a DLT and tries to use
+the DLT compression mode, the data will actually get bigger and one will
+end up with less space on the tape.
+
+@node sparse
+@subsection Archiving Sparse Files
+@cindex Sparse Files
+@UNREVISED
+
+@table @kbd
+@item -S
+@itemx --sparse
+Handle sparse files efficiently.
+@end table
+
+This option causes all files to be put in the archive to be tested for
+sparseness, and handled specially if they are. The @value{op-sparse}
+option is useful when many @code{dbm} files, for example, are being
+backed up. Using this option dramatically decreases the amount of
+space needed to store such a file.
+
+In later versions, this option may be removed, and the testing and
+treatment of sparse files may be done automatically with any special
+@sc{gnu} options. For now, it is an option needing to be specified on
+the command line with the creation or updating of an archive.
+
+Files in the filesystem occasionally have ``holes.'' A hole in a file
+is a section of the file's contents which was never written. The
+contents of a hole read as all zeros. On many operating systems,
+actual disk storage is not allocated for holes, but they are counted
+in the length of the file. If you archive such a file, @command{tar}
+could create an archive longer than the original. To have @command{tar}
+attempt to recognize the holes in a file, use @value{op-sparse}. When
+you use the @value{op-sparse} option, then, for any file using less
+disk space than would be expected from its length, @command{tar} searches
+the file for consecutive stretches of zeros. It then records in the
+archive for the file where the consecutive stretches of zeros are, and
+only archives the ``real contents'' of the file. On extraction (using
+@value{op-sparse} is not needed on extraction) any such files have
+hols created wherever the continuous stretches of zeros were found.
+Thus, if you use @value{op-sparse}, @command{tar} archives won't take
+more space than the original.
+
+A file is sparse if it contains blocks of zeros whose existence is
+recorded, but that have no space allocated on disk. When you specify
+the @value{op-sparse} option in conjunction with the @value{op-create}
+operation, @command{tar} tests all files for sparseness while archiving.
+If @command{tar} finds a file to be sparse, it uses a sparse representation of
+the file in the archive. @value{xref-create}, for more information
+about creating archives.
+
+@value{op-sparse} is useful when archiving files, such as dbm files,
+likely to contain many nulls. This option dramatically
+decreases the amount of space needed to store such an archive.
+
+@quotation
+@strong{Please Note:} Always use @value{op-sparse} when performing file
+system backups, to avoid archiving the expanded forms of files stored
+sparsely in the system.
+
+Even if your system has no sparse files currently, some may be
+created in the future. If you use @value{op-sparse} while making file
+system backups as a matter of course, you can be assured the archive
+will never take more space on the media than the files take on disk
+(otherwise, archiving a disk filled with sparse files might take
+hundreds of tapes). @FIXME-xref{incremental when node name is set.}
+@end quotation
+
+@command{tar} ignores the @value{op-sparse} option when reading an archive.
+
+@table @kbd
+@item --sparse
+@itemx -S
+Files stored sparsely in the file system are represented sparsely in
+the archive. Use in conjunction with write operations.
+@end table
+
+However, users should be well aware that at archive creation time, @sc{gnu}
+@command{tar} still has to read whole disk file to locate the @dfn{holes}, and
+so, even if sparse files use little space on disk and in the archive, they
+may sometimes require inordinate amount of time for reading and examining
+all-zero blocks of a file. Although it works, it's painfully slow for a
+large (sparse) file, even though the resulting tar archive may be small.
+(One user reports that dumping a @file{core} file of over 400 megabytes,
+but with only about 3 megabytes of actual data, took about 9 minutes on
+a Sun Sparcstation ELC, with full CPU utilization.)
+
+This reading is required in all cases and is not related to the fact
+the @value{op-sparse} option is used or not, so by merely @emph{not}
+using the option, you are not saving time@footnote{Well! We should say
+the whole truth, here. When @value{op-sparse} is selected while creating
+an archive, the current @command{tar} algorithm requires sparse files to be
+read twice, not once. We hope to develop a new archive format for saving
+sparse files in which one pass will be sufficient.}.
+
+Programs like @command{dump} do not have to read the entire file; by examining
+the file system directly, they can determine in advance exactly where the
+holes are and thus avoid reading through them. The only data it need read
+are the actual allocated data blocks. @sc{gnu} @command{tar} uses a more portable
+and straightforward archiving approach, it would be fairly difficult that
+it does otherwise. Elizabeth Zwicky writes to @file{comp.unix.internals},
+on 1990-12-10:
+
+@quotation
+What I did say is that you cannot tell the difference between a hole and an
+equivalent number of nulls without reading raw blocks. @code{st_blocks} at
+best tells you how many holes there are; it doesn't tell you @emph{where}.
+Just as programs may, conceivably, care what @code{st_blocks} is (care
+to name one that does?), they may also care where the holes are (I have
+no examples of this one either, but it's equally imaginable).
+
+I conclude from this that good archivers are not portable. One can
+arguably conclude that if you want a portable program, you can in good
+conscience restore files with as many holes as possible, since you can't
+get it right.
+@end quotation
+
+@node Attributes
+@section Handling File Attributes
+@UNREVISED
+
+When @command{tar} reads files, this causes them to have the access
+times updated. To have @command{tar} attempt to set the access times
+back to what they were before they were read, use the
+@value{op-atime-preserve} option.
+
+Handling of file attributes
+
+@table @kbd
+@item --atime-preserve
+Preserve access times on files that are read.
+This doesn't work for files that
+you don't own, unless you're root, and it doesn't interact with
+incremental dumps nicely (@pxref{Backups}), and it can set access or
+modification times incorrectly if other programs access the file while
+@command{tar} is running; but it is good enough for some purposes.
+
+@item -m
+@itemx --touch
+Do not extract file modified time.
+
+When this option is used, @command{tar} leaves the modification times
+of the files it extracts as the time when the files were extracted,
+instead of setting it to the time recorded in the archive.
+
+This option is meaningless with @value{op-list}.
+
+@item --same-owner
+Create extracted files with the same ownership they have in the
+archive.
+
+This is the default behavior for the superuser,
+so this option is meaningful only for non-root users, when @command{tar}
+is executed on those systems able to give files away. This is
+considered as a security flaw by many people, at least because it
+makes quite difficult to correctly account users for the disk space
+they occupy. Also, the @code{suid} or @code{sgid} attributes of
+files are easily and silently lost when files are given away.
+
+When writing an archive, @command{tar} writes the user id and user name
+separately. If it can't find a user name (because the user id is not
+in @file{/etc/passwd}), then it does not write one. When restoring,
+and doing a @code{chmod} like when you use @value{op-same-permissions},
+@FIXME{same-owner?}it tries to look the name (if one was written)
+up in @file{/etc/passwd}. If it fails, then it uses the user id
+stored in the archive instead.
+
+@item --no-same-owner
+Do not attempt to restore ownership when extracting. This is the
+default behavior for ordinary users, so this option has an effect
+only for the superuser.
+
+@item --numeric-owner
+The @value{op-numeric-owner} option allows (ANSI) archives to be written
+without user/group name information or such information to be ignored
+when extracting. It effectively disables the generation and/or use
+of user/group name information. This option forces extraction using
+the numeric ids from the archive, ignoring the names.
+
+This is useful in certain circumstances, when restoring a backup from
+an emergency floppy with different passwd/group files for example.
+It is otherwise impossible to extract files with the right ownerships
+if the password file in use during the extraction does not match the
+one belonging to the filesystem(s) being extracted. This occurs,
+for example, if you are restoring your files after a major crash and
+had booted from an emergency floppy with no password file or put your
+disk into another machine to do the restore.
+
+The numeric ids are @emph{always} saved into @command{tar} archives.
+The identifying names are added at create time when provided by the
+system, unless @value{op-old-archive} is used. Numeric ids could be
+used when moving archives between a collection of machines using
+a centralized management for attribution of numeric ids to users
+and groups. This is often made through using the NIS capabilities.
+
+When making a @command{tar} file for distribution to other sites, it
+is sometimes cleaner to use a single owner for all files in the
+distribution, and nicer to specify the write permission bits of the
+files as stored in the archive independently of their actual value on
+the file system. The way to prepare a clean distribution is usually
+to have some Makefile rule creating a directory, copying all needed
+files in that directory, then setting ownership and permissions as
+wanted (there are a lot of possible schemes), and only then making a
+@command{tar} archive out of this directory, before cleaning everything
+out. Of course, we could add a lot of options to @sc{gnu} @command{tar} for
+fine tuning permissions and ownership. This is not the good way,
+I think. @sc{gnu} @command{tar} is already crowded with options and moreover,
+the approach just explained gives you a great deal of control already.
+
+@item -p
+@itemx --same-permissions
+@itemx --preserve-permissions
+Extract all protection information.
+
+This option causes @command{tar} to set the modes (access permissions) of
+extracted files exactly as recorded in the archive. If this option
+is not used, the current @code{umask} setting limits the permissions
+on extracted files.
+
+This option is meaningless with @value{op-list}.
+
+@item --preserve
+Same as both @value{op-same-permissions} and @value{op-same-order}.
+
+The @value{op-preserve} option has no equivalent short option name.
+It is equivalent to @value{op-same-permissions} plus @value{op-same-order}.
+
+@FIXME{I do not see the purpose of such an option. (Neither I. FP.)}
+
+@end table
+
+@node Standard
+@section The Standard Format
+@UNREVISED
+
+While an archive may contain many files, the archive itself is a
+single ordinary file. Like any other file, an archive file can be
+written to a storage device such as a tape or disk, sent through a
+pipe or over a network, saved on the active file system, or even
+stored in another archive. An archive file is not easy to read or
+manipulate without using the @command{tar} utility or Tar mode in @sc{gnu}
+Emacs.
+
+Physically, an archive consists of a series of file entries terminated
+by an end-of-archive entry, which consists of 512 zero bytes. A file
+entry usually describes one of the files in the archive (an
+@dfn{archive member}), and consists of a file header and the contents
+of the file. File headers contain file names and statistics, checksum
+information which @command{tar} uses to detect file corruption, and
+information about file types.
+
+Archives are permitted to have more than one member with the same
+member name. One way this situation can occur is if more than one
+version of a file has been stored in the archive. For information
+about adding new versions of a file to an archive, see @ref{update}.
+@FIXME-xref{To learn more about having more than one archive member with the
+same name, see -backup node, when it's written.}
+
+In addition to entries describing archive members, an archive may
+contain entries which @command{tar} itself uses to store information.
+@value{xref-label}, for an example of such an archive entry.
+
+A @command{tar} archive file contains a series of blocks. Each block
+contains @code{BLOCKSIZE} bytes. Although this format may be thought
+of as being on magnetic tape, other media are often used.
+
+Each file archived is represented by a header block which describes
+the file, followed by zero or more blocks which give the contents
+of the file. At the end of the archive file there may be a block
+filled with binary zeros as an end-of-file marker. A reasonable system
+should write a block of zeros at the end, but must not assume that
+such a block exists when reading an archive.
+
+The blocks may be @dfn{blocked} for physical I/O operations.
+Each record of @var{n} blocks (where @var{n} is set by the
+@value{op-blocking-factor} option to @command{tar}) is written with a single
+@w{@samp{write ()}} operation. On magnetic tapes, the result of
+such a write is a single record. When writing an archive,
+the last record of blocks should be written at the full size, with
+blocks after the zero block containing all zeros. When reading
+an archive, a reasonable system should properly handle an archive
+whose last record is shorter than the rest, or which contains garbage
+records after a zero block.
+
+The header block is defined in C as follows. In the @sc{gnu} @command{tar}
+distribution, this is part of file @file{src/tar.h}:
+
+@example
+@include header.texi
+@end example
+
+All characters in header blocks are represented by using 8-bit
+characters in the local variant of ASCII. Each field within the
+structure is contiguous; that is, there is no padding used within
+the structure. Each character on the archive medium is stored
+contiguously.
+
+Bytes representing the contents of files (after the header block
+of each file) are not translated in any way and are not constrained
+to represent characters in any character set. The @command{tar} format
+does not distinguish text files from binary files, and no translation
+of file contents is performed.
+
+The @code{name}, @code{linkname}, @code{magic}, @code{uname}, and
+@code{gname} are null-terminated character strings. All other fields
+are zero-filled octal numbers in ASCII. Each numeric field of width
+@var{w} contains @var{w} minus 2 digits, a space, and a null, except
+@code{size}, and @code{mtime}, which do not contain the trailing null.
+
+The @code{name} field is the file name of the file, with directory names
+(if any) preceding the file name, separated by slashes.
+
+@FIXME{how big a name before field overflows?}
+
+The @code{mode} field provides nine bits specifying file permissions
+and three bits to specify the Set UID, Set GID, and Save Text
+(@dfn{sticky}) modes. Values for these bits are defined above.
+When special permissions are required to create a file with a given
+mode, and the user restoring files from the archive does not hold such
+permissions, the mode bit(s) specifying those special permissions
+are ignored. Modes which are not supported by the operating system
+restoring files from the archive will be ignored. Unsupported modes
+should be faked up when creating or updating an archive; e.g.@: the
+group permission could be copied from the @emph{other} permission.
+
+The @code{uid} and @code{gid} fields are the numeric user and group
+ID of the file owners, respectively. If the operating system does
+not support numeric user or group IDs, these fields should be ignored.
+
+The @code{size} field is the size of the file in bytes; linked files
+are archived with this field specified as zero. @FIXME-xref{Modifiers, in
+particular the @value{op-incremental} option.}
+
+The @code{mtime} field is the modification time of the file at the time
+it was archived. It is the ASCII representation of the octal value of
+the last time the file was modified, represented as an integer number of
+seconds since January 1, 1970, 00:00 Coordinated Universal Time.
+
+The @code{chksum} field is the ASCII representation of the octal value
+of the simple sum of all bytes in the header block. Each 8-bit
+byte in the header is added to an unsigned integer, initialized to
+zero, the precision of which shall be no less than seventeen bits.
+When calculating the checksum, the @code{chksum} field is treated as
+if it were all blanks.
+
+The @code{typeflag} field specifies the type of file archived. If a
+particular implementation does not recognize or permit the specified
+type, the file will be extracted as if it were a regular file. As this
+action occurs, @command{tar} issues a warning to the standard error.
+
+The @code{atime} and @code{ctime} fields are used in making incremental
+backups; they store, respectively, the particular file's access time
+and last inode-change time.
+
+The @code{offset} is used by the @value{op-multi-volume} option, when
+making a multi-volume archive. The offset is number of bytes into
+the file that we need to restart at to continue the file on the next
+tape, i.e., where we store the location that a continued file is
+continued at.
+
+The following fields were added to deal with sparse files. A file
+is @dfn{sparse} if it takes in unallocated blocks which end up being
+represented as zeros, i.e., no useful data. A test to see if a file
+is sparse is to look at the number blocks allocated for it versus the
+number of characters in the file; if there are fewer blocks allocated
+for the file than would normally be allocated for a file of that
+size, then the file is sparse. This is the method @command{tar} uses to
+detect a sparse file, and once such a file is detected, it is treated
+differently from non-sparse files.
+
+Sparse files are often @code{dbm} files, or other database-type files
+which have data at some points and emptiness in the greater part of
+the file. Such files can appear to be very large when an @samp{ls
+-l} is done on them, when in truth, there may be a very small amount
+of important data contained in the file. It is thus undesirable
+to have @command{tar} think that it must back up this entire file, as
+great quantities of room are wasted on empty blocks, which can lead
+to running out of room on a tape far earlier than is necessary.
+Thus, sparse files are dealt with so that these empty blocks are
+not written to the tape. Instead, what is written to the tape is a
+description, of sorts, of the sparse file: where the holes are, how
+big the holes are, and how much data is found at the end of the hole.
+This way, the file takes up potentially far less room on the tape,
+and when the file is extracted later on, it will look exactly the way
+it looked beforehand. The following is a description of the fields
+used to handle a sparse file:
+
+The @code{sp} is an array of @code{struct sparse}. Each @code{struct
+sparse} contains two 12-character strings which represent an offset
+into the file and a number of bytes to be written at that offset.
+The offset is absolute, and not relative to the offset in preceding
+array element.
+
+The header can hold four of these @code{struct sparse} at the moment;
+if more are needed, they are not stored in the header.
+
+The @code{isextended} flag is set when an @code{extended_header}
+is needed to deal with a file. Note that this means that this flag
+can only be set when dealing with a sparse file, and it is only set
+in the event that the description of the file will not fit in the
+allotted room for sparse structures in the header. In other words,
+an extended_header is needed.
+
+The @code{extended_header} structure is used for sparse files which
+need more sparse structures than can fit in the header. The header can
+fit 4 such structures; if more are needed, the flag @code{isextended}
+gets set and the next block is an @code{extended_header}.
+
+Each @code{extended_header} structure contains an array of 21
+sparse structures, along with a similar @code{isextended} flag
+that the header had. There can be an indeterminate number of such
+@code{extended_header}s to describe a sparse file.
+
+@table @asis
+
+@item @code{REGTYPE}
+@itemx @code{AREGTYPE}
+These flags represent a regular file. In order to be compatible
+with older versions of @command{tar}, a @code{typeflag} value of
+@code{AREGTYPE} should be silently recognized as a regular file.
+New archives should be created using @code{REGTYPE}. Also, for
+backward compatibility, @command{tar} treats a regular file whose name
+ends with a slash as a directory.
+
+@item @code{LNKTYPE}
+This flag represents a file linked to another file, of any type,
+previously archived. Such files are identified in Unix by each
+file having the same device and inode number. The linked-to name is
+specified in the @code{linkname} field with a trailing null.
+
+@item @code{SYMTYPE}
+This represents a symbolic link to another file. The linked-to name
+is specified in the @code{linkname} field with a trailing null.
+
+@item @code{CHRTYPE}
+@itemx @code{BLKTYPE}
+These represent character special files and block special files
+respectively. In this case the @code{devmajor} and @code{devminor}
+fields will contain the major and minor device numbers respectively.
+Operating systems may map the device specifications to their own
+local specification, or may ignore the entry.
+
+@item @code{DIRTYPE}
+This flag specifies a directory or sub-directory. The directory
+name in the @code{name} field should end with a slash. On systems where
+disk allocation is performed on a directory basis, the @code{size} field
+will contain the maximum number of bytes (which may be rounded to
+the nearest disk block allocation unit) which the directory may
+hold. A @code{size} field of zero indicates no such limiting. Systems
+which do not support limiting in this manner should ignore the
+@code{size} field.
+
+@item @code{FIFOTYPE}
+This specifies a FIFO special file. Note that the archiving of a
+FIFO file archives the existence of this file and not its contents.
+
+@item @code{CONTTYPE}
+This specifies a contiguous file, which is the same as a normal
+file except that, in operating systems which support it, all its
+space is allocated contiguously on the disk. Operating systems
+which do not allow contiguous allocation should silently treat this
+type as a normal file.
+
+@item @code{A} @dots{} @code{Z}
+These are reserved for custom implementations. Some of these are
+used in the @sc{gnu} modified format, as described below.
+
+@end table
+
+Other values are reserved for specification in future revisions of
+the P1003 standard, and should not be used by any @command{tar} program.
+
+The @code{magic} field indicates that this archive was output in
+the P1003 archive format. If this field contains @code{TMAGIC},
+the @code{uname} and @code{gname} fields will contain the ASCII
+representation of the owner and group of the file respectively.
+If found, the user and group IDs are used rather than the values in
+the @code{uid} and @code{gid} fields.
+
+For references, see ISO/IEC 9945-1:1990 or IEEE Std 1003.1-1990, pages
+169-173 (section 10.1) for @cite{Archive/Interchange File Format}; and
+IEEE Std 1003.2-1992, pages 380-388 (section 4.48) and pages 936-940
+(section E.4.48) for @cite{pax - Portable archive interchange}.
+
+@node Extensions
+@section @sc{gnu} Extensions to the Archive Format
+@UNREVISED
+
+The @sc{gnu} format uses additional file types to describe new types of
+files in an archive. These are listed below.
+
+@table @code
+@item GNUTYPE_DUMPDIR
+@itemx 'D'
+This represents a directory and a list of files created by the
+@value{op-incremental} option. The @code{size} field gives the total
+size of the associated list of files. Each file name is preceded by
+either a @samp{Y} (the file should be in this archive) or an @samp{N}.
+(The file is a directory, or is not stored in the archive.) Each file
+name is terminated by a null. There is an additional null after the
+last file name.
+
+@item GNUTYPE_MULTIVOL
+@itemx 'M'
+This represents a file continued from another volume of a multi-volume
+archive created with the @value{op-multi-volume} option. The original
+type of the file is not given here. The @code{size} field gives the
+maximum size of this piece of the file (assuming the volume does
+not end before the file is written out). The @code{offset} field
+gives the offset from the beginning of the file where this part of
+the file begins. Thus @code{size} plus @code{offset} should equal
+the original size of the file.
+
+@item GNUTYPE_SPARSE
+@itemx 'S'
+This flag indicates that we are dealing with a sparse file. Note
+that archiving a sparse file requires special operations to find
+holes in the file, which mark the positions of these holes, along
+with the number of bytes of data to be found after the hole.
+
+@item GNUTYPE_VOLHDR
+@itemx 'V'
+This file type is used to mark the volume header that was given with
+the @value{op-label} option when the archive was created. The @code{name}
+field contains the @code{name} given after the @value{op-label} option.
+The @code{size} field is zero. Only the first file in each volume
+of an archive should have this type.
+
+@end table
+
+You may have trouble reading a @sc{gnu} format archive on a non-@sc{gnu}
+system if the options @value{op-incremental}, @value{op-multi-volume},
+@value{op-sparse}, or @value{op-label} were used when writing the archive.
+In general, if @command{tar} does not use the @sc{gnu}-added fields of the
+header, other versions of @command{tar} should be able to read the
+archive. Otherwise, the @command{tar} program will give an error, the
+most likely one being a checksum error.
+
+@node cpio
+@section Comparison of @command{tar} and @command{cpio}
+@UNREVISED
+
+@FIXME{Reorganize the following material}
+
+The @command{cpio} archive formats, like @command{tar}, do have maximum
+pathname lengths. The binary and old ASCII formats have a max path
+length of 256, and the new ASCII and CRC ASCII formats have a max
+path length of 1024. @sc{gnu} @command{cpio} can read and write archives
+with arbitrary pathname lengths, but other @command{cpio} implementations
+may crash unexplainedly trying to read them.
+
+@command{tar} handles symbolic links in the form in which it comes in BSD;
+@command{cpio} doesn't handle symbolic links in the form in which it comes
+in System V prior to SVR4, and some vendors may have added symlinks
+to their system without enhancing @command{cpio} to know about them.
+Others may have enhanced it in a way other than the way I did it
+at Sun, and which was adopted by AT&T (and which is, I think, also
+present in the @command{cpio} that Berkeley picked up from AT&T and put
+into a later BSD release---I think I gave them my changes).
+
+(SVR4 does some funny stuff with @command{tar}; basically, its @command{cpio}
+can handle @command{tar} format input, and write it on output, and it
+probably handles symbolic links. They may not have bothered doing
+anything to enhance @command{tar} as a result.)
+
+@command{cpio} handles special files; traditional @command{tar} doesn't.
+
+@command{tar} comes with V7, System III, System V, and BSD source;
+@command{cpio} comes only with System III, System V, and later BSD
+(4.3-tahoe and later).
+
+@command{tar}'s way of handling multiple hard links to a file can handle
+file systems that support 32-bit inumbers (e.g., the BSD file system);
+@command{cpio}s way requires you to play some games (in its "binary"
+format, i-numbers are only 16 bits, and in its "portable ASCII" format,
+they're 18 bits---it would have to play games with the "file system ID"
+field of the header to make sure that the file system ID/i-number pairs
+of different files were always different), and I don't know which
+@command{cpio}s, if any, play those games. Those that don't might get
+confused and think two files are the same file when they're not, and
+make hard links between them.
+
+@command{tar}s way of handling multiple hard links to a file places only
+one copy of the link on the tape, but the name attached to that copy
+is the @emph{only} one you can use to retrieve the file; @command{cpio}s
+way puts one copy for every link, but you can retrieve it using any
+of the names.
+
+@quotation
+What type of check sum (if any) is used, and how is this calculated.
+@end quotation
+
+See the attached manual pages for @command{tar} and @command{cpio} format.
+@command{tar} uses a checksum which is the sum of all the bytes in the
+@command{tar} header for a file; @command{cpio} uses no checksum.
+
+@quotation
+If anyone knows why @command{cpio} was made when @command{tar} was present
+at the unix scene,
+@end quotation
+
+It wasn't. @command{cpio} first showed up in PWB/UNIX 1.0; no
+generally-available version of UNIX had @command{tar} at the time. I don't
+know whether any version that was generally available @emph{within AT&T}
+had @command{tar}, or, if so, whether the people within AT&T who did
+@command{cpio} knew about it.
+
+On restore, if there is a corruption on a tape @command{tar} will stop at
+that point, while @command{cpio} will skip over it and try to restore the
+rest of the files.
+
+The main difference is just in the command syntax and header format.
+
+@command{tar} is a little more tape-oriented in that everything is blocked
+to start on a record boundary.
+
+@quotation
+Is there any differences between the ability to recover crashed
+archives between the two of them. (Is there any chance of recovering
+crashed archives at all.)
+@end quotation
+
+Theoretically it should be easier under @command{tar} since the blocking
+lets you find a header with some variation of @samp{dd skip=@var{nn}}.
+However, modern @command{cpio}'s and variations have an option to just
+search for the next file header after an error with a reasonable chance
+of resyncing. However, lots of tape driver software won't allow you to
+continue past a media error which should be the only reason for getting
+out of sync unless a file changed sizes while you were writing the
+archive.
+
+@quotation
+If anyone knows why @command{cpio} was made when @command{tar} was present
+at the unix scene, please tell me about this too.
+@end quotation
+
+Probably because it is more media efficient (by not blocking everything
+and using only the space needed for the headers where @command{tar}
+always uses 512 bytes per file header) and it knows how to archive
+special files.
+
+You might want to look at the freely available alternatives. The major
+ones are @command{afio}, @sc{gnu} @command{tar}, and @command{pax}, each of which
+have their own extensions with some backwards compatibility.
+
+Sparse files were @command{tar}red as sparse files (which you can easily
+test, because the resulting archive gets smaller, and @sc{gnu} @command{cpio}
+can no longer read it).
+
+@node Media
+@chapter Tapes and Other Archive Media
+@UNREVISED
+
+A few special cases about tape handling warrant more detailed
+description. These special cases are discussed below.
+
+Many complexities surround the use of @command{tar} on tape drives. Since
+the creation and manipulation of archives located on magnetic tape was
+the original purpose of @command{tar}, it contains many features making
+such manipulation easier.
+
+Archives are usually written on dismountable media---tape cartridges,
+mag tapes, or floppy disks.
+
+The amount of data a tape or disk holds depends not only on its size,
+but also on how it is formatted. A 2400 foot long reel of mag tape
+holds 40 megabytes of data when formatted at 1600 bits per inch. The
+physically smaller EXABYTE tape cartridge holds 2.3 gigabytes.
+
+Magnetic media are re-usable---once the archive on a tape is no longer
+needed, the archive can be erased and the tape or disk used over.
+Media quality does deteriorate with use, however. Most tapes or disks
+should be discarded when they begin to produce data errors. EXABYTE
+tape cartridges should be discarded when they generate an @dfn{error
+count} (number of non-usable bits) of more than 10k.
+
+Magnetic media are written and erased using magnetic fields, and
+should be protected from such fields to avoid damage to stored data.
+Sticking a floppy disk to a filing cabinet using a magnet is probably
+not a good idea.
+
+@menu
+* Device:: Device selection and switching
+* Remote Tape Server::
+* Common Problems and Solutions::
+* Blocking:: Blocking
+* Many:: Many archives on one tape
+* Using Multiple Tapes:: Using Multiple Tapes
+* label:: Including a Label in the Archive
+* verify::
+* Write Protection::
+@end menu
+
+@node Device
+@section Device Selection and Switching
+@UNREVISED
+
+@table @kbd
+@item -f [@var{hostname}:]@var{file}
+@itemx --file=[@var{hostname}:]@var{file}
+Use archive file or device @var{file} on @var{hostname}.
+@end table
+
+This option is used to specify the file name of the archive @command{tar}
+works on.
+
+If the file name is @samp{-}, @command{tar} reads the archive from standard
+input (when listing or extracting), or writes it to standard output
+(when creating). If the @samp{-} file name is given when updating an
+archive, @command{tar} will read the original archive from its standard
+input, and will write the entire new archive to its standard output.
+
+If the file name contains a @samp{:}, it is interpreted as
+@samp{hostname:file name}. If the @var{hostname} contains an @dfn{at}
+sign (@kbd{@@}), it is treated as @samp{user@@hostname:file name}. In
+either case, @command{tar} will invoke the command @command{rsh} (or
+@command{remsh}) to start up an @file{/etc/rmt} on the remote machine. If
+you give an alternate login name, it will be given to the @command{rsh}.
+Naturally, the remote machine must have an executable @file{/etc/rmt}.
+This program is free software from the University of California, and a
+copy of the source code can be found with the sources for @command{tar};
+it's compiled and installed by default.
+
+If this option is not given, but the environment variable @env{TAPE} is
+set, its value is used; otherwise, old versions of @command{tar} used a default
+archive name (which was picked when @command{tar} was compiled). The
+default is normally set up to be the @dfn{first} tape drive or other
+transportable I/O medium on the system.
+
+Starting with version 1.11.5, @sc{gnu} @command{tar} uses standard input and
+standard output as the default device, and I will not try anymore
+supporting automatic device detection at installation time. This was
+failing really in too many cases, it was hopeless. This is now
+completely left to the installer to override standard input and standard
+output for default device, if this seems preferable.
+Further, I think @emph{most} actual usages of @command{tar} are done with
+pipes or disks, not really tapes, cartridges or diskettes.
+
+Some users think that using standard input and output is running
+after trouble. This could lead to a nasty surprise on your screen if
+you forget to specify an output file name---especially if you are going
+through a network or terminal server capable of buffering large amounts
+of output. We had so many bug reports in that area of configuring
+default tapes automatically, and so many contradicting requests, that
+we finally consider the problem to be portably intractable. We could
+of course use something like @samp{/dev/tape} as a default, but this
+is @emph{also} running after various kind of trouble, going from hung
+processes to accidental destruction of real tapes. After having seen
+all this mess, using standard input and output as a default really
+sounds like the only clean choice left, and a very useful one too.
+
+@sc{gnu} @command{tar} reads and writes archive in records, I suspect this is the
+main reason why block devices are preferred over character devices.
+Most probably, block devices are more efficient too. The installer
+could also check for @samp{DEFTAPE} in @file{<sys/mtio.h>}.
+
+@table @kbd
+@item --force-local
+Archive file is local even if it contains a colon.
+
+@item --rsh-command=@var{command}
+Use remote @var{command} instead of @command{rsh}. This option exists
+so that people who use something other than the standard @command{rsh}
+(e.g., a Kerberized @command{rsh}) can access a remote device.
+
+When this command is not used, the shell command found when
+the @command{tar} program was installed is used instead. This is
+the first found of @file{/usr/ucb/rsh}, @file{/usr/bin/remsh},
+@file{/usr/bin/rsh}, @file{/usr/bsd/rsh} or @file{/usr/bin/nsh}.
+The installer may have overridden this by defining the environment
+variable @env{RSH} @emph{at installation time}.
+
+@item -[0-7][lmh]
+Specify drive and density.
+
+@item -M
+@itemx --multi-volume
+Create/list/extract multi-volume archive.
+
+This option causes @command{tar} to write a @dfn{multi-volume} archive---one
+that may be larger than will fit on the medium used to hold it.
+@xref{Multi-Volume Archives}.
+
+@item -L @var{num}
+@itemx --tape-length=@var{num}
+Change tape after writing @var{num} x 1024 bytes.
+
+This option might be useful when your tape drivers do not properly
+detect end of physical tapes. By being slightly conservative on the
+maximum tape length, you might avoid the problem entirely.
+
+@item -F @var{file}
+@itemx --info-script=@var{file}
+@itemx --new-volume-script=@var{file}
+Execute @file{file} at end of each tape. If @file{file} exits with
+nonzero status, exit. This implies @value{op-multi-volume}.
+@end table
+
+@node Remote Tape Server
+@section The Remote Tape Server
+
+@cindex remote tape drive
+@pindex rmt
+In order to access the tape drive on a remote machine, @command{tar}
+uses the remote tape server written at the University of California at
+Berkeley. The remote tape server must be installed as @file{/etc/rmt}
+on any machine whose tape drive you want to use. @command{tar} calls
+@file{/etc/rmt} by running an @command{rsh} or @command{remsh} to the remote
+machine, optionally using a different login name if one is supplied.
+
+A copy of the source for the remote tape server is provided. It is
+Copyright @copyright{} 1983 by the Regents of the University of
+California, but can be freely distributed. Instructions for compiling
+and installing it are included in the @file{Makefile}.
+
+@cindex absolute file names
+Unless you use the @value{op-absolute-names} option, @sc{gnu} @command{tar} will
+not allow you to create an archive that contains absolute file names
+(a file name beginning with @samp{/}.) If you try, @command{tar} will
+automatically remove the leading @samp{/} from the file names it
+stores in the archive. It will also type a warning message telling
+you what it is doing.
+
+When reading an archive that was created with a different @command{tar}
+program, @sc{gnu} @command{tar} automatically extracts entries in the archive
+which have absolute file names as if the file names were not absolute.
+This is an important feature. A visitor here once gave a
+@command{tar} tape to an operator to restore; the operator used Sun @command{tar}
+instead of @sc{gnu} @command{tar}, and the result was that it replaced large
+portions of our @file{/bin} and friends with versions from the tape;
+needless to say, we were unhappy about having to recover the file system
+from backup tapes.
+
+For example, if the archive contained a file @file{/usr/bin/computoy},
+@sc{gnu} @command{tar} would extract the file to @file{usr/bin/computoy},
+relative to the current directory. If you want to extract the files in
+an archive to the same absolute names that they had when the archive
+was created, you should do a @samp{cd /} before extracting the files
+from the archive, or you should either use the @value{op-absolute-names}
+option, or use the command @samp{tar -C / @dots{}}.
+
+@cindex Ultrix 3.1 and write failure
+Some versions of Unix (Ultrix 3.1 is known to have this problem),
+can claim that a short write near the end of a tape succeeded,
+when it actually failed. This will result in the -M option not
+working correctly. The best workaround at the moment is to use a
+significantly larger blocking factor than the default 20.
+
+In order to update an archive, @command{tar} must be able to backspace the
+archive in order to reread or rewrite a record that was just read (or
+written). This is currently possible only on two kinds of files: normal
+disk files (or any other file that can be backspaced with @samp{lseek}),
+and industry-standard 9-track magnetic tape (or any other kind of tape
+that can be backspaced with the @code{MTIOCTOP} @code{ioctl}.
+
+This means that the @value{op-append}, @value{op-update},
+@value{op-concatenate}, and @value{op-delete} commands will not work on any
+other kind of file. Some media simply cannot be backspaced, which
+means these commands and options will never be able to work on them.
+These non-backspacing media include pipes and cartridge tape drives.
+
+Some other media can be backspaced, and @command{tar} will work on them
+once @command{tar} is modified to do so.
+
+Archives created with the @value{op-multi-volume}, @value{op-label}, and
+@value{op-incremental} options may not be readable by other version
+of @command{tar}. In particular, restoring a file that was split over
+a volume boundary will require some careful work with @command{dd}, if
+it can be done at all. Other versions of @command{tar} may also create
+an empty file whose name is that of the volume header. Some versions
+of @command{tar} may create normal files instead of directories archived
+with the @value{op-incremental} option.
+
+@node Common Problems and Solutions
+@section Some Common Problems and their Solutions
+
+@ifclear PUBLISH
+
+@format
+errors from system:
+permission denied
+no such file or directory
+not owner
+
+errors from @command{tar}:
+directory checksum error
+header format error
+
+errors from media/system:
+i/o error
+device busy
+@end format
+
+@end ifclear
+
+@node Blocking
+@section Blocking
+@UNREVISED
+
+@dfn{Block} and @dfn{record} terminology is rather confused, and it
+is also confusing to the expert reader. On the other hand, readers
+who are new to the field have a fresh mind, and they may safely skip
+the next two paragraphs, as the remainder of this manual uses those
+two terms in a quite consistent way.
+
+John Gilmore, the writer of the public domain @command{tar} from which
+@sc{gnu} @command{tar} was originally derived, wrote (June 1995):
+
+@quotation
+The nomenclature of tape drives comes from IBM, where I believe
+they were invented for the IBM 650 or so. On IBM mainframes, what
+is recorded on tape are tape blocks. The logical organization of
+data is into records. There are various ways of putting records into
+blocks, including @code{F} (fixed sized records), @code{V} (variable
+sized records), @code{FB} (fixed blocked: fixed size records, @var{n}
+to a block), @code{VB} (variable size records, @var{n} to a block),
+@code{VSB} (variable spanned blocked: variable sized records that can
+occupy more than one block), etc. The @code{JCL} @samp{DD RECFORM=}
+parameter specified this to the operating system.
+
+The Unix man page on @command{tar} was totally confused about this.
+When I wrote @code{PD TAR}, I used the historically correct terminology
+(@command{tar} writes data records, which are grouped into blocks).
+It appears that the bogus terminology made it into @sc{posix} (no surprise
+here), and now Fran@,{c}ois has migrated that terminology back
+into the source code too.
+@end quotation
+
+The term @dfn{physical block} means the basic transfer chunk from or
+to a device, after which reading or writing may stop without anything
+being lost. In this manual, the term @dfn{block} usually refers to
+a disk physical block, @emph{assuming} that each disk block is 512
+bytes in length. It is true that some disk devices have different
+physical blocks, but @command{tar} ignore these differences in its own
+format, which is meant to be portable, so a @command{tar} block is always
+512 bytes in length, and @dfn{block} always mean a @command{tar} block.
+The term @dfn{logical block} often represents the basic chunk of
+allocation of many disk blocks as a single entity, which the operating
+system treats somewhat atomically; this concept is only barely used
+in @sc{gnu} @command{tar}.
+
+The term @dfn{physical record} is another way to speak of a physical
+block, those two terms are somewhat interchangeable. In this manual,
+the term @dfn{record} usually refers to a tape physical block,
+@emph{assuming} that the @command{tar} archive is kept on magnetic tape.
+It is true that archives may be put on disk or used with pipes,
+but nevertheless, @command{tar} tries to read and write the archive one
+@dfn{record} at a time, whatever the medium in use. One record is made
+up of an integral number of blocks, and this operation of putting many
+disk blocks into a single tape block is called @dfn{reblocking}, or
+more simply, @dfn{blocking}. The term @dfn{logical record} refers to
+the logical organization of many characters into something meaningful
+to the application. The term @dfn{unit record} describes a small set
+of characters which are transmitted whole to or by the application,
+and often refers to a line of text. Those two last terms are unrelated
+to what we call a @dfn{record} in @sc{gnu} @command{tar}.
+
+When writing to tapes, @command{tar} writes the contents of the archive
+in chunks known as @dfn{records}. To change the default blocking
+factor, use the @value{op-blocking-factor} option. Each record will
+then be composed of @var{512-size} blocks. (Each @command{tar} block is
+512 bytes. @xref{Standard}.) Each file written to the archive uses
+at least one full record. As a result, using a larger record size
+can result in more wasted space for small files. On the other hand, a
+larger record size can often be read and written much more efficiently.
+
+Further complicating the problem is that some tape drives ignore the
+blocking entirely. For these, a larger record size can still improve
+performance (because the software layers above the tape drive still
+honor the blocking), but not as dramatically as on tape drives that
+honor blocking.
+
+When reading an archive, @command{tar} can usually figure out the record
+size on itself. When this is the case, and a non-standard record size
+was used when the archive was created, @command{tar} will print a message
+about a non-standard blocking factor, and then operate normally. On
+some tape devices, however, @command{tar} cannot figure out the record size
+itself. On most of those, you can specify a blocking factor (with
+@value{op-blocking-factor}) larger than the actual blocking factor, and then use
+the @value{op-read-full-records} option. (If you specify a blocking factor
+with @value{op-blocking-factor} and don't use the @value{op-read-full-records}
+option, then @command{tar} will not attempt to figure out the recording size
+itself.) On some devices, you must always specify the record size
+exactly with @value{op-blocking-factor} when reading, because @command{tar} cannot
+figure it out. In any case, use @value{op-list} before doing any
+extractions to see whether @command{tar} is reading the archive correctly.
+
+@command{tar} blocks are all fixed size (512 bytes), and its scheme for
+putting them into records is to put a whole number of them (one or
+more) into each record. @command{tar} records are all the same size;
+at the end of the file there's a block containing all zeros, which
+is how you tell that the remainder of the last record(s) are garbage.
+
+In a standard @command{tar} file (no options), the block size is 512
+and the record size is 10240, for a blocking factor of 20. What the
+@value{op-blocking-factor} option does is sets the blocking factor,
+changing the record size while leaving the block size at 512 bytes.
+20 was fine for ancient 800 or 1600 bpi reel-to-reel tape drives;
+most tape drives these days prefer much bigger records in order to
+stream and not waste tape. When writing tapes for myself, some tend
+to use a factor of the order of 2048, say, giving a record size of
+around one megabyte.
+
+If you use a blocking factor larger than 20, older @command{tar} programs
+might not be able to read the archive, so we recommend this as a limit
+to use in practice. @sc{gnu} @command{tar}, however, will support arbitrarily
+large record sizes, limited only by the amount of virtual memory or the
+physical characteristics of the tape device.
+
+@menu
+* Format Variations:: Format Variations
+* Blocking Factor:: The Blocking Factor of an Archive
+@end menu
+
+@node Format Variations
+@subsection Format Variations
+@cindex Format Parameters
+@cindex Format Options
+@cindex Options, archive format specifying
+@cindex Options, format specifying
+@UNREVISED
+
+Format parameters specify how an archive is written on the archive
+media. The best choice of format parameters will vary depending on
+the type and number of files being archived, and on the media used to
+store the archive.
+
+To specify format parameters when accessing or creating an archive,
+you can use the options described in the following sections.
+If you do not specify any format parameters, @command{tar} uses
+default parameters. You cannot modify a compressed archive.
+If you create an archive with the @value{op-blocking-factor} option
+specified (@value{pxref-blocking-factor}), you must specify that
+blocking-factor when operating on the archive. @xref{Formats}, for other
+examples of format parameter considerations.
+
+@node Blocking Factor
+@subsection The Blocking Factor of an Archive
+@cindex Blocking Factor
+@cindex Record Size
+@cindex Number of blocks per record
+@cindex Number of bytes per record
+@cindex Bytes per record
+@cindex Blocks per record
+@UNREVISED
+
+The data in an archive is grouped into blocks, which are 512 bytes.
+Blocks are read and written in whole number multiples called
+@dfn{records}. The number of blocks in a record (ie. the size of a
+record in units of 512 bytes) is called the @dfn{blocking factor}.
+The @value{op-blocking-factor} option specifies the blocking factor of
+an archive. The default blocking factor is typically 20 (ie.@:
+10240 bytes), but can be specified at installation. To find out
+the blocking factor of an existing archive, use @samp{tar --list
+--file=@var{archive-name}}. This may not work on some devices.
+
+Records are separated by gaps, which waste space on the archive media.
+If you are archiving on magnetic tape, using a larger blocking factor
+(and therefore larger records) provides faster throughput and allows you
+to fit more data on a tape (because there are fewer gaps). If you are
+archiving on cartridge, a very large blocking factor (say 126 or more)
+greatly increases performance. A smaller blocking factor, on the other
+hand, may be useful when archiving small files, to avoid archiving lots
+of nulls as @command{tar} fills out the archive to the end of the record.
+In general, the ideal record size depends on the size of the
+inter-record gaps on the tape you are using, and the average size of the
+files you are archiving. @xref{create}, for information on
+writing archives.
+
+@FIXME{Need example of using a cartridge with blocking factor=126 or more.}
+
+Archives with blocking factors larger than 20 cannot be read
+by very old versions of @command{tar}, or by some newer versions
+of @command{tar} running on old machines with small address spaces.
+With @sc{gnu} @command{tar}, the blocking factor of an archive is limited
+only by the maximum record size of the device containing the archive,
+or by the amount of available virtual memory.
+
+Also, on some systems, not using adequate blocking factors, as sometimes
+imposed by the device drivers, may yield unexpected diagnostics. For
+example, this has been reported:
+
+@example
+Cannot write to /dev/dlt: Invalid argument
+@end example
+
+@noindent
+In such cases, it sometimes happen that the @command{tar} bundled by the
+system is aware of block size idiosyncrasies, while @sc{gnu} @command{tar} requires
+an explicit specification for the block size, which it cannot guess.
+This yields some people to consider @sc{gnu} @command{tar} is misbehaving, because
+by comparison, @cite{the bundle @command{tar} works OK}. Adding @w{@kbd{-b
+256}}, for example, might resolve the problem.
+
+If you use a non-default blocking factor when you create an archive, you
+must specify the same blocking factor when you modify that archive. Some
+archive devices will also require you to specify the blocking factor when
+reading that archive, however this is not typically the case. Usually, you
+can use @value{op-list} without specifying a blocking factor---@command{tar}
+reports a non-default record size and then lists the archive members as
+it would normally. To extract files from an archive with a non-standard
+blocking factor (particularly if you're not sure what the blocking factor
+is), you can usually use the @value{op-read-full-records} option while
+specifying a blocking factor larger then the blocking factor of the archive
+(ie. @samp{tar --extract --read-full-records --blocking-factor=300}.
+@xref{list}, for more information on the @value{op-list}
+operation. @xref{Reading}, for a more detailed explanation of that option.
+
+@table @kbd
+@item --blocking-factor=@var{number}
+@itemx -b @var{number}
+Specifies the blocking factor of an archive. Can be used with any
+operation, but is usually not necessary with @value{op-list}.
+@end table
+
+Device blocking
+
+@table @kbd
+@item -b @var{blocks}
+@itemx --blocking-factor=@var{blocks}
+Set record size to @math{@var{blocks} * 512} bytes.
+
+This option is used to specify a @dfn{blocking factor} for the archive.
+When reading or writing the archive, @command{tar}, will do reads and writes
+of the archive in records of @math{@var{block}*512} bytes. This is true
+even when the archive is compressed. Some devices requires that all
+write operations be a multiple of a certain size, and so, @command{tar}
+pads the archive out to the next record boundary.
+
+The default blocking factor is set when @command{tar} is compiled, and is
+typically 20. Blocking factors larger than 20 cannot be read by very
+old versions of @command{tar}, or by some newer versions of @command{tar}
+running on old machines with small address spaces.
+
+With a magnetic tape, larger records give faster throughput and fit
+more data on a tape (because there are fewer inter-record gaps).
+If the archive is in a disk file or a pipe, you may want to specify
+a smaller blocking factor, since a large one will result in a large
+number of null bytes at the end of the archive.
+
+When writing cartridge or other streaming tapes, a much larger
+blocking factor (say 126 or more) will greatly increase performance.
+However, you must specify the same blocking factor when reading or
+updating the archive.
+
+Apparently, Exabyte drives have a physical block size of 8K bytes.
+If we choose our blocksize as a multiple of 8k bytes, then the problem
+seems to dissapper. Id est, we are using block size of 112 right
+now, and we haven't had the problem since we switched@dots{}
+
+With @sc{gnu} @command{tar} the blocking factor is limited only by the maximum
+record size of the device containing the archive, or by the amount of
+available virtual memory.
+
+However, deblocking or reblocking is virtually avoided in a special
+case which often occurs in practice, but which requires all the
+following conditions to be simultaneously true:
+@itemize @bullet
+@item
+the archive is subject to a compression option,
+@item
+the archive is not handled through standard input or output, nor
+redirected nor piped,
+@item
+the archive is directly handled to a local disk, instead of any special
+device,
+@item
+@value{op-blocking-factor} is not explicitly specified on the @command{tar}
+invocation.
+@end itemize
+
+In previous versions of @sc{gnu} @command{tar}, the @samp{--compress-block}
+option (or even older: @samp{--block-compress}) was necessary to
+reblock compressed archives. It is now a dummy option just asking
+not to be used, and otherwise ignored. If the output goes directly
+to a local disk, and not through stdout, then the last write is
+not extended to a full record size. Otherwise, reblocking occurs.
+Here are a few other remarks on this topic:
+
+@itemize @bullet
+
+@item
+@command{gzip} will complain about trailing garbage if asked to
+uncompress a compressed archive on tape, there is an option to turn
+the message off, but it breaks the regularity of simply having to use
+@samp{@var{prog} -d} for decompression. It would be nice if gzip was
+silently ignoring any number of trailing zeros. I'll ask Jean-loup
+Gailly, by sending a copy of this message to him.
+
+@item
+@command{compress} does not show this problem, but as Jean-loup pointed
+out to Michael, @samp{compress -d} silently adds garbage after
+the result of decompression, which tar ignores because it already
+recognized its end-of-file indicator. So this bug may be safely
+ignored.
+
+@item
+@samp{gzip -d -q} will be silent about the trailing zeros indeed,
+but will still return an exit status of 2 which tar reports in turn.
+@command{tar} might ignore the exit status returned, but I hate doing
+that, as it weakens the protection @command{tar} offers users against
+other possible problems at decompression time. If @command{gzip} was
+silently skipping trailing zeros @emph{and} also avoiding setting the
+exit status in this innocuous case, that would solve this situation.
+
+@item
+@command{tar} should become more solid at not stopping to read a pipe at
+the first null block encountered. This inelegantly breaks the pipe.
+@command{tar} should rather drain the pipe out before exiting itself.
+@end itemize
+
+@item -i
+@itemx --ignore-zeros
+Ignore blocks of zeros in archive (means EOF).
+
+The @value{op-ignore-zeros} option causes @command{tar} to ignore blocks
+of zeros in the archive. Normally a block of zeros indicates the
+end of the archive, but when reading a damaged archive, or one which
+was created by concatenating several archives together, this option
+allows @command{tar} to read the entire archive. This option is not on
+by default because many versions of @command{tar} write garbage after
+the zeroed blocks.
+
+Note that this option causes @command{tar} to read to the end of the
+archive file, which may sometimes avoid problems when multiple files
+are stored on a single physical tape.
+
+@item -B
+@itemx --read-full-records
+Reblock as we read (for reading 4.2BSD pipes).
+
+If @value{op-read-full-records} is used, @command{tar} will not panic if an
+attempt to read a record from the archive does not return a full record.
+Instead, @command{tar} will keep reading until it has obtained a full
+record.
+
+This option is turned on by default when @command{tar} is reading
+an archive from standard input, or from a remote machine. This is
+because on BSD Unix systems, a read of a pipe will return however
+much happens to be in the pipe, even if it is less than @command{tar}
+requested. If this option was not used, @command{tar} would fail as
+soon as it read an incomplete record from the pipe.
+
+This option is also useful with the commands for updating an archive.
+
+@end table
+
+Tape blocking
+
+@FIXME{Appropriate options should be moved here from elsewhere.}
+
+@cindex blocking factor
+@cindex tape blocking
+
+When handling various tapes or cartridges, you have to take care of
+selecting a proper blocking, that is, the number of disk blocks you
+put together as a single tape block on the tape, without intervening
+tape gaps. A @dfn{tape gap} is a small landing area on the tape
+with no information on it, used for decelerating the tape to a
+full stop, and for later regaining the reading or writing speed.
+When the tape driver starts reading a record, the record has to
+be read whole without stopping, as a tape gap is needed to stop the
+tape motion without loosing information.
+
+@cindex Exabyte blocking
+@cindex DAT blocking
+Using higher blocking (putting more disk blocks per tape block) will use
+the tape more efficiently as there will be less tape gaps. But reading
+such tapes may be more difficult for the system, as more memory will be
+required to receive at once the whole record. Further, if there is a
+reading error on a huge record, this is less likely that the system will
+succeed in recovering the information. So, blocking should not be too
+low, nor it should be too high. @command{tar} uses by default a blocking of
+20 for historical reasons, and it does not really matter when reading or
+writing to disk. Current tape technology would easily accommodate higher
+blockings. Sun recommends a blocking of 126 for Exabytes and 96 for DATs.
+We were told that for some DLT drives, the blocking should be a multiple
+of 4Kb, preferably 64Kb (@w{@kbd{-b 128}}) or 256 for decent performance.
+Other manufacturers may use different recommendations for the same tapes.
+This might also depends of the buffering techniques used inside modern
+tape controllers. Some imposes a minimum blocking, or a maximum blocking.
+Others request blocking to be some exponent of two.
+
+So, there is no fixed rule for blocking. But blocking at read time
+should ideally be the same as blocking used at write time. At one place
+I know, with a wide variety of equipment, they found it best to use a
+blocking of 32 to guarantee that their tapes are fully interchangeable.
+
+I was also told that, for recycled tapes, prior erasure (by the same
+drive unit that will be used to create the archives) sometimes lowers
+the error rates observed at rewriting time.
+
+I might also use @samp{--number-blocks} instead of
+@samp{--block-number}, so @samp{--block} will then expand to
+@samp{--blocking-factor} unambiguously.
+
+@node Many
+@section Many Archives on One Tape
+
+@FIXME{Appropriate options should be moved here from elsewhere.}
+
+@findex ntape @r{device}
+Most tape devices have two entries in the @file{/dev} directory, or
+entries that come in pairs, which differ only in the minor number for
+this device. Let's take for example @file{/dev/tape}, which often
+points to the only or usual tape device of a given system. There might
+be a corresponding @file{/dev/nrtape} or @file{/dev/ntape}. The simpler
+name is the @emph{rewinding} version of the device, while the name
+having @samp{nr} in it is the @emph{no rewinding} version of the same
+device.
+
+A rewinding tape device will bring back the tape to its beginning point
+automatically when this device is opened or closed. Since @command{tar}
+opens the archive file before using it and closes it afterwards, this
+means that a simple:
+
+@example
+$ @kbd{tar cf /dev/tape @var{directory}}
+@end example
+
+@noindent
+will reposition the tape to its beginning both prior and after saving
+@var{directory} contents to it, thus erasing prior tape contents and
+making it so that any subsequent write operation will destroy what has
+just been saved.
+
+@cindex tape positioning
+So, a rewinding device is normally meant to hold one and only one file.
+If you want to put more than one @command{tar} archive on a given tape, you
+will need to avoid using the rewinding version of the tape device. You
+will also have to pay special attention to tape positioning. Errors in
+positioning may overwrite the valuable data already on your tape. Many
+people, burnt by past experiences, will only use rewinding devices and
+limit themselves to one file per tape, precisely to avoid the risk of
+such errors. Be fully aware that writing at the wrong position on a
+tape loses all information past this point and most probably until the
+end of the tape, and this destroyed information @emph{cannot} be
+recovered.
+
+To save @var{directory-1} as a first archive at the beginning of a
+tape, and leave that tape ready for a second archive, you should use:
+
+@example
+$ @kbd{mt -f /dev/nrtape rewind}
+$ @kbd{tar cf /dev/nrtape @var{directory-1}}
+@end example
+
+@cindex tape marks
+@dfn{Tape marks} are special magnetic patterns written on the tape
+media, which are later recognizable by the reading hardware. These
+marks are used after each file, when there are many on a single tape.
+An empty file (that is to say, two tape marks in a row) signal the
+logical end of the tape, after which no file exist. Usually,
+non-rewinding tape device drivers will react to the close request issued
+by @command{tar} by first writing two tape marks after your archive, and by
+backspacing over one of these. So, if you remove the tape at that time
+from the tape drive, it is properly terminated. But if you write
+another file at the current position, the second tape mark will be
+erased by the new information, leaving only one tape mark between files.
+
+So, you may now save @var{directory-2} as a second archive after the
+first on the same tape by issuing the command:
+
+@example
+$ @kbd{tar cf /dev/nrtape @var{directory-2}}
+@end example
+
+@noindent
+and so on for all the archives you want to put on the same tape.
+
+Another usual case is that you do not write all the archives the same
+day, and you need to remove and store the tape between two archive
+sessions. In general, you must remember how many files are already
+saved on your tape. Suppose your tape already has 16 files on it, and
+that you are ready to write the 17th. You have to take care of skipping
+the first 16 tape marks before saving @var{directory-17}, say, by using
+these commands:
+
+@example
+$ @kbd{mt -f /dev/nrtape rewind}
+$ @kbd{mt -f /dev/nrtape fsf 16}
+$ @kbd{tar cf /dev/nrtape @var{directory-17}}
+@end example
+
+In all the previous examples, we put aside blocking considerations, but
+you should do the proper things for that as well. @xref{Blocking}.
+
+@menu
+* Tape Positioning:: Tape Positions and Tape Marks
+* mt:: The @command{mt} Utility
+@end menu
+
+@node Tape Positioning
+@subsection Tape Positions and Tape Marks
+@UNREVISED
+
+Just as archives can store more than one file from the file system,
+tapes can store more than one archive file. To keep track of where
+archive files (or any other type of file stored on tape) begin and
+end, tape archive devices write magnetic @dfn{tape marks} on the
+archive media. Tape drives write one tape mark between files,
+two at the end of all the file entries.
+
+If you think of data as a series of records "rrrr"'s, and tape marks as
+"*"'s, a tape might look like the following:
+
+@example
+rrrr*rrrrrr*rrrrr*rr*rrrrr**-------------------------
+@end example
+
+Tape devices read and write tapes using a read/write @dfn{tape
+head}---a physical part of the device which can only access one
+point on the tape at a time. When you use @command{tar} to read or
+write archive data from a tape device, the device will begin reading
+or writing from wherever on the tape the tape head happens to be,
+regardless of which archive or what part of the archive the tape
+head is on. Before writing an archive, you should make sure that no
+data on the tape will be overwritten (unless it is no longer needed).
+Before reading an archive, you should make sure the tape head is at
+the beginning of the archive you want to read. (The @code{restore}
+script will find the archive automatically. @FIXME{There is no such
+restore script!}@FIXME-xref{Scripted Restoration}@xref{mt}, for
+an explanation of the tape moving utility.
+
+If you want to add new archive file entries to a tape, you should
+advance the tape to the end of the existing file entries, backspace
+over the last tape mark, and write the new archive file. If you were
+to add two archives to the example above, the tape might look like the
+following:
+
+@example
+rrrr*rrrrrr*rrrrr*rr*rrrrr*rrr*rrrr**----------------
+@end example
+
+@node mt
+@subsection The @command{mt} Utility
+@UNREVISED
+
+@FIXME{Is it true that this only works on non-block devices?
+should explain the difference, (fixed or variable).}
+@value{xref-blocking-factor}.
+
+You can use the @command{mt} utility to advance or rewind a tape past a
+specified number of archive files on the tape. This will allow you
+to move to the beginning of an archive before extracting or reading
+it, or to the end of all the archives before writing a new one.
+@FIXME{Why isn't there an "advance 'til you find two tape marks
+together"?}
+
+The syntax of the @command{mt} command is:
+
+@example
+@kbd{mt [-f @var{tapename}] @var{operation} [@var{number}]}
+@end example
+
+where @var{tapename} is the name of the tape device, @var{number} is
+the number of times an operation is performed (with a default of one),
+and @var{operation} is one of the following:
+
+@FIXME{is there any use for record operations?}
+
+@table @kbd
+@item eof
+@itemx weof
+Writes @var{number} tape marks at the current position on the tape.
+
+@item fsf
+Moves tape position forward @var{number} files.
+
+@item bsf
+Moves tape position back @var{number} files.
+
+@item rewind
+Rewinds the tape. (Ignores @var{number}).
+
+@item offline
+@itemx rewoff1
+Rewinds the tape and takes the tape device off-line. (Ignores @var{number}).
+
+@item status
+Prints status information about the tape unit.
+
+@end table
+
+@FIXME{Is there a better way to frob the spacing on the list?}
+
+If you don't specify a @var{tapename}, @command{mt} uses the environment
+variable @env{TAPE}; if @env{TAPE} is not set, @command{mt} uses the device
+@file{/dev/rmt12}.
+
+@command{mt} returns a 0 exit status when the operation(s) were
+successful, 1 if the command was unrecognized, and 2 if an operation
+failed.
+
+@FIXME{New node on how to find an archive?}
+
+If you use @value{op-extract} with the @value{op-label} option specified,
+@command{tar} will read an archive label (the tape head has to be positioned
+on it) and print an error if the archive label doesn't match the
+@var{archive-name} specified. @var{archive-name} can be any regular
+expression. If the labels match, @command{tar} extracts the archive.
+@value{xref-label}.
+@FIXME-xref{Matching Format Parameters}@FIXME{fix cross
+references}@samp{tar --list --label} will cause @command{tar} to print the
+label.
+
+@FIXME{Program to list all the labels on a tape?}
+
+@node Using Multiple Tapes
+@section Using Multiple Tapes
+@UNREVISED
+
+Often you might want to write a large archive, one larger than will fit
+on the actual tape you are using. In such a case, you can run multiple
+@command{tar} commands, but this can be inconvenient, particularly if you
+are using options like @value{op-exclude} or dumping entire filesystems.
+Therefore, @command{tar} supports multiple tapes automatically.
+
+Use @value{op-multi-volume} on the command line, and then @command{tar} will,
+when it reaches the end of the tape, prompt for another tape, and
+continue the archive. Each tape will have an independent archive, and
+can be read without needing the other. (As an exception to this, the
+file that @command{tar} was archiving when it ran out of tape will usually
+be split between the two archives; in this case you need to extract from
+the first archive, using @value{op-multi-volume}, and then put in the
+second tape when prompted, so @command{tar} can restore both halves of the
+file.)
+
+@sc{gnu} @command{tar} multi-volume archives do not use a truly portable format.
+You need @sc{gnu} @command{tar} at both end to process them properly.
+
+When prompting for a new tape, @command{tar} accepts any of the following
+responses:
+
+@table @kbd
+@item ?
+Request @command{tar} to explain possible responses
+@item q
+Request @command{tar} to exit immediately.
+@item n @var{file name}
+Request @command{tar} to write the next volume on the file @var{file name}.
+@item !
+Request @command{tar} to run a subshell.
+@item y
+Request @command{tar} to begin writing the next volume.
+@end table
+
+(You should only type @samp{y} after you have changed the tape;
+otherwise @command{tar} will write over the volume it just finished.)
+
+If you want more elaborate behavior than this, give @command{tar} the
+@value{op-info-script} option. The file @var{script-name} is expected
+to be a program (or shell script) to be run instead of the normal
+prompting procedure. If the program fails, @command{tar} exits;
+otherwise, @command{tar} begins writing the next volume. The behavior
+of the
+@samp{n} response to the normal tape-change prompt is not available
+if you use @value{op-info-script}.
+
+The method @command{tar} uses to detect end of tape is not perfect, and
+fails on some operating systems or on some devices. You can use the
+@value{op-tape-length} option if @command{tar} can't detect the end of the
+tape itself. This option selects @value{op-multi-volume} automatically.
+The @var{size} argument should then be the usable size of the tape.
+But for many devices, and floppy disks in particular, this option is
+never required for real, as far as we know.
+
+The volume number used by @command{tar} in its tape-change prompt
+can be changed; if you give the @value{op-volno-file} option, then
+@var{file-of-number} should be an unexisting file to be created, or else,
+a file already containing a decimal number. That number will be used
+as the volume number of the first volume written. When @command{tar} is
+finished, it will rewrite the file with the now-current volume number.
+(This does not change the volume number written on a tape label, as
+per @value{ref-label}, it @emph{only} affects the number used in
+the prompt.)
+
+If you want @command{tar} to cycle through a series of tape drives, then
+you can use the @samp{n} response to the tape-change prompt. This is
+error prone, however, and doesn't work at all with @value{op-info-script}.
+Therefore, if you give @command{tar} multiple @value{op-file} options, then
+the specified files will be used, in sequence, as the successive volumes
+of the archive. Only when the first one in the sequence needs to be
+used again will @command{tar} prompt for a tape change (or run the info
+script).
+
+Multi-volume archives
+
+With @value{op-multi-volume}, @command{tar} will not abort when it cannot
+read or write any more data. Instead, it will ask you to prepare a new
+volume. If the archive is on a magnetic tape, you should change tapes
+now; if the archive is on a floppy disk, you should change disks, etc.
+
+Each volume of a multi-volume archive is an independent @command{tar}
+archive, complete in itself. For example, you can list or extract any
+volume alone; just don't specify @value{op-multi-volume}. However, if one
+file in the archive is split across volumes, the only way to extract
+it successfully is with a multi-volume extract command @samp{--extract
+--multi-volume} (@samp{-xM}) starting on or before the volume where
+the file begins.
+
+For example, let's presume someone has two tape drives on a system
+named @file{/dev/tape0} and @file{/dev/tape1}. For having @sc{gnu}
+@command{tar} to switch to the second drive when it needs to write the
+second tape, and then back to the first tape, etc., just do either of:
+
+@smallexample
+$ @kbd{tar --create --multi-volume --file=/dev/tape0 --file=/dev/tape1 @var{files}}
+$ @kbd{tar cMff /dev/tape0 /dev/tape1 @var{files}}
+@end smallexample
+
+@menu
+* Multi-Volume Archives:: Archives Longer than One Tape or Disk
+* Tape Files:: Tape Files
+@end menu
+
+@node Multi-Volume Archives
+@subsection Archives Longer than One Tape or Disk
+@cindex Multi-volume archives
+@UNREVISED
+
+To create an archive that is larger than will fit on a single unit of
+the media, use the @value{op-multi-volume} option in conjunction with
+the @value{op-create} option (@pxref{create}). A
+@dfn{multi-volume} archive can be manipulated like any other archive
+(provided the @value{op-multi-volume} option is specified), but is
+stored on more than one tape or disk.
+
+When you specify @value{op-multi-volume}, @command{tar} does not report an
+error when it comes to the end of an archive volume (when reading), or
+the end of the media (when writing). Instead, it prompts you to load
+a new storage volume. If the archive is on a magnetic tape, you
+should change tapes when you see the prompt; if the archive is on a
+floppy disk, you should change disks; etc.
+
+You can read each individual volume of a multi-volume archive as if it
+were an archive by itself. For example, to list the contents of one
+volume, use @value{op-list}, without @value{op-multi-volume} specified.
+To extract an archive member from one volume (assuming it is described
+that volume), use @value{op-extract}, again without
+@value{op-multi-volume}.
+
+If an archive member is split across volumes (ie. its entry begins on
+one volume of the media and ends on another), you need to specify
+@value{op-multi-volume} to extract it successfully. In this case, you
+should load the volume where the archive member starts, and use
+@samp{tar --extract --multi-volume}---@command{tar} will prompt for later
+volumes as it needs them. @xref{extracting archives}, for more
+information about extracting archives.
+
+@value{op-info-script} is like @value{op-multi-volume}, except that
+@command{tar} does not prompt you directly to change media volumes when
+a volume is full---instead, @command{tar} runs commands you have stored
+in @var{script-name}. For example, this option can be used to eject
+cassettes, or to broadcast messages such as @samp{Someone please come
+change my tape} when performing unattended backups. When @var{script-name}
+is done, @command{tar} will assume that the media has been changed.
+
+Multi-volume archives can be modified like any other archive. To add
+files to a multi-volume archive, you need to only mount the last
+volume of the archive media (and new volumes, if needed). For all
+other operations, you need to use the entire archive.
+
+If a multi-volume archive was labeled using @value{op-label}
+(@value{pxref-label}) when it was created, @command{tar} will not
+automatically label volumes which are added later. To label subsequent
+volumes, specify @value{op-label} again in conjunction with the
+@value{op-append}, @value{op-update} or @value{op-concatenate} operation.
+
+@cindex Labeling multi-volume archives
+@FIXME{example}
+
+@FIXME{There should be a sample program here, including an exit
+before end. Is the exit status even checked in tar? :-(}
+
+@table @kbd
+@item --multi-volume
+@itemx -M
+Creates a multi-volume archive, when used in conjunction with
+@value{op-create}. To perform any other operation on a multi-volume
+archive, specify @value{op-multi-volume} in conjunction with that
+operation.
+
+@item --info-script=@var{program-file}
+@itemx -F @var{program-file}
+Creates a multi-volume archive via a script. Used in conjunction with
+@value{op-create}.
+@end table
+
+Beware that there is @emph{no} real standard about the proper way, for a
+@command{tar} archive, to span volume boundaries. If you have a multi-volume
+created by some vendor's @command{tar}, there is almost no chance you could
+read all the volumes with @sc{gnu} @command{tar}. The converse is also true:
+you may not expect multi-volume archives created by @sc{gnu} @command{tar} to
+be fully recovered by vendor's @command{tar}. Since there is little chance
+that, in mixed system configurations, some vendor's @command{tar} will work on
+another vendor's machine, and there is a great chance that @sc{gnu} @command{tar}
+will work on most of them, your best bet is to install @sc{gnu} @command{tar}
+on all machines between which you know exchange of files is possible.
+
+@node Tape Files
+@subsection Tape Files
+@UNREVISED
+
+To give the archive a name which will be recorded in it, use the
+@value{op-label} option. This will write a special block identifying
+@var{volume-label} as the name of the archive to the front of the archive
+which will be displayed when the archive is listed with @value{op-list}.
+If you are creating a multi-volume archive with
+@value{op-multi-volume}@FIXME-pxref{Using Multiple Tapes}, then the
+volume label will have
+@samp{Volume @var{nnn}} appended to the name you give, where @var{nnn} is
+the number of the volume of the archive. (If you use the @value{op-label}
+option when reading an archive, it checks to make sure the label on the
+tape matches the one you give. @value{xref-label}.
+
+When @command{tar} writes an archive to tape, it creates a single
+tape file. If multiple archives are written to the same tape, one
+after the other, they each get written as separate tape files. When
+extracting, it is necessary to position the tape at the right place
+before running @command{tar}. To do this, use the @command{mt} command.
+For more information on the @command{mt} command and on the organization
+of tapes into a sequence of tape files, see @ref{mt}.
+
+People seem to often do:
+
+@example
+@kbd{--label="@var{some-prefix} `date +@var{some-format}`"}
+@end example
+
+or such, for pushing a common date in all volumes or an archive set.
+
+@node label
+@section Including a Label in the Archive
+@cindex Labeling an archive
+@cindex Labels on the archive media
+@UNREVISED
+
+@table @kbd
+@item -V @var{name}
+@itemx --label=@var{name}
+Create archive with volume name @var{name}.
+@end table
+
+This option causes @command{tar} to write out a @dfn{volume header} at
+the beginning of the archive. If @value{op-multi-volume} is used, each
+volume of the archive will have a volume header of @samp{@var{name}
+Volume @var{n}}, where @var{n} is 1 for the first volume, 2 for the
+next, and so on.
+
+@FIXME{Should the arg to --label be a quoted string?? No.}
+
+To avoid problems caused by misplaced paper labels on the archive
+media, you can include a @dfn{label} entry---an archive member which
+contains the name of the archive---in the archive itself. Use the
+@value{op-label} option in conjunction with the @value{op-create} operation
+to include a label entry in the archive as it is being created.
+
+If you create an archive using both @value{op-label} and
+@value{op-multi-volume}, each volume of the archive will have an
+archive label of the form @samp{@var{archive-label} Volume @var{n}},
+where @var{n} is 1 for the first volume, 2 for the next, and so on.
+@FIXME-xref{Multi-Volume Archives, for information on creating multiple
+volume archives.}
+
+If you list or extract an archive using @value{op-label}, @command{tar} will
+print an error if the archive label doesn't match the @var{archive-label}
+specified, and will then not list nor extract the archive. In those cases,
+@var{archive-label} argument is interpreted as a globbing-style pattern
+which must match the actual magnetic volume label. @xref{exclude}, for
+a precise description of how match is attempted@footnote{Previous versions
+of @command{tar} used full regular expression matching, or before that, only
+exact string matching, instead of wildcard matchers. We decided for the
+sake of simplicity to use a uniform matching device through @command{tar}.}.
+If the switch @value{op-multi-volume} is being used, the volume label
+matcher will also suffix @var{archive-label} by @w{@samp{ Volume [1-9]*}}
+if the initial match fails, before giving up. Since the volume numbering
+is automatically added in labels at creation time, it sounded logical to
+equally help the user taking care of it when the archive is being read.
+
+The @value{op-label} was once called @samp{--volume}, but is not available
+under that name anymore.
+
+To find out an archive's label entry (or to find out if an archive has
+a label at all), use @samp{tar --list --verbose}. @command{tar} will print the
+label first, and then print archive member information, as in the
+example below:
+
+@example
+$ @kbd{tar --verbose --list --file=iamanarchive}
+V--------- 0 0 0 1992-03-07 12:01 iamalabel--Volume Header--
+-rw-rw-rw- ringo user 40 1990-05-21 13:30 iamafilename
+@end example
+
+@table @kbd
+@item --label=@var{archive-label}
+@itemx -V @var{archive-label}
+Includes an @dfn{archive-label} at the beginning of the archive when
+the archive is being created, when used in conjunction with the
+@value{op-create} option. Checks to make sure the archive label
+matches the one specified (when used in conjunction with the
+@value{op-extract} option.
+@end table
+
+To get a common information on all tapes of a series, use the
+@value{op-label} option. For having this information different in each
+series created through a single script used on a regular basis, just
+manage to get some date string as part of the label. For example:
+
+@example
+$ @kbd{tar cfMV /dev/tape "Daily backup for `date +%Y-%m-%d`"}
+$ @kbd{tar --create --file=/dev/tape --multi-volume \
+ --volume="Daily backup for `date +%Y-%m-%d`"}
+@end example
+
+Also note that each label has its own date and time, which corresponds
+to when @sc{gnu} @command{tar} initially attempted to write it, often soon
+after the operator launches @command{tar} or types the carriage return
+telling that the next tape is ready. Comparing date labels does give
+an idea of tape throughput only if the delays for rewinding tapes
+and the operator switching them were negligible, which is usually
+not the case.
+
+@FIXME{was --volume}
+
+@node verify
+@section Verifying Data as It is Stored
+@cindex Verifying a write operation
+@cindex Double-checking a write operation
+
+@table @kbd
+@item -W
+@itemx --verify
+Attempt to verify the archive after writing.
+@end table
+
+This option causes @command{tar} to verify the archive after writing it.
+Each volume is checked after it is written, and any discrepancies
+are recorded on the standard error output.
+
+Verification requires that the archive be on a back-space-able medium.
+This means pipes, some cartridge tape drives, and some other devices
+cannot be verified.
+
+You can insure the accuracy of an archive by comparing files in the
+system with archive members. @command{tar} can compare an archive to the
+file system as the archive is being written, to verify a write
+operation, or can compare a previously written archive, to insure that
+it is up to date.
+
+To check for discrepancies in an archive immediately after it is
+written, use the @value{op-verify} option in conjunction with
+the @value{op-create} operation. When this option is
+specified, @command{tar} checks archive members against their counterparts
+in the file system, and reports discrepancies on the standard error.
+
+To verify an archive, you must be able to read it from before the end
+of the last written entry. This option is useful for detecting data
+errors on some tapes. Archives written to pipes, some cartridge tape
+drives, and some other devices cannot be verified.
+
+One can explicitly compare an already made archive with the file system
+by using the @value{op-compare} option, instead of using the more automatic
+@value{op-verify} option. @value{xref-compare}.
+
+Note that these two options have a slightly different intent. The
+@value{op-compare} option how identical are the logical contents of some
+archive with what is on your disks, while the @value{op-verify} option is
+really for checking if the physical contents agree and if the recording
+media itself is of dependable quality. So, for the @value{op-verify}
+operation, @command{tar} tries to defeat all in-memory cache pertaining to
+the archive, while it lets the speed optimization undisturbed for the
+@value{op-compare} option. If you nevertheless use @value{op-compare} for
+media verification, you may have to defeat the in-memory cache yourself,
+maybe by opening and reclosing the door latch of your recording unit,
+forcing some doubt in your operating system about the fact this is really
+the same volume as the one just written or read.
+
+The @value{op-verify} option would not be necessary if drivers were indeed
+able to detect dependably all write failures. This sometimes require many
+magnetic heads, some able to read after the writes occurred. One would
+not say that drivers unable to detect all cases are necessarily flawed,
+as long as programming is concerned.
+
+The @value{op-verify} option will not work in conjunction with the
+@value{op-multi-volume} option or the @value{op-append},
+@value{op-update} and @value{op-delete} operations. @xref{Operations},
+for more information on these operations.
+
+Also, since @command{tar} normally strips leading @samp{/} from file
+names (@pxref{absolute}), a command like @samp{tar --verify -cf
+/tmp/foo.tar /etc} will work as desired only if the working directory is
+@file{/}, as @command{tar} uses the archive's relative member names
+(e.g., @file{etc/motd}) when verifying the archive.
+
+@node Write Protection
+@section Write Protection
+
+Almost all tapes and diskettes, and in a few rare cases, even disks can
+be @dfn{write protected}, to protect data on them from being changed.
+Once an archive is written, you should write protect the media to prevent
+the archive from being accidentally overwritten or deleted. (This will
+protect the archive from being changed with a tape or floppy drive---it
+will not protect it from magnet fields or other physical hazards).
+
+The write protection device itself is usually an integral part of the
+physical media, and can be a two position (write enabled/write
+disabled) switch, a notch which can be popped out or covered, a ring
+which can be removed from the center of a tape reel, or some other
+changeable feature.
+
+@node Free Software Needs Free Documentation
+@appendix Free Software Needs Free Documentation
+@include freemanuals.texi
+
+@node Copying This Manual
+@appendix Copying This Manual
+
+@menu
+* GNU Free Documentation License:: License for copying this manual
+@end menu
+
+@include fdl.texi
+
+@node Index
+@appendix Index
+
+@printindex cp
+
+@summarycontents
+@contents
+@bye
+
+@c Local variables:
+@c texinfo-column-for-description: 32
+@c End:
diff --git a/contrib/tar/doc/version.texi b/contrib/tar/doc/version.texi
new file mode 100644
index 0000000..c203ac3
--- /dev/null
+++ b/contrib/tar/doc/version.texi
@@ -0,0 +1,4 @@
+@set UPDATED 26 September 2001
+@set UPDATED-MONTH September 2001
+@set EDITION 1.13.24
+@set VERSION 1.13.24
diff --git a/contrib/tar/lib/addext.c b/contrib/tar/lib/addext.c
new file mode 100644
index 0000000..571e3c2
--- /dev/null
+++ b/contrib/tar/lib/addext.c
@@ -0,0 +1,114 @@
+/* addext.c -- add an extension to a file name
+ Copyright 1990, 1997, 1998, 1999, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu> and Paul Eggert */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef HAVE_DOS_FILE_NAMES
+# define HAVE_DOS_FILE_NAMES 0
+#endif
+#ifndef HAVE_LONG_FILE_NAMES
+# define HAVE_LONG_FILE_NAMES 0
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#ifndef _POSIX_NAME_MAX
+# define _POSIX_NAME_MAX 14
+#endif
+
+#include <sys/types.h>
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#include "backupfile.h"
+#include "dirname.h"
+
+/* Append to FILENAME the extension EXT, unless the result would be too long,
+ in which case just append the character E. */
+
+void
+addext (char *filename, char const *ext, int e)
+{
+ char *s = base_name (filename);
+ size_t slen = base_len (s);
+ size_t extlen = strlen (ext);
+ size_t slen_max = HAVE_LONG_FILE_NAMES ? 255 : _POSIX_NAME_MAX;
+
+#if HAVE_PATHCONF && defined _PC_NAME_MAX
+ if (_POSIX_NAME_MAX < slen + extlen || HAVE_DOS_FILE_NAMES)
+ {
+ /* The new base name is long enough to require a pathconf check. */
+ long name_max;
+ errno = 0;
+ if (s == filename)
+ name_max = pathconf (".", _PC_NAME_MAX);
+ else
+ {
+ char c = *s;
+ if (! ISSLASH (c))
+ *s = 0;
+ name_max = pathconf (filename, _PC_NAME_MAX);
+ *s = c;
+ }
+ if (0 <= name_max || errno == 0)
+ slen_max = name_max == (size_t) name_max ? name_max : -1;
+ }
+#endif
+
+ if (HAVE_DOS_FILE_NAMES && slen_max <= 12)
+ {
+ /* Live within DOS's 8.3 limit. */
+ char *dot = strchr (s, '.');
+ if (dot)
+ {
+ slen -= dot + 1 - s;
+ s = dot + 1;
+ slen_max = 3;
+ }
+ else
+ slen_max = 8;
+ extlen = 9; /* Don't use EXT. */
+ }
+
+ if (slen + extlen <= slen_max)
+ strcpy (s + slen, ext);
+ else
+ {
+ if (slen_max <= slen)
+ slen = slen_max - 1;
+ s[slen] = e;
+ s[slen + 1] = 0;
+ }
+}
diff --git a/contrib/tar/lib/alloca.c b/contrib/tar/lib/alloca.c
new file mode 100644
index 0000000..6ad425a
--- /dev/null
+++ b/contrib/tar/lib/alloca.c
@@ -0,0 +1,504 @@
+/* alloca.c -- allocate automatically reclaimed memory
+ (Mostly) portable public-domain implementation -- D A Gwyn
+
+ This implementation of the PWB library alloca function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+ J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+ There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if HAVE_STRING_H
+# include <string.h>
+#endif
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef emacs
+# include "blockinput.h"
+#endif
+
+/* If compiling with GCC 2, this file's not needed. */
+#if !defined (__GNUC__) || __GNUC__ < 2
+
+/* If someone has defined alloca as a macro,
+ there must be some other way alloca is supposed to work. */
+# ifndef alloca
+
+# ifdef emacs
+# ifdef static
+/* actually, only want this if static is defined as ""
+ -- this is for usg, in which emacs must undefine static
+ in order to make unexec workable
+ */
+# ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+# endif /* STACK_DIRECTION undefined */
+# endif /* static */
+# endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+ provide an "address metric" ADDRESS_FUNCTION macro. */
+
+# if defined (CRAY) && defined (CRAY_STACKSEG_END)
+long i00afunc ();
+# define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+# else
+# define ADDRESS_FUNCTION(arg) &(arg)
+# endif
+
+# if __STDC__
+typedef void *pointer;
+# else
+typedef char *pointer;
+# endif
+
+# ifndef NULL
+# define NULL 0
+# endif
+
+/* Different portions of Emacs need to call different versions of
+ malloc. The Emacs executable needs alloca to call xmalloc, because
+ ordinary malloc isn't protected from input signals. On the other
+ hand, the utilities in lib-src need alloca to call malloc; some of
+ them are very simple, and don't have an xmalloc routine.
+
+ Non-Emacs programs expect this to call xmalloc.
+
+ Callers below should use malloc. */
+
+# ifndef emacs
+# undef malloc
+# define malloc xmalloc
+# endif
+extern pointer malloc ();
+
+/* Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+
+# ifndef STACK_DIRECTION
+# define STACK_DIRECTION 0 /* Direction unknown. */
+# endif
+
+# if STACK_DIRECTION != 0
+
+# define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
+
+# else /* STACK_DIRECTION == 0; need run-time code. */
+
+static int stack_dir; /* 1 or -1 once known. */
+# define STACK_DIR stack_dir
+
+static void
+find_stack_direction ()
+{
+ static char *addr = NULL; /* Address of first `dummy', once known. */
+ auto char dummy; /* To get stack address. */
+
+ if (addr == NULL)
+ { /* Initial entry. */
+ addr = ADDRESS_FUNCTION (dummy);
+
+ find_stack_direction (); /* Recurse once. */
+ }
+ else
+ {
+ /* Second entry. */
+ if (ADDRESS_FUNCTION (dummy) > addr)
+ stack_dir = 1; /* Stack grew upward. */
+ else
+ stack_dir = -1; /* Stack grew downward. */
+ }
+}
+
+# endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+ (a) chain together all alloca'ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc
+ alignment chunk size. The following default should work okay. */
+
+# ifndef ALIGN_SIZE
+# define ALIGN_SIZE sizeof(double)
+# endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* To force sizeof(header). */
+ struct
+ {
+ union hdr *next; /* For chaining headers. */
+ char *deep; /* For stack depth measure. */
+ } h;
+} header;
+
+static header *last_alloca_header = NULL; /* -> last alloca header. */
+
+/* Return a pointer to at least SIZE bytes of storage,
+ which will be automatically reclaimed upon exit from
+ the procedure that called alloca. Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32. */
+
+pointer
+alloca (size_t size)
+{
+ auto char probe; /* Probes stack depth: */
+ register char *depth = ADDRESS_FUNCTION (probe);
+
+# if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* Unknown growth direction. */
+ find_stack_direction ();
+# endif
+
+ /* Reclaim garbage, defined as all alloca'd storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ register header *hp; /* Traverses linked list. */
+
+# ifdef emacs
+ BLOCK_INPUT;
+# endif
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if ((STACK_DIR > 0 && hp->h.deep > depth)
+ || (STACK_DIR < 0 && hp->h.deep < depth))
+ {
+ register header *np = hp->h.next;
+
+ free ((pointer) hp); /* Collect garbage. */
+
+ hp = np; /* -> next header. */
+ }
+ else
+ break; /* Rest are not deeper. */
+
+ last_alloca_header = hp; /* -> last valid storage. */
+
+# ifdef emacs
+ UNBLOCK_INPUT;
+# endif
+ }
+
+ if (size == 0)
+ return NULL; /* No allocation required. */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ register pointer new = malloc (sizeof (header) + size);
+ /* Address of header. */
+
+ if (new == 0)
+ abort();
+
+ ((header *) new)->h.next = last_alloca_header;
+ ((header *) new)->h.deep = depth;
+
+ last_alloca_header = (header *) new;
+
+ /* User storage begins just after header. */
+
+ return (pointer) ((char *) new + sizeof (header));
+ }
+}
+
+# if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+# ifdef DEBUG_I00AFUNC
+# include <stdio.h>
+# endif
+
+# ifndef CRAY_STACK
+# define CRAY_STACK
+# ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+ {
+ long shgrow:32; /* Number of times stack has grown. */
+ long shaseg:32; /* Size of increments to stack. */
+ long shhwm:32; /* High water mark of stack. */
+ long shsize:32; /* Current size of stack (all segments). */
+ };
+
+/* The stack segment linkage control information occurs at
+ the high-address end of a stack segment. (The stack
+ grows from low addresses to high addresses.) The initial
+ part of the stack segment linkage control information is
+ 0200 (octal) words. This provides for register storage
+ for the routine which overflows the stack. */
+
+struct stack_segment_linkage
+ {
+ long ss[0200]; /* 0200 overflow words. */
+ long sssize:32; /* Number of words in this segment. */
+ long ssbase:32; /* Offset to stack base. */
+ long:32;
+ long sspseg:32; /* Offset to linkage control of previous
+ segment of stack. */
+ long:32;
+ long sstcpt:32; /* Pointer to task common address block. */
+ long sscsnm; /* Private control structure number for
+ microtasking. */
+ long ssusr1; /* Reserved for user. */
+ long ssusr2; /* Reserved for user. */
+ long sstpid; /* Process ID for pid based multi-tasking. */
+ long ssgvup; /* Pointer to multitasking thread giveup. */
+ long sscray[7]; /* Reserved for Cray Research. */
+ long ssa0;
+ long ssa1;
+ long ssa2;
+ long ssa3;
+ long ssa4;
+ long ssa5;
+ long ssa6;
+ long ssa7;
+ long sss0;
+ long sss1;
+ long sss2;
+ long sss3;
+ long sss4;
+ long sss5;
+ long sss6;
+ long sss7;
+ };
+
+# else /* CRAY2 */
+/* The following structure defines the vector of words
+ returned by the STKSTAT library routine. */
+struct stk_stat
+ {
+ long now; /* Current total stack size. */
+ long maxc; /* Amount of contiguous space which would
+ be required to satisfy the maximum
+ stack demand to date. */
+ long high_water; /* Stack high-water mark. */
+ long overflows; /* Number of stack overflow ($STKOFEN) calls. */
+ long hits; /* Number of internal buffer hits. */
+ long extends; /* Number of block extensions. */
+ long stko_mallocs; /* Block allocations by $STKOFEN. */
+ long underflows; /* Number of stack underflow calls ($STKRETN). */
+ long stko_free; /* Number of deallocations by $STKRETN. */
+ long stkm_free; /* Number of deallocations by $STKMRET. */
+ long segments; /* Current number of stack segments. */
+ long maxs; /* Maximum number of stack segments so far. */
+ long pad_size; /* Stack pad size. */
+ long current_address; /* Current stack segment address. */
+ long current_size; /* Current stack segment size. This
+ number is actually corrupted by STKSTAT to
+ include the fifteen word trailer area. */
+ long initial_address; /* Address of initial segment. */
+ long initial_size; /* Size of initial segment. */
+ };
+
+/* The following structure describes the data structure which trails
+ any stack segment. I think that the description in 'asdef' is
+ out of date. I only describe the parts that I am sure about. */
+
+struct stk_trailer
+ {
+ long this_address; /* Address of this block. */
+ long this_size; /* Size of this block (does not include
+ this trailer). */
+ long unknown2;
+ long unknown3;
+ long link; /* Address of trailer block of previous
+ segment. */
+ long unknown5;
+ long unknown6;
+ long unknown7;
+ long unknown8;
+ long unknown9;
+ long unknown10;
+ long unknown11;
+ long unknown12;
+ long unknown13;
+ long unknown14;
+ };
+
+# endif /* CRAY2 */
+# endif /* not CRAY_STACK */
+
+# ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+ I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+ struct stk_stat status;
+ struct stk_trailer *trailer;
+ long *block, size;
+ long result = 0;
+
+ /* We want to iterate through all of the segments. The first
+ step is to get the stack status structure. We could do this
+ more quickly and more directly, perhaps, by referencing the
+ $LM00 common block, but I know that this works. */
+
+ STKSTAT (&status);
+
+ /* Set up the iteration. */
+
+ trailer = (struct stk_trailer *) (status.current_address
+ + status.current_size
+ - 15);
+
+ /* There must be at least one stack segment. Therefore it is
+ a fatal error if "trailer" is null. */
+
+ if (trailer == 0)
+ abort ();
+
+ /* Discard segments that do not contain our argument address. */
+
+ while (trailer != 0)
+ {
+ block = (long *) trailer->this_address;
+ size = trailer->this_size;
+ if (block == 0 || size == 0)
+ abort ();
+ trailer = (struct stk_trailer *) trailer->link;
+ if ((block <= address) && (address < (block + size)))
+ break;
+ }
+
+ /* Set the result to the offset in this segment and add the sizes
+ of all predecessor segments. */
+
+ result = address - block;
+
+ if (trailer == 0)
+ {
+ return result;
+ }
+
+ do
+ {
+ if (trailer->this_size <= 0)
+ abort ();
+ result += trailer->this_size;
+ trailer = (struct stk_trailer *) trailer->link;
+ }
+ while (trailer != 0);
+
+ /* We are done. Note that if you present a bogus address (one
+ not in any segment), you will get a different number back, formed
+ from subtracting the address of the first block. This is probably
+ not what you want. */
+
+ return (result);
+}
+
+# else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+ Determine the number of the cell within the stack,
+ given the address of the cell. The purpose of this
+ routine is to linearize, in some sense, stack addresses
+ for alloca. */
+
+static long
+i00afunc (long address)
+{
+ long stkl = 0;
+
+ long size, pseg, this_segment, stack;
+ long result = 0;
+
+ struct stack_segment_linkage *ssptr;
+
+ /* Register B67 contains the address of the end of the
+ current stack segment. If you (as a subprogram) store
+ your registers on the stack and find that you are past
+ the contents of B67, you have overflowed the segment.
+
+ B67 also points to the stack segment linkage control
+ area, which is what we are really interested in. */
+
+ stkl = CRAY_STACKSEG_END ();
+ ssptr = (struct stack_segment_linkage *) stkl;
+
+ /* If one subtracts 'size' from the end of the segment,
+ one has the address of the first word of the segment.
+
+ If this is not the first segment, 'pseg' will be
+ nonzero. */
+
+ pseg = ssptr->sspseg;
+ size = ssptr->sssize;
+
+ this_segment = stkl - size;
+
+ /* It is possible that calling this routine itself caused
+ a stack overflow. Discard stack segments which do not
+ contain the target address. */
+
+ while (!(this_segment <= address && address <= stkl))
+ {
+# ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+# endif
+ if (pseg == 0)
+ break;
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ this_segment = stkl - size;
+ }
+
+ result = address - this_segment;
+
+ /* If you subtract pseg from the current end of the stack,
+ you get the address of the previous stack segment's end.
+ This seems a little convoluted to me, but I'll bet you save
+ a cycle somewhere. */
+
+ while (pseg != 0)
+ {
+# ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o\n", pseg, size);
+# endif
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ result += size;
+ }
+ return (result);
+}
+
+# endif /* not CRAY2 */
+# endif /* CRAY */
+
+# endif /* no alloca */
+#endif /* not GCC version 2 */
diff --git a/contrib/tar/lib/argmatch.c b/contrib/tar/lib/argmatch.c
new file mode 100644
index 0000000..af96c8c
--- /dev/null
+++ b/contrib/tar/lib/argmatch.c
@@ -0,0 +1,308 @@
+/* argmatch.c -- find a match for a string in an array
+ Copyright (C) 1990, 1998, 1999, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by David MacKenzie <djm@ai.mit.edu>
+ Modified by Akim Demaille <demaille@inf.enst.fr> */
+
+#include "argmatch.h"
+
+#include <stdio.h>
+#ifdef STDC_HEADERS
+# include <string.h>
+#endif
+
+#if HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# define _(Text) Text
+#endif
+
+#include "error.h"
+#include "quotearg.h"
+#include "quote.h"
+
+/* When reporting an invalid argument, show nonprinting characters
+ by using the quoting style ARGMATCH_QUOTING_STYLE. Do not use
+ literal_quoting_style. */
+#ifndef ARGMATCH_QUOTING_STYLE
+# define ARGMATCH_QUOTING_STYLE locale_quoting_style
+#endif
+
+/* The following test is to work around the gross typo in
+ systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE
+ is defined to 0, not 1. */
+#if !EXIT_FAILURE
+# undef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+/* Non failing version of argmatch call this function after failing. */
+#ifndef ARGMATCH_DIE
+# define ARGMATCH_DIE exit (EXIT_FAILURE)
+#endif
+
+#ifdef ARGMATCH_DIE_DECL
+ARGMATCH_DIE_DECL;
+#endif
+
+static void
+__argmatch_die (void)
+{
+ ARGMATCH_DIE;
+}
+
+/* Used by XARGMATCH and XARGCASEMATCH. See description in argmatch.h.
+ Default to __argmatch_die, but allow caller to change this at run-time. */
+argmatch_exit_fn argmatch_die = __argmatch_die;
+
+
+/* If ARG is an unambiguous match for an element of the
+ null-terminated array ARGLIST, return the index in ARGLIST
+ of the matched element, else -1 if it does not match any element
+ or -2 if it is ambiguous (is a prefix of more than one element).
+ If SENSITIVE, comparison is case sensitive.
+
+ If VALLIST is none null, use it to resolve ambiguities limited to
+ synonyms, i.e., for
+ "yes", "yop" -> 0
+ "no", "nope" -> 1
+ "y" is a valid argument, for `0', and "n" for `1'. */
+
+static int
+__argmatch_internal (const char *arg, const char *const *arglist,
+ const char *vallist, size_t valsize,
+ int case_sensitive)
+{
+ int i; /* Temporary index in ARGLIST. */
+ size_t arglen; /* Length of ARG. */
+ int matchind = -1; /* Index of first nonexact match. */
+ int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
+
+ arglen = strlen (arg);
+
+ /* Test all elements for either exact match or abbreviated matches. */
+ for (i = 0; arglist[i]; i++)
+ {
+ if (case_sensitive
+ ? !strncmp (arglist[i], arg, arglen)
+ : !strncasecmp (arglist[i], arg, arglen))
+ {
+ if (strlen (arglist[i]) == arglen)
+ /* Exact match found. */
+ return i;
+ else if (matchind == -1)
+ /* First nonexact match found. */
+ matchind = i;
+ else
+ {
+ /* Second nonexact match found. */
+ if (vallist == NULL
+ || memcmp (vallist + valsize * matchind,
+ vallist + valsize * i, valsize))
+ {
+ /* There is a real ambiguity, or we could not
+ disambiguate. */
+ ambiguous = 1;
+ }
+ }
+ }
+ }
+ if (ambiguous)
+ return -2;
+ else
+ return matchind;
+}
+
+/* argmatch - case sensitive version */
+int
+argmatch (const char *arg, const char *const *arglist,
+ const char *vallist, size_t valsize)
+{
+ return __argmatch_internal (arg, arglist, vallist, valsize, 1);
+}
+
+/* argcasematch - case insensitive version */
+int
+argcasematch (const char *arg, const char *const *arglist,
+ const char *vallist, size_t valsize)
+{
+ return __argmatch_internal (arg, arglist, vallist, valsize, 0);
+}
+
+/* Error reporting for argmatch.
+ CONTEXT is a description of the type of entity that was being matched.
+ VALUE is the invalid value that was given.
+ PROBLEM is the return value from argmatch. */
+
+void
+argmatch_invalid (const char *context, const char *value, int problem)
+{
+ char const *format = (problem == -1
+ ? _("invalid argument %s for %s")
+ : _("ambiguous argument %s for %s"));
+
+ error (0, 0, format, quotearg_style (ARGMATCH_QUOTING_STYLE, value),
+ quote (context));
+}
+
+/* List the valid arguments for argmatch.
+ ARGLIST is the same as in argmatch.
+ VALLIST is a pointer to an array of values.
+ VALSIZE is the size of the elements of VALLIST */
+void
+argmatch_valid (const char *const *arglist,
+ const char *vallist, size_t valsize)
+{
+ int i;
+ const char *last_val = NULL;
+
+ /* We try to put synonyms on the same line. The assumption is that
+ synonyms follow each other */
+ fprintf (stderr, _("Valid arguments are:"));
+ for (i = 0; arglist[i]; i++)
+ if ((i == 0)
+ || memcmp (last_val, vallist + valsize * i, valsize))
+ {
+ fprintf (stderr, "\n - `%s'", arglist[i]);
+ last_val = vallist + valsize * i;
+ }
+ else
+ {
+ fprintf (stderr, ", `%s'", arglist[i]);
+ }
+ putc ('\n', stderr);
+}
+
+/* Never failing versions of the previous functions.
+
+ CONTEXT is the context for which argmatch is called (e.g.,
+ "--version-control", or "$VERSION_CONTROL" etc.). Upon failure,
+ calls the (supposed never to return) function EXIT_FN. */
+
+int
+__xargmatch_internal (const char *context,
+ const char *arg, const char *const *arglist,
+ const char *vallist, size_t valsize,
+ int case_sensitive,
+ argmatch_exit_fn exit_fn)
+{
+ int res = __argmatch_internal (arg, arglist,
+ vallist, valsize,
+ case_sensitive);
+ if (res >= 0)
+ /* Success. */
+ return res;
+
+ /* We failed. Explain why. */
+ argmatch_invalid (context, arg, res);
+ argmatch_valid (arglist, vallist, valsize);
+ (*exit_fn) ();
+
+ return -1; /* To please the compilers. */
+}
+
+/* Look for VALUE in VALLIST, an array of objects of size VALSIZE and
+ return the first corresponding argument in ARGLIST */
+const char *
+argmatch_to_argument (const char *value,
+ const char *const *arglist,
+ const char *vallist, size_t valsize)
+{
+ int i;
+
+ for (i = 0; arglist[i]; i++)
+ if (!memcmp (value, vallist + valsize * i, valsize))
+ return arglist[i];
+ return NULL;
+}
+
+#ifdef TEST
+/*
+ * Based on "getversion.c" by David MacKenzie <djm@gnu.ai.mit.edu>
+ */
+char *program_name;
+extern const char *getenv ();
+
+/* When to make backup files. */
+enum backup_type
+{
+ /* Never make backups. */
+ none,
+
+ /* Make simple backups of every file. */
+ simple,
+
+ /* Make numbered backups of files that already have numbered backups,
+ and simple backups of the others. */
+ numbered_existing,
+
+ /* Make numbered backups of every file. */
+ numbered
+};
+
+/* Two tables describing arguments (keys) and their corresponding
+ values */
+static const char *const backup_args[] =
+{
+ "no", "none", "off",
+ "simple", "never",
+ "existing", "nil",
+ "numbered", "t",
+ 0
+};
+
+static const enum backup_type backup_vals[] =
+{
+ none, none, none,
+ simple, simple,
+ numbered_existing, numbered_existing,
+ numbered, numbered
+};
+
+int
+main (int argc, const char *const *argv)
+{
+ const char *cp;
+ enum backup_type backup_type = none;
+
+ program_name = (char *) argv[0];
+
+ if (argc > 2)
+ {
+ fprintf (stderr, "Usage: %s [VERSION_CONTROL]\n", program_name);
+ exit (1);
+ }
+
+ if ((cp = getenv ("VERSION_CONTROL")))
+ backup_type = XARGCASEMATCH ("$VERSION_CONTROL", cp,
+ backup_args, backup_vals);
+
+ if (argc == 2)
+ backup_type = XARGCASEMATCH (program_name, argv[1],
+ backup_args, backup_vals);
+
+ printf ("The version control is `%s'\n",
+ ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
+
+ return 0;
+}
+#endif
diff --git a/contrib/tar/lib/argmatch.h b/contrib/tar/lib/argmatch.h
new file mode 100644
index 0000000..d3f25cc
--- /dev/null
+++ b/contrib/tar/lib/argmatch.h
@@ -0,0 +1,129 @@
+/* argmatch.h -- definitions and prototypes for argmatch.c
+ Copyright (C) 1990, 1998, 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by David MacKenzie <djm@ai.mit.edu>
+ Modified by Akim Demaille <demaille@inf.enst.fr> */
+
+#ifndef ARGMATCH_H_
+# define ARGMATCH_H_ 1
+
+# if HAVE_CONFIG_H
+# include <config.h>
+# endif
+
+# include <sys/types.h>
+
+# ifndef PARAMS
+# if PROTOTYPES || (defined (__STDC__) && __STDC__)
+# define PARAMS(args) args
+# else
+# define PARAMS(args) ()
+# endif /* GCC. */
+# endif /* Not PARAMS. */
+
+/* Assert there are as many real arguments as there are values
+ (argument list ends with a NULL guard). There is no execution
+ cost, since it will be statically evalauted to `assert (0)' or
+ `assert (1)'. Unfortunately there is no -Wassert-0. */
+
+# undef ARRAY_CARDINALITY
+# define ARRAY_CARDINALITY(Array) (sizeof ((Array)) / sizeof (*(Array)))
+
+# define ARGMATCH_ASSERT(Arglist, Vallist) \
+ assert (ARRAY_CARDINALITY ((Arglist)) == ARRAY_CARDINALITY ((Vallist)) + 1)
+
+/* Return the index of the element of ARGLIST (NULL terminated) that
+ matches with ARG. If VALLIST is not NULL, then use it to resolve
+ false ambiguities (i.e., different matches of ARG but corresponding
+ to the same values in VALLIST). */
+
+int argmatch
+ PARAMS ((const char *arg, const char *const *arglist,
+ const char *vallist, size_t valsize));
+int argcasematch
+ PARAMS ((const char *arg, const char *const *arglist,
+ const char *vallist, size_t valsize));
+
+# define ARGMATCH(Arg, Arglist, Vallist) \
+ argmatch ((Arg), (Arglist), (const char *) (Vallist), sizeof (*(Vallist)))
+
+# define ARGCASEMATCH(Arg, Arglist, Vallist) \
+ argcasematch ((Arg), (Arglist), (const char *) (Vallist), sizeof (*(Vallist)))
+
+/* xargmatch calls this function when it fails. This function should not
+ return. By default, this is a function that calls ARGMATCH_DIE which
+ in turn defaults to `exit (EXIT_FAILURE)'. */
+typedef void (*argmatch_exit_fn) PARAMS ((void));
+extern argmatch_exit_fn argmatch_die;
+
+/* Report on stderr why argmatch failed. Report correct values. */
+
+void argmatch_invalid
+ PARAMS ((const char *context, const char *value, int problem));
+
+/* Left for compatibility with the old name invalid_arg */
+
+# define invalid_arg(Context, Value, Problem) \
+ argmatch_invalid ((Context), (Value), (Problem))
+
+
+
+/* Report on stderr the list of possible arguments. */
+
+void argmatch_valid
+ PARAMS ((const char *const *arglist,
+ const char *vallist, size_t valsize));
+
+# define ARGMATCH_VALID(Arglist, Vallist) \
+ argmatch_valid (Arglist, (const char *) Vallist, sizeof (*(Vallist)))
+
+
+
+/* Same as argmatch, but upon failure, reports a explanation on the
+ failure, and exits using the function EXIT_FN. */
+
+int __xargmatch_internal
+ PARAMS ((const char *context,
+ const char *arg, const char *const *arglist,
+ const char *vallist, size_t valsize,
+ int case_sensitive, argmatch_exit_fn exit_fn));
+
+/* Programmer friendly interface to __xargmatch_internal. */
+
+# define XARGMATCH(Context, Arg, Arglist, Vallist) \
+ (Vallist [__xargmatch_internal ((Context), (Arg), (Arglist), \
+ (const char *) (Vallist), \
+ sizeof (*(Vallist)), \
+ 1, argmatch_die)])
+
+# define XARGCASEMATCH(Context, Arg, Arglist, Vallist) \
+ (Vallist [__xargmatch_internal ((Context), (Arg), (Arglist), \
+ (const char *) (Vallist), \
+ sizeof (*(Vallist)), \
+ 0, argmatch_die)])
+
+/* Convert a value into a corresponding argument. */
+
+const char *argmatch_to_argument
+ PARAMS ((char const *value, const char *const *arglist,
+ const char *vallist, size_t valsize));
+
+# define ARGMATCH_TO_ARGUMENT(Value, Arglist, Vallist) \
+ argmatch_to_argument ((char const *) &(Value), (Arglist), \
+ (const char *) (Vallist), sizeof (*(Vallist)))
+
+#endif /* ARGMATCH_H_ */
diff --git a/contrib/tar/lib/backupfile.c b/contrib/tar/lib/backupfile.c
new file mode 100644
index 0000000..fa5ece1
--- /dev/null
+++ b/contrib/tar/lib/backupfile.c
@@ -0,0 +1,278 @@
+/* backupfile.c -- make Emacs style backup file names
+ Copyright 1990,91,92,93,94,95,96,97,98,99,2000, 2001 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
+ Some algorithms adapted from GNU Emacs. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NLENGTH(direct) strlen ((direct)->d_name)
+#else
+# define dirent direct
+# define NLENGTH(direct) ((size_t) (direct)->d_namlen)
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#if CLOSEDIR_VOID
+/* Fake a return value. */
+# define CLOSEDIR(d) (closedir (d), 0)
+#else
+# define CLOSEDIR(d) closedir (d)
+#endif
+
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifndef HAVE_DECL_GETENV
+"this configure-time declaration test was not run"
+#endif
+#if !HAVE_DECL_GETENV
+char *getenv ();
+#endif
+
+#ifndef HAVE_DECL_MALLOC
+"this configure-time declaration test was not run"
+#endif
+#if !HAVE_DECL_MALLOC
+char *malloc ();
+#endif
+
+#if HAVE_DIRENT_H || HAVE_NDIR_H || HAVE_SYS_DIR_H || HAVE_SYS_NDIR_H
+# define HAVE_DIR 1
+#else
+# define HAVE_DIR 0
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#ifndef CHAR_BIT
+# define CHAR_BIT 8
+#endif
+/* Upper bound on the string length of an integer converted to string.
+ 302 / 1000 is ceil (log10 (2.0)). Subtract 1 for the sign bit;
+ add 1 for integer division truncation; add 1 more for a minus sign. */
+#define INT_STRLEN_BOUND(t) ((sizeof (t) * CHAR_BIT - 1) * 302 / 1000 + 2)
+
+/* ISDIGIT differs from isdigit, as follows:
+ - Its arg may be any int or unsigned int; it need not be an unsigned char.
+ - It's guaranteed to evaluate its argument exactly once.
+ - It's typically faster.
+ Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+ only '0' through '9' are digits. Prefer ISDIGIT to isdigit unless
+ it's important to use the locale's definition of `digit' even when the
+ host does not conform to Posix. */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#if D_INO_IN_DIRENT
+# define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
+#else
+# define REAL_DIR_ENTRY(dp) 1
+#endif
+
+#include "argmatch.h"
+#include "backupfile.h"
+#include "dirname.h"
+
+/* The extension added to file names to produce a simple (as opposed
+ to numbered) backup file name. */
+const char *simple_backup_suffix = "~";
+
+static int max_backup_version PARAMS ((const char *, const char *));
+static int version_number PARAMS ((const char *, const char *, size_t));
+
+/* Return the name of the new backup file for file FILE,
+ allocated with malloc. Return 0 if out of memory.
+ FILE must not end with a '/' unless it is the root directory.
+ Do not call this function if backup_type == none. */
+
+char *
+find_backup_file_name (const char *file, enum backup_type backup_type)
+{
+ size_t backup_suffix_size_max;
+ size_t file_len = strlen (file);
+ size_t numbered_suffix_size_max = INT_STRLEN_BOUND (int) + 4;
+ char *s;
+ const char *suffix = simple_backup_suffix;
+
+ /* Allow room for simple or `.~N~' backups. */
+ backup_suffix_size_max = strlen (simple_backup_suffix) + 1;
+ if (HAVE_DIR && backup_suffix_size_max < numbered_suffix_size_max)
+ backup_suffix_size_max = numbered_suffix_size_max;
+
+ s = malloc (file_len + 1
+ + backup_suffix_size_max + numbered_suffix_size_max);
+ if (s)
+ {
+#if HAVE_DIR
+ if (backup_type != simple)
+ {
+ int highest_backup;
+ size_t dirlen = dir_len (file);
+
+ memcpy (s, file, dirlen);
+ if (dirlen == FILESYSTEM_PREFIX_LEN (file))
+ s[dirlen++] = '.';
+ s[dirlen] = '\0';
+ highest_backup = max_backup_version (base_name (file), s);
+ if (! (backup_type == numbered_existing && highest_backup == 0))
+ {
+ char *numbered_suffix = s + (file_len + backup_suffix_size_max);
+ sprintf (numbered_suffix, ".~%d~", highest_backup + 1);
+ suffix = numbered_suffix;
+ }
+ }
+#endif /* HAVE_DIR */
+
+ strcpy (s, file);
+ addext (s, suffix, '~');
+ }
+ return s;
+}
+
+#if HAVE_DIR
+
+/* Return the number of the highest-numbered backup file for file
+ FILE in directory DIR. If there are no numbered backups
+ of FILE in DIR, or an error occurs reading DIR, return 0.
+ */
+
+static int
+max_backup_version (const char *file, const char *dir)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ int highest_version;
+ int this_version;
+ size_t file_name_length;
+
+ dirp = opendir (dir);
+ if (!dirp)
+ return 0;
+
+ highest_version = 0;
+ file_name_length = base_len (file);
+
+ while ((dp = readdir (dirp)) != 0)
+ {
+ if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) < file_name_length + 4)
+ continue;
+
+ this_version = version_number (file, dp->d_name, file_name_length);
+ if (this_version > highest_version)
+ highest_version = this_version;
+ }
+ if (CLOSEDIR (dirp))
+ return 0;
+ return highest_version;
+}
+
+/* If BACKUP is a numbered backup of BASE, return its version number;
+ otherwise return 0. BASE_LENGTH is the length of BASE.
+ */
+
+static int
+version_number (const char *base, const char *backup, size_t base_length)
+{
+ int version;
+ const char *p;
+
+ version = 0;
+ if (strncmp (base, backup, base_length) == 0
+ && backup[base_length] == '.'
+ && backup[base_length + 1] == '~')
+ {
+ for (p = &backup[base_length + 2]; ISDIGIT (*p); ++p)
+ version = version * 10 + *p - '0';
+ if (p[0] != '~' || p[1])
+ version = 0;
+ }
+ return version;
+}
+#endif /* HAVE_DIR */
+
+static const char * const backup_args[] =
+{
+ /* In a series of synonyms, present the most meaning full first, so
+ that argmatch_valid be more readable. */
+ "none", "off",
+ "simple", "never",
+ "existing", "nil",
+ "numbered", "t",
+ 0
+};
+
+static const enum backup_type backup_types[] =
+{
+ none, none,
+ simple, simple,
+ numbered_existing, numbered_existing,
+ numbered, numbered
+};
+
+/* Return the type of backup specified by VERSION.
+ If VERSION is NULL or the empty string, return numbered_existing.
+ If VERSION is invalid or ambiguous, fail with a diagnostic appropriate
+ for the specified CONTEXT. Unambiguous abbreviations are accepted. */
+
+enum backup_type
+get_version (const char *context, const char *version)
+{
+ if (version == 0 || *version == 0)
+ return numbered_existing;
+ else
+ return XARGMATCH (context, version, backup_args, backup_types);
+}
+
+
+/* Return the type of backup specified by VERSION.
+ If VERSION is NULL, use the value of the envvar VERSION_CONTROL.
+ If the specified string is invalid or ambiguous, fail with a diagnostic
+ appropriate for the specified CONTEXT.
+ Unambiguous abbreviations are accepted. */
+
+enum backup_type
+xget_version (const char *context, const char *version)
+{
+ if (version && *version)
+ return get_version (context, version);
+ else
+ return get_version ("$VERSION_CONTROL", getenv ("VERSION_CONTROL"));
+}
diff --git a/contrib/tar/lib/backupfile.h b/contrib/tar/lib/backupfile.h
new file mode 100644
index 0000000..b9b973c
--- /dev/null
+++ b/contrib/tar/lib/backupfile.h
@@ -0,0 +1,60 @@
+/* backupfile.h -- declarations for making Emacs style backup file names
+ Copyright (C) 1990-1992, 1997-1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef BACKUPFILE_H_
+# define BACKUPFILE_H_
+
+/* When to make backup files. */
+enum backup_type
+{
+ /* Never make backups. */
+ none,
+
+ /* Make simple backups of every file. */
+ simple,
+
+ /* Make numbered backups of files that already have numbered backups,
+ and simple backups of the others. */
+ numbered_existing,
+
+ /* Make numbered backups of every file. */
+ numbered
+};
+
+# define VALID_BACKUP_TYPE(Type) \
+ ((Type) == none \
+ || (Type) == simple \
+ || (Type) == numbered_existing \
+ || (Type) == numbered)
+
+extern char const *simple_backup_suffix;
+
+# ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+# endif
+
+char *find_backup_file_name PARAMS ((char const *, enum backup_type));
+enum backup_type get_version PARAMS ((char const *context, char const *arg));
+enum backup_type xget_version PARAMS ((char const *context, char const *arg));
+void addext PARAMS ((char *, char const *, int));
+
+#endif /* ! BACKUPFILE_H_ */
diff --git a/contrib/tar/lib/basename.c b/contrib/tar/lib/basename.c
new file mode 100644
index 0000000..54f037e
--- /dev/null
+++ b/contrib/tar/lib/basename.c
@@ -0,0 +1,79 @@
+/* basename.c -- return the last element in a path
+ Copyright (C) 1990, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+#endif
+#include "dirname.h"
+
+/* In general, we can't use the builtin `basename' function if available,
+ since it has different meanings in different environments.
+ In some environments the builtin `basename' modifies its argument.
+
+ Return the address of the last file name component of NAME. If
+ NAME has no file name components because it is all slashes, return
+ NAME if it is empty, the address of its last slash otherwise. */
+
+char *
+base_name (char const *name)
+{
+ char const *base = name + FILESYSTEM_PREFIX_LEN (name);
+ char const *p;
+
+ for (p = base; *p; p++)
+ {
+ if (ISSLASH (*p))
+ {
+ /* Treat multiple adjacent slashes like a single slash. */
+ do p++;
+ while (ISSLASH (*p));
+
+ /* If the file name ends in slash, use the trailing slash as
+ the basename if no non-slashes have been found. */
+ if (! *p)
+ {
+ if (ISSLASH (*base))
+ base = p - 1;
+ break;
+ }
+
+ /* *P is a non-slash preceded by a slash. */
+ base = p;
+ }
+ }
+
+ return (char *) base;
+}
+
+/* Return the length of of the basename NAME. Typically NAME is the
+ value returned by base_name. Act like strlen (NAME), except omit
+ redundant trailing slashes. */
+
+size_t
+base_len (char const *name)
+{
+ size_t len;
+
+ for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--)
+ continue;
+
+ return len;
+}
diff --git a/contrib/tar/lib/dirname.c b/contrib/tar/lib/dirname.c
new file mode 100644
index 0000000..9fb5f09
--- /dev/null
+++ b/contrib/tar/lib/dirname.c
@@ -0,0 +1,105 @@
+/* dirname.c -- return all but the last element in a path
+ Copyright 1990, 1998, 2000, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+#endif
+
+#include "dirname.h"
+#include "xalloc.h"
+
+/* Return the length of `dirname (PATH)', or zero if PATH is
+ in the working directory. Works properly even if
+ there are trailing slashes (by effectively ignoring them). */
+size_t
+dir_len (char const *path)
+{
+ size_t prefix_length = FILESYSTEM_PREFIX_LEN (path);
+ size_t length;
+
+ /* Strip the basename and any redundant slashes before it. */
+ for (length = base_name (path) - path; prefix_length < length; length--)
+ if (! ISSLASH (path[length - 1]))
+ return length;
+
+ /* But don't strip the only slash from "/". */
+ return prefix_length + ISSLASH (path[prefix_length]);
+}
+
+/* Return the leading directories part of PATH,
+ allocated with xmalloc.
+ Works properly even if there are trailing slashes
+ (by effectively ignoring them). */
+
+char *
+dir_name (char const *path)
+{
+ size_t length = dir_len (path);
+ int append_dot = (length == FILESYSTEM_PREFIX_LEN (path));
+ char *newpath = xmalloc (length + append_dot + 1);
+ memcpy (newpath, path, length);
+ if (append_dot)
+ newpath[length++] = '.';
+ newpath[length] = 0;
+ return newpath;
+}
+
+#ifdef TEST_DIRNAME
+/*
+
+Run the test like this (expect no output):
+ gcc -DHAVE_CONFIG_H -DTEST_DIRNAME -I.. -O -Wall \
+ basename.c dirname.c xmalloc.c
+ sed -n '/^BEGIN-DATA$/,/^END-DATA$/p' dirname.c|grep -v DATA|./a.out
+
+BEGIN-DATA
+foo//// .
+bar/foo//// bar
+foo/ .
+/ /
+. .
+a .
+END-DATA
+
+*/
+
+# define MAX_BUFF_LEN 1024
+# include <stdio.h>
+
+int
+main ()
+{
+ char buff[MAX_BUFF_LEN + 1];
+
+ buff[MAX_BUFF_LEN] = 0;
+ while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
+ {
+ char path[MAX_BUFF_LEN];
+ char expected_result[MAX_BUFF_LEN];
+ char const *result;
+ sscanf (buff, "%s %s", path, expected_result);
+ result = dir_name (path);
+ if (strcmp (result, expected_result))
+ printf ("%s: got %s, expected %s\n", path, result, expected_result);
+ }
+ return 0;
+}
+#endif
diff --git a/contrib/tar/lib/dirname.h b/contrib/tar/lib/dirname.h
new file mode 100644
index 0000000..cea14c0
--- /dev/null
+++ b/contrib/tar/lib/dirname.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 1998, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef DIRNAME_H_
+# define DIRNAME_H_ 1
+
+# ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+# endif
+
+# ifndef DIRECTORY_SEPARATOR
+# define DIRECTORY_SEPARATOR '/'
+# endif
+
+# ifndef ISSLASH
+# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
+# endif
+
+# ifndef FILESYSTEM_PREFIX_LEN
+# define FILESYSTEM_PREFIX_LEN(Filename) 0
+# endif
+
+char *base_name PARAMS ((char const *path));
+char *dir_name PARAMS ((char const *path));
+size_t base_len PARAMS ((char const *path));
+size_t dir_len PARAMS ((char const *path));
+
+int strip_trailing_slashes PARAMS ((char *path));
+
+#endif /* not DIRNAME_H_ */
diff --git a/contrib/tar/lib/error.c b/contrib/tar/lib/error.c
new file mode 100644
index 0000000..2153194
--- /dev/null
+++ b/contrib/tar/lib/error.c
@@ -0,0 +1,396 @@
+/* Error handler for noninteractive utilities
+ Copyright (C) 1990-1998, 2000, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library. Its master source is NOT part of
+ the C library, however. The master source lives in /gd/gnu/lib.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#if HAVE_LIBINTL_H
+# include <libintl.h>
+#endif
+#ifdef _LIBC
+# include <wchar.h>
+# define mbsrtowcs __mbsrtowcs
+#endif
+
+#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC
+# if __STDC__
+# include <stdarg.h>
+# define VA_START(args, lastarg) va_start(args, lastarg)
+# else
+# include <varargs.h>
+# define VA_START(args, lastarg) va_start(args)
+# endif
+#else
+# define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif
+
+#if STDC_HEADERS || _LIBC
+# include <stdlib.h>
+# include <string.h>
+#else
+void exit ();
+#endif
+
+#include "error.h"
+
+#ifndef HAVE_DECL_STRERROR_R
+"this configure-time declaration test was not run"
+#endif
+#if !HAVE_DECL_STRERROR_R
+char *strerror_r ();
+#endif
+
+#ifndef _
+# define _(String) String
+#endif
+
+/* If NULL, error will flush stdout, then print on stderr the program
+ name, a colon and a space. Otherwise, error will call this
+ function without parameters instead. */
+void (*error_print_progname) (
+#if __STDC__ - 0
+ void
+#endif
+ );
+
+/* This variable is incremented each time `error' is called. */
+unsigned int error_message_count;
+
+#ifdef _LIBC
+/* In the GNU C library, there is a predefined variable for this. */
+
+# define program_name program_invocation_name
+# include <errno.h>
+
+/* In GNU libc we want do not want to use the common name `error' directly.
+ Instead make it a weak alias. */
+extern void __error (int status, int errnum, const char *message, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+extern void __error_at_line (int status, int errnum, const char *file_name,
+ unsigned int line_number, const char *message,
+ ...)
+ __attribute__ ((__format__ (__printf__, 5, 6)));;
+# define error __error
+# define error_at_line __error_at_line
+
+# ifdef USE_IN_LIBIO
+# include <libio/iolibio.h>
+# define fflush(s) _IO_fflush (s)
+# endif
+
+#else /* not _LIBC */
+
+/* The calling program should define program_name and set it to the
+ name of the executing program. */
+extern char *program_name;
+
+# ifdef HAVE_STRERROR_R
+# define __strerror_r strerror_r
+# else
+# if HAVE_STRERROR
+# ifndef strerror /* On some systems, strerror is a macro */
+char *strerror ();
+# endif
+# else
+static char *
+private_strerror (errnum)
+ int errnum;
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+
+ if (errnum > 0 && errnum <= sys_nerr)
+ return _(sys_errlist[errnum]);
+ return _("Unknown system error");
+}
+# define strerror private_strerror
+# endif /* HAVE_STRERROR */
+# endif /* HAVE_STRERROR_R */
+#endif /* not _LIBC */
+
+
+#ifdef VA_START
+static void
+error_tail (int status, int errnum, const char *message, va_list args)
+{
+# if HAVE_VPRINTF || _LIBC
+# if _LIBC && USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ {
+# define ALLOCA_LIMIT 2000
+ size_t len = strlen (message) + 1;
+ wchar_t *wmessage = NULL;
+ mbstate_t st;
+ size_t res;
+ const char *tmp;
+
+ do
+ {
+ if (len < ALLOCA_LIMIT)
+ wmessage = (wchar_t *) alloca (len * sizeof (wchar_t));
+ else
+ {
+ if (wmessage != NULL && len / 2 < ALLOCA_LIMIT)
+ wmessage = NULL;
+
+ wmessage = (wchar_t *) realloc (wmessage,
+ len * sizeof (wchar_t));
+
+ if (wmessage == NULL)
+ {
+ fputws_unlocked (L"out of memory\n", stderr);
+ return;
+ }
+ }
+
+ memset (&st, '\0', sizeof (st));
+ tmp =message;
+ }
+ while ((res = mbsrtowcs (wmessage, &tmp, len, &st)) == len);
+
+ if (res == (size_t) -1)
+ /* The string cannot be converted. */
+ wmessage = (wchar_t *) L"???";
+
+ __vfwprintf (stderr, wmessage, args);
+ }
+ else
+# endif
+ vfprintf (stderr, message, args);
+# else
+ _doprnt (message, args, stderr);
+# endif
+ va_end (args);
+
+ ++error_message_count;
+ if (errnum)
+ {
+# if defined HAVE_STRERROR_R || _LIBC
+ char errbuf[1024];
+ char *s = __strerror_r (errnum, errbuf, sizeof errbuf);
+# if _LIBC && USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L": %s", s);
+ else
+# endif
+ fprintf (stderr, ": %s", s);
+# else
+ fprintf (stderr, ": %s", strerror (errnum));
+# endif
+ }
+# if _LIBC && USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ putwc (L'\n', stderr);
+ else
+# endif
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+}
+#endif
+
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+ format string with optional args.
+ If ERRNUM is nonzero, print its corresponding system error message.
+ Exit with status STATUS if it is nonzero. */
+/* VARARGS */
+void
+#if defined VA_START && __STDC__
+error (int status, int errnum, const char *message, ...)
+#else
+error (status, errnum, message, va_alist)
+ int status;
+ int errnum;
+ char *message;
+ va_dcl
+#endif
+{
+#ifdef VA_START
+ va_list args;
+#endif
+
+ fflush (stdout);
+#ifdef _LIBC
+# ifdef USE_IN_LIBIO
+ _IO_flockfile (stderr);
+# else
+ __flockfile (stderr);
+# endif
+#endif
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ {
+#if _LIBC && USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s: ", program_name);
+ else
+#endif
+ fprintf (stderr, "%s: ", program_name);
+ }
+
+#ifdef VA_START
+ VA_START (args, message);
+ error_tail (status, errnum, message, args);
+#else
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ ++error_message_count;
+ if (errnum)
+ {
+# if defined HAVE_STRERROR_R || _LIBC
+ char errbuf[1024];
+ /* Don't use __strerror_r's return value because on some systems
+ (at least DEC UNIX 4.0[A-D]) strerror_r returns `int'. */
+ __strerror_r (errnum, errbuf, sizeof errbuf);
+ fprintf (stderr, ": %s", errbuf);
+# else
+ fprintf (stderr, ": %s", strerror (errnum));
+# endif
+ }
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+#endif
+
+#ifdef _LIBC
+# ifdef USE_IN_LIBIO
+ _IO_funlockfile (stderr);
+# else
+ __funlockfile (stderr);
+# endif
+#endif
+}
+
+/* Sometimes we want to have at most one error per line. This
+ variable controls whether this mode is selected or not. */
+int error_one_per_line;
+
+void
+#if defined VA_START && __STDC__
+error_at_line (int status, int errnum, const char *file_name,
+ unsigned int line_number, const char *message, ...)
+#else
+error_at_line (status, errnum, file_name, line_number, message, va_alist)
+ int status;
+ int errnum;
+ const char *file_name;
+ unsigned int line_number;
+ char *message;
+ va_dcl
+#endif
+{
+#ifdef VA_START
+ va_list args;
+#endif
+
+ if (error_one_per_line)
+ {
+ static const char *old_file_name;
+ static unsigned int old_line_number;
+
+ if (old_line_number == line_number
+ && (file_name == old_file_name
+ || strcmp (old_file_name, file_name) == 0))
+ /* Simply return and print nothing. */
+ return;
+
+ old_file_name = file_name;
+ old_line_number = line_number;
+ }
+
+ fflush (stdout);
+#ifdef _LIBC
+# ifdef USE_IN_LIBIO
+ _IO_flockfile (stderr);
+# else
+ __flockfile (stderr);
+# endif
+#endif
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ {
+#if _LIBC && USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s: ", program_name);
+ else
+#endif
+ fprintf (stderr, "%s:", program_name);
+ }
+
+ if (file_name != NULL)
+ {
+#if _LIBC && USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s:%d: ", file_name, line_number);
+ else
+#endif
+ fprintf (stderr, "%s:%d: ", file_name, line_number);
+ }
+
+#ifdef VA_START
+ VA_START (args, message);
+ error_tail (status, errnum, message, args);
+#else
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ ++error_message_count;
+ if (errnum)
+ {
+# if defined HAVE_STRERROR_R || _LIBC
+ char errbuf[1024];
+ /* Don't use __strerror_r's return value because on some systems
+ (at least DEC UNIX 4.0[A-D]) strerror_r returns `int'. */
+ __strerror_r (errnum, errbuf, sizeof errbuf);
+ fprintf (stderr, ": %s", errbuf);
+# else
+ fprintf (stderr, ": %s", strerror (errnum));
+# endif
+ }
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+#endif
+
+#ifdef _LIBC
+# ifdef USE_IN_LIBIO
+ _IO_funlockfile (stderr);
+# else
+ __funlockfile (stderr);
+# endif
+#endif
+}
+
+#ifdef _LIBC
+/* Make the weak alias. */
+# undef error
+# undef error_at_line
+weak_alias (__error, error)
+weak_alias (__error_at_line, error_at_line)
+#endif
diff --git a/contrib/tar/lib/error.h b/contrib/tar/lib/error.h
new file mode 100644
index 0000000..177b2dc
--- /dev/null
+++ b/contrib/tar/lib/error.h
@@ -0,0 +1,78 @@
+/* Declaration for error-reporting function
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifndef _ERROR_H
+#define _ERROR_H 1
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+# define __attribute__(Spec) /* empty */
+# endif
+/* The __-protected variants of `format' and `printf' attributes
+ are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __format__ format
+# define __printf__ printf
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (__STDC__) && __STDC__
+
+/* Print a message with `fprintf (stderr, FORMAT, ...)';
+ if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
+ If STATUS is nonzero, terminate the program with `exit (STATUS)'. */
+
+extern void error (int status, int errnum, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+
+extern void error_at_line (int status, int errnum, const char *fname,
+ unsigned int lineno, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 5, 6)));
+
+/* If NULL, error will flush stdout, then print on stderr the program
+ name, a colon and a space. Otherwise, error will call this
+ function without parameters instead. */
+extern void (*error_print_progname) (void);
+
+#else
+void error ();
+void error_at_line ();
+extern void (*error_print_progname) ();
+#endif
+
+/* This variable is incremented each time `error' is called. */
+extern unsigned int error_message_count;
+
+/* Sometimes we want to have at most one error per line. This
+ variable controls whether this mode is selected or not. */
+extern int error_one_per_line;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* error.h */
diff --git a/contrib/tar/lib/exclude.c b/contrib/tar/lib/exclude.c
new file mode 100644
index 0000000..e44145c
--- /dev/null
+++ b/contrib/tar/lib/exclude.c
@@ -0,0 +1,267 @@
+/* exclude.c -- exclude file names
+
+ Copyright 1992, 1993, 1994, 1997, 1999, 2000, 2001 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Paul Eggert <eggert@twinsun.com> */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+typedef enum {false = 0, true = 1} bool;
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#if HAVE_STRING_H
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+
+#include "exclude.h"
+#include "fnmatch.h"
+#include "xalloc.h"
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
+/* Verify a requirement at compile-time (unlike assert, which is runtime). */
+#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
+
+verify (EXCLUDE_macros_do_not_collide_with_FNM_macros,
+ (((EXCLUDE_ANCHORED | EXCLUDE_INCLUDE | EXCLUDE_WILDCARDS)
+ & (FNM_FILE_NAME | FNM_NOESCAPE | FNM_PERIOD | FNM_LEADING_DIR
+ | FNM_CASEFOLD))
+ == 0));
+
+/* An exclude pattern-options pair. The options are fnmatch options
+ ORed with EXCLUDE_* options. */
+
+struct patopts
+ {
+ char const *pattern;
+ int options;
+ };
+
+/* An exclude list, of pattern-options pairs. */
+
+struct exclude
+ {
+ struct patopts *exclude;
+ size_t exclude_alloc;
+ size_t exclude_count;
+ };
+
+/* Return a newly allocated and empty exclude list. */
+
+struct exclude *
+new_exclude (void)
+{
+ struct exclude *ex = (struct exclude *) xmalloc (sizeof *ex);
+ ex->exclude_count = 0;
+ ex->exclude_alloc = (1 << 6); /* This must be a power of 2. */
+ ex->exclude = (struct patopts *) xmalloc (ex->exclude_alloc
+ * sizeof ex->exclude[0]);
+ return ex;
+}
+
+/* Free the storage associated with an exclude list. */
+
+void
+free_exclude (struct exclude *ex)
+{
+ free (ex->exclude);
+ free (ex);
+}
+
+/* Return zero if PATTERN matches F, obeying OPTIONS, except that
+ (unlike fnmatch) wildcards are disabled in PATTERN. */
+
+static int
+fnmatch_no_wildcards (char const *pattern, char const *f, int options)
+{
+ if (! (options & FNM_LEADING_DIR))
+ return ((options & FNM_CASEFOLD)
+ ? strcasecmp (pattern, f)
+ : strcmp (pattern, f));
+ else
+ {
+ size_t patlen = strlen (pattern);
+ int r = ((options & FNM_CASEFOLD)
+ ? strncasecmp (pattern, f, patlen)
+ : strncmp (pattern, f, patlen));
+ if (! r)
+ {
+ r = f[patlen];
+ if (r == '/')
+ r = 0;
+ }
+ return r;
+ }
+}
+
+/* Return true if EX excludes F. */
+
+bool
+excluded_filename (struct exclude const *ex, char const *f)
+{
+ size_t exclude_count = ex->exclude_count;
+
+ /* If no options are given, the default is to include. */
+ if (exclude_count == 0)
+ return 0;
+ else
+ {
+ struct patopts const *exclude = ex->exclude;
+ size_t i;
+
+ /* Otherwise, the default is the opposite of the first option. */
+ bool excluded = !! (exclude[0].options & EXCLUDE_INCLUDE);
+
+ /* Scan through the options, seeing whether they change F from
+ excluded to included or vice versa. */
+ for (i = 0; i < exclude_count; i++)
+ {
+ char const *pattern = exclude[i].pattern;
+ int options = exclude[i].options;
+ if (excluded == !! (options & EXCLUDE_INCLUDE))
+ {
+ int (*matcher) PARAMS ((char const *, char const *, int)) =
+ (options & EXCLUDE_WILDCARDS
+ ? fnmatch
+ : fnmatch_no_wildcards);
+ bool matched = ((*matcher) (pattern, f, options) == 0);
+ char const *p;
+
+ if (! (options & EXCLUDE_ANCHORED))
+ for (p = f; *p && ! matched; p++)
+ if (*p == '/' && p[1] != '/')
+ matched = ((*matcher) (pattern, p + 1, options) == 0);
+
+ excluded ^= matched;
+ }
+ }
+
+ return excluded;
+ }
+}
+
+/* Append to EX the exclusion PATTERN with OPTIONS. */
+
+void
+add_exclude (struct exclude *ex, char const *pattern, int options)
+{
+ struct patopts *patopts;
+
+ if (ex->exclude_alloc <= ex->exclude_count)
+ {
+ size_t s = 2 * ex->exclude_alloc;
+ if (! (0 < s && s <= SIZE_MAX / sizeof ex->exclude[0]))
+ xalloc_die ();
+ ex->exclude_alloc = s;
+ ex->exclude = (struct patopts *) xrealloc (ex->exclude,
+ s * sizeof ex->exclude[0]);
+ }
+
+ patopts = &ex->exclude[ex->exclude_count++];
+ patopts->pattern = pattern;
+ patopts->options = options;
+}
+
+/* Use ADD_FUNC to append to EX the patterns in FILENAME, each with
+ OPTIONS. LINE_END terminates each pattern in the file. Return -1
+ on failure, 0 on success. */
+
+int
+add_exclude_file (void (*add_func) PARAMS ((struct exclude *,
+ char const *, int)),
+ struct exclude *ex, char const *filename, int options,
+ char line_end)
+{
+ bool use_stdin = filename[0] == '-' && !filename[1];
+ FILE *in;
+ char *buf;
+ char *p;
+ char const *pattern;
+ char const *lim;
+ size_t buf_alloc = (1 << 10); /* This must be a power of two. */
+ size_t buf_count = 0;
+ int c;
+ int e = 0;
+
+ if (use_stdin)
+ in = stdin;
+ else if (! (in = fopen (filename, "r")))
+ return -1;
+
+ buf = xmalloc (buf_alloc);
+
+ while ((c = getc (in)) != EOF)
+ {
+ buf[buf_count++] = c;
+ if (buf_count == buf_alloc)
+ {
+ buf_alloc *= 2;
+ if (! buf_alloc)
+ xalloc_die ();
+ buf = xrealloc (buf, buf_alloc);
+ }
+ }
+
+ if (ferror (in))
+ e = errno;
+
+ if (!use_stdin && fclose (in) != 0)
+ e = errno;
+
+ buf = xrealloc (buf, buf_count + 1);
+
+ for (pattern = p = buf, lim = buf + buf_count; p <= lim; p++)
+ if (p < lim ? *p == line_end : buf < p && p[-1])
+ {
+ *p = '\0';
+ (*add_func) (ex, pattern, options);
+ pattern = p + 1;
+ }
+
+ errno = e;
+ return e ? -1 : 0;
+}
diff --git a/contrib/tar/lib/exclude.h b/contrib/tar/lib/exclude.h
new file mode 100644
index 0000000..54c33ef
--- /dev/null
+++ b/contrib/tar/lib/exclude.h
@@ -0,0 +1,49 @@
+/* exclude.h -- declarations for excluding file names
+ Copyright 1992, 1993, 1994, 1997, 1999, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Paul Eggert <eggert@twinsun.com> */
+
+#ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+#endif
+
+/* Exclude options, which can be ORed with fnmatch options. */
+
+/* Patterns must match the start of file names, instead of matching
+ anywhere after a '/'. */
+#define EXCLUDE_ANCHORED (1 << 5)
+
+/* Include instead of exclude. */
+#define EXCLUDE_INCLUDE (1 << 6)
+
+/* '?', '*', '[', and '\\' are special in patterns. Without this
+ option, these characters are ordinary and fnmatch is not used. */
+#define EXCLUDE_WILDCARDS (1 << 7)
+
+struct exclude;
+
+struct exclude *new_exclude PARAMS ((void));
+void free_exclude PARAMS ((struct exclude *));
+void add_exclude PARAMS ((struct exclude *, char const *, int));
+int add_exclude_file PARAMS ((void (*) (struct exclude *, char const *, int),
+ struct exclude *, char const *, int, char));
+bool excluded_filename PARAMS ((struct exclude const *, char const *));
diff --git a/contrib/tar/lib/fileblocks.c b/contrib/tar/lib/fileblocks.c
new file mode 100644
index 0000000..2c94430
--- /dev/null
+++ b/contrib/tar/lib/fileblocks.c
@@ -0,0 +1,77 @@
+/* Convert file size to number of blocks on System V-like machines.
+ Copyright (C) 1990, 1997, 1998, 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Brian L. Matthews, blm@6sceng.UUCP. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#if !HAVE_STRUCT_STAT_ST_BLOCKS && !defined _POSIX_SOURCE && defined BSIZE
+
+# if HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+
+# ifndef NINDIR
+
+# if defined (__DJGPP__)
+typedef long daddr_t; /* for disk address */
+# endif
+
+/* Some SysV's, like Irix, seem to lack this. Hope it's correct. */
+/* Number of inode pointers per indirect block. */
+# define NINDIR (BSIZE / sizeof (daddr_t))
+# endif /* !NINDIR */
+
+/* Number of direct block addresses in an inode. */
+# define NDIR 10
+
+/* Return the number of 512-byte blocks in a file of SIZE bytes. */
+
+off_t
+st_blocks (off_t size)
+{
+ off_t datablks = size / 512 + (size % 512 != 0);
+ off_t indrblks = 0;
+
+ if (datablks > NDIR)
+ {
+ indrblks = (datablks - NDIR - 1) / NINDIR + 1;
+
+ if (datablks > NDIR + NINDIR)
+ {
+ indrblks += (datablks - NDIR - NINDIR - 1) / (NINDIR * NINDIR) + 1;
+
+ if (datablks > NDIR + NINDIR + NINDIR * NINDIR)
+ indrblks++;
+ }
+ }
+
+ return datablks + indrblks;
+}
+#else
+/* This declaration is solely to ensure that after preprocessing
+ this file is never empty. */
+extern int textutils_fileblocks_unused;
+#endif
diff --git a/contrib/tar/lib/fnmatch.c b/contrib/tar/lib/fnmatch.c
new file mode 100644
index 0000000..9bff8c2
--- /dev/null
+++ b/contrib/tar/lib/fnmatch.c
@@ -0,0 +1,230 @@
+/* Copyright 1991, 1992, 1993, 1996, 1997, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Enable GNU extensions in fnmatch.h. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#include <errno.h>
+#include <fnmatch.h>
+#include <ctype.h>
+
+#if defined STDC_HEADERS || !defined isascii
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii (c)
+#endif
+
+#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
+
+
+#ifndef errno
+extern int errno;
+#endif
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+ it matches, nonzero if not. */
+int
+fnmatch (const char *pattern, const char *string, int flags)
+{
+ register const char *p = pattern, *n = string;
+ register char c;
+
+/* Note that this evaluates C many times. */
+#define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER ((unsigned char) (c)) \
+ ? tolower ((unsigned char) (c)) \
+ : (c))
+
+ while ((c = *p++) != '\0')
+ {
+ c = FOLD (c);
+
+ switch (c)
+ {
+ case '?':
+ if (*n == '\0')
+ return FNM_NOMATCH;
+ else if ((flags & FNM_FILE_NAME) && *n == '/')
+ return FNM_NOMATCH;
+ else if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+ break;
+
+ case '\\':
+ if (!(flags & FNM_NOESCAPE))
+ {
+ c = *p++;
+ if (c == '\0')
+ /* Trailing \ loses. */
+ return FNM_NOMATCH;
+ c = FOLD (c);
+ }
+ if (FOLD (*n) != c)
+ return FNM_NOMATCH;
+ break;
+
+ case '*':
+ if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+
+ for (c = *p++; c == '?' || c == '*'; c = *p++)
+ {
+ if (c == '?')
+ {
+ /* A ? needs to match one character. */
+ if (*n == '\0' || (*n == '/' && (flags & FNM_FILE_NAME)))
+ /* There isn't another character; no match. */
+ return FNM_NOMATCH;
+ else
+ /* One character of the string is consumed in matching
+ this ? wildcard, so *??? won't match if there are
+ less than three characters. */
+ ++n;
+ }
+ }
+
+ if (c == '\0')
+ {
+ if ((flags & (FNM_FILE_NAME | FNM_LEADING_DIR)) == FNM_FILE_NAME)
+ for (; *n != '\0'; n++)
+ if (*n == '/')
+ return FNM_NOMATCH;
+ return 0;
+ }
+
+ {
+ char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
+ c1 = FOLD (c1);
+ for (--p; *n != '\0'; ++n)
+ if ((c == '[' || FOLD (*n) == c1) &&
+ fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+ return 0;
+ else if (*n == '/' && (flags & FNM_FILE_NAME))
+ break;
+ return FNM_NOMATCH;
+ }
+
+ case '[':
+ {
+ /* Nonzero if the sense of the character class is inverted. */
+ register int not;
+
+ if (*n == '\0')
+ return FNM_NOMATCH;
+
+ if ((flags & FNM_PERIOD) && *n == '.' &&
+ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+ return FNM_NOMATCH;
+
+ not = (*p == '!' || *p == '^');
+ if (not)
+ ++p;
+
+ c = *p++;
+ for (;;)
+ {
+ register char cstart = c, cend = c;
+
+ if (!(flags & FNM_NOESCAPE) && c == '\\')
+ {
+ if (*p == '\0')
+ return FNM_NOMATCH;
+ cstart = cend = *p++;
+ }
+
+ cstart = cend = FOLD (cstart);
+
+ if (c == '\0')
+ /* [ (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ c = *p++;
+ c = FOLD (c);
+
+ if ((flags & FNM_FILE_NAME) && c == '/')
+ /* [/] can never match. */
+ return FNM_NOMATCH;
+
+ if (c == '-' && *p != ']')
+ {
+ cend = *p++;
+ if (!(flags & FNM_NOESCAPE) && cend == '\\')
+ cend = *p++;
+ if (cend == '\0')
+ return FNM_NOMATCH;
+ cend = FOLD (cend);
+
+ c = *p++;
+ }
+
+ if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
+ goto matched;
+
+ if (c == ']')
+ break;
+ }
+ if (!not)
+ return FNM_NOMATCH;
+ break;
+
+ matched:;
+ /* Skip the rest of the [...] that already matched. */
+ while (c != ']')
+ {
+ if (c == '\0')
+ /* [... (unterminated) loses. */
+ return FNM_NOMATCH;
+
+ c = *p++;
+ if (!(flags & FNM_NOESCAPE) && c == '\\')
+ {
+ if (*p == '\0')
+ return FNM_NOMATCH;
+ /* XXX 1003.2d11 is unclear if this is right. */
+ ++p;
+ }
+ }
+ if (not)
+ return FNM_NOMATCH;
+ }
+ break;
+
+ default:
+ if (c != FOLD (*n))
+ return FNM_NOMATCH;
+ }
+
+ ++n;
+ }
+
+ if (*n == '\0')
+ return 0;
+
+ if ((flags & FNM_LEADING_DIR) && *n == '/')
+ /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
+ return 0;
+
+ return FNM_NOMATCH;
+
+#undef FOLD
+}
diff --git a/contrib/tar/lib/fnmatch.hin b/contrib/tar/lib/fnmatch.hin
new file mode 100644
index 0000000..af1dcf5
--- /dev/null
+++ b/contrib/tar/lib/fnmatch.hin
@@ -0,0 +1,69 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+NOTE: The canonical source of this file is maintained with the GNU C Library.
+Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _FNMATCH_H
+
+#define _FNMATCH_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+#undef __P
+#define __P(protos) protos
+#else /* Not C++ or ANSI C. */
+#undef __P
+#define __P(protos) ()
+/* We can get away without defining `const' here only because in this file
+ it is used only inside the prototype for `fnmatch', which is elided in
+ non-ANSI C where `const' is problematical. */
+#endif /* C++ or ANSI C. */
+
+
+/* We #undef these before defining them because some losing systems
+ (HP-UX A.08.07 for example) define these in <unistd.h>. */
+#undef FNM_PATHNAME
+#undef FNM_NOESCAPE
+#undef FNM_PERIOD
+
+/* Bits set in the FLAGS argument to `fnmatch'. */
+#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
+#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
+#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
+
+#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE)
+#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
+#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
+#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
+#endif
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN. */
+#define FNM_NOMATCH 1
+
+/* Match STRING against the filename pattern PATTERN,
+ returning zero if it matches, FNM_NOMATCH if not. */
+extern int fnmatch __P ((const char *__pattern, const char *__string,
+ int __flags));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* fnmatch.h */
diff --git a/contrib/tar/lib/ftruncate.c b/contrib/tar/lib/ftruncate.c
new file mode 100644
index 0000000..adf87f6
--- /dev/null
+++ b/contrib/tar/lib/ftruncate.c
@@ -0,0 +1,95 @@
+/* ftruncate emulations that work on some System V's.
+ This file is in the public domain. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef F_CHSIZE
+
+int
+ftruncate (int fd, off_t length)
+{
+ return fcntl (fd, F_CHSIZE, length);
+}
+
+#else /* not F_CHSIZE */
+# ifdef F_FREESP
+
+/* By William Kucharski <kucharsk@netcom.com>. */
+
+# include <sys/stat.h>
+# include <errno.h>
+# if HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+
+int
+ftruncate (int fd, off_t length)
+{
+ struct flock fl;
+ struct stat filebuf;
+
+ if (fstat (fd, &filebuf) < 0)
+ return -1;
+
+ if (filebuf.st_size < length)
+ {
+ /* Extend file length. */
+ if (lseek (fd, (length - 1), SEEK_SET) < 0)
+ return -1;
+
+ /* Write a "0" byte. */
+ if (write (fd, "", 1) != 1)
+ return -1;
+ }
+ else
+ {
+
+ /* Truncate length. */
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = length;
+ fl.l_type = F_WRLCK; /* write lock on file space */
+
+ /* This relies on the *undocumented* F_FREESP argument to fcntl,
+ which truncates the file so that it ends at the position
+ indicated by fl.l_start. Will minor miracles never cease? */
+
+ if (fcntl (fd, F_FREESP, &fl) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+# else /* not F_CHSIZE nor F_FREESP */
+# if HAVE_CHSIZE
+
+int
+ftruncate (int fd, off_t length)
+{
+ return chsize (fd, length);
+}
+
+# else /* not F_CHSIZE nor F_FREESP nor HAVE_CHSIZE */
+
+# include <errno.h>
+# ifndef errno
+extern int errno;
+# endif
+
+int
+ftruncate (int fd, off_t length)
+{
+ errno = EIO;
+ return -1;
+}
+
+# endif /* not HAVE_CHSIZE */
+# endif /* not F_FREESP */
+#endif /* not F_CHSIZE */
diff --git a/contrib/tar/lib/full-write.c b/contrib/tar/lib/full-write.c
new file mode 100644
index 0000000..4e566f6
--- /dev/null
+++ b/contrib/tar/lib/full-write.c
@@ -0,0 +1,67 @@
+/* full-write.c -- an interface to write that retries after interrupts
+
+ Copyright 1993, 1994, 1997, 1998, 1999, 2000, 2001 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Written by Paul Eggert. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#include "full-write.h"
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted
+ or if partial writes occur. Return the number of bytes successfully
+ written, setting errno if that is less than LEN. */
+
+size_t
+full_write (int desc, const char *ptr, size_t len)
+{
+ size_t total_written = 0;
+
+ while (len > 0)
+ {
+ ssize_t written = write (desc, ptr, len);
+ if (written <= 0)
+ {
+ /* Some buggy drivers return 0 when you fall off a device's end. */
+ if (written == 0)
+ errno = ENOSPC;
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ break;
+ }
+ total_written += written;
+ ptr += written;
+ len -= written;
+ }
+ return total_written;
+}
diff --git a/contrib/tar/lib/full-write.h b/contrib/tar/lib/full-write.h
new file mode 100644
index 0000000..f23bccb
--- /dev/null
+++ b/contrib/tar/lib/full-write.h
@@ -0,0 +1,9 @@
+#ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+#endif
+
+size_t full_write PARAMS ((int, const char *, size_t));
diff --git a/contrib/tar/lib/getdate.c b/contrib/tar/lib/getdate.c
new file mode 100644
index 0000000..77bbd02
--- /dev/null
+++ b/contrib/tar/lib/getdate.c
@@ -0,0 +1,2210 @@
+
+/* A Bison parser, made from getdate.y
+ by GNU bison 1.29. */
+
+#define YYBISON 1 /* Identify Bison output. */
+
+# define tAGO 257
+# define tDST 258
+# define tDAY 259
+# define tDAY_UNIT 260
+# define tDAYZONE 261
+# define tHOUR_UNIT 262
+# define tLOCAL_ZONE 263
+# define tMERIDIAN 264
+# define tMINUTE_UNIT 265
+# define tMONTH 266
+# define tMONTH_UNIT 267
+# define tSEC_UNIT 268
+# define tYEAR_UNIT 269
+# define tZONE 270
+# define tSNUMBER 271
+# define tUNUMBER 272
+
+#line 1 "getdate.y"
+
+/* Parse a string into an internal time stamp.
+ Copyright 1999, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Originally written by Steven M. Bellovin <smb@research.att.com> while
+ at the University of North Carolina at Chapel Hill. Later tweaked by
+ a couple of people on Usenet. Completely overhauled by Rich $alz
+ <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
+
+ Modified by Paul Eggert <eggert@twinsun.com> in August 1999 to do
+ the right thing about local DST. Unlike previous versions, this
+ version is reentrant. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+# ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+# endif
+#endif
+
+/* Since the code of getdate.y is not included in the Emacs executable
+ itself, there is no need to #define static in this file. Even if
+ the code were included in the Emacs executable, it probably
+ wouldn't do any harm to #undef it here; this will only cause
+ problems if we try to write to a static variable, which I don't
+ think this code needs to do. */
+#ifdef emacs
+# undef static
+#endif
+
+#include <ctype.h>
+
+#if HAVE_STDLIB_H
+# include <stdlib.h> /* for `free'; used by Bison 1.27 */
+#endif
+
+#if STDC_HEADERS || (! defined isascii && ! HAVE_ISASCII)
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii (c)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c))
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+
+/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
+ - Its arg may be any int or unsigned int; it need not be an unsigned char.
+ - It's guaranteed to evaluate its argument exactly once.
+ - It's typically faster.
+ Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+ only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless
+ it's important to use the locale's definition of `digit' even when the
+ host does not conform to Posix. */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+#endif
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif
+
+#define EPOCH_YEAR 1970
+#define TM_YEAR_BASE 1900
+
+#define HOUR(x) ((x) * 60)
+
+/* An integer value, and the number of digits in its textual
+ representation. */
+typedef struct
+{
+ int value;
+ int digits;
+} textint;
+
+/* An entry in the lexical lookup table. */
+typedef struct
+{
+ char const *name;
+ int type;
+ int value;
+} table;
+
+/* Meridian: am, pm, or 24-hour style. */
+enum { MERam, MERpm, MER24 };
+
+/* Information passed to and from the parser. */
+typedef struct
+{
+ /* The input string remaining to be parsed. */
+ const char *input;
+
+ /* N, if this is the Nth Tuesday. */
+ int day_ordinal;
+
+ /* Day of week; Sunday is 0. */
+ int day_number;
+
+ /* tm_isdst flag for the local zone. */
+ int local_isdst;
+
+ /* Time zone, in minutes east of UTC. */
+ int time_zone;
+
+ /* Style used for time. */
+ int meridian;
+
+ /* Gregorian year, month, day, hour, minutes, and seconds. */
+ textint year;
+ int month;
+ int day;
+ int hour;
+ int minutes;
+ int seconds;
+
+ /* Relative year, month, day, hour, minutes, and seconds. */
+ int rel_year;
+ int rel_month;
+ int rel_day;
+ int rel_hour;
+ int rel_minutes;
+ int rel_seconds;
+
+ /* Counts of nonterminals of various flavors parsed so far. */
+ int dates_seen;
+ int days_seen;
+ int local_zones_seen;
+ int rels_seen;
+ int times_seen;
+ int zones_seen;
+
+ /* Table of local time zone abbrevations, terminated by a null entry. */
+ table local_time_zone_table[3];
+} parser_control;
+
+#define PC (* (parser_control *) parm)
+#define YYLEX_PARAM parm
+#define YYPARSE_PARAM parm
+
+static int yyerror ();
+static int yylex ();
+
+
+#line 172 "getdate.y"
+typedef union
+{
+ int intval;
+ textint textintval;
+} YYSTYPE;
+#include <stdio.h>
+
+
+
+#define YYFINAL 64
+#define YYFLAG -32768
+#define YYNTBASE 22
+
+/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */
+#define YYTRANSLATE(x) ((unsigned)(x) <= 272 ? yytranslate[x] : 33)
+
+/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */
+static const char yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 20, 2, 2, 21, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 19, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] =
+{
+ 0, 0, 1, 4, 6, 8, 10, 12, 14, 16,
+ 18, 21, 26, 31, 38, 45, 47, 50, 52, 54,
+ 57, 59, 62, 65, 69, 75, 79, 83, 86, 91,
+ 94, 98, 101, 103, 106, 109, 111, 114, 117, 119,
+ 122, 125, 127, 130, 133, 135, 138, 141, 143, 146,
+ 149, 151, 153, 154
+};
+static const short yyrhs[] =
+{
+ -1, 22, 23, 0, 24, 0, 25, 0, 26, 0,
+ 28, 0, 27, 0, 29, 0, 31, 0, 18, 10,
+ 0, 18, 19, 18, 32, 0, 18, 19, 18, 17,
+ 0, 18, 19, 18, 19, 18, 32, 0, 18, 19,
+ 18, 19, 18, 17, 0, 9, 0, 9, 4, 0,
+ 16, 0, 7, 0, 16, 4, 0, 5, 0, 5,
+ 20, 0, 18, 5, 0, 18, 21, 18, 0, 18,
+ 21, 18, 21, 18, 0, 18, 17, 17, 0, 18,
+ 12, 17, 0, 12, 18, 0, 12, 18, 20, 18,
+ 0, 18, 12, 0, 18, 12, 18, 0, 30, 3,
+ 0, 30, 0, 18, 15, 0, 17, 15, 0, 15,
+ 0, 18, 13, 0, 17, 13, 0, 13, 0, 18,
+ 6, 0, 17, 6, 0, 6, 0, 18, 8, 0,
+ 17, 8, 0, 8, 0, 18, 11, 0, 17, 11,
+ 0, 11, 0, 18, 14, 0, 17, 14, 0, 14,
+ 0, 18, 0, 0, 10, 0
+};
+
+#endif
+
+#if YYDEBUG != 0
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const short yyrline[] =
+{
+ 0, 189, 191, 194, 197, 199, 201, 203, 205, 207,
+ 210, 218, 225, 233, 240, 251, 254, 258, 261, 263,
+ 267, 273, 278, 285, 291, 311, 318, 326, 331, 337,
+ 342, 350, 360, 363, 366, 368, 370, 372, 374, 376,
+ 378, 380, 382, 384, 386, 388, 390, 392, 394, 396,
+ 398, 402, 438, 441
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined YYERROR_VERBOSE
+
+/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */
+static const char *const yytname[] =
+{
+ "$", "error", "$undefined.", "tAGO", "tDST", "tDAY", "tDAY_UNIT",
+ "tDAYZONE", "tHOUR_UNIT", "tLOCAL_ZONE", "tMERIDIAN", "tMINUTE_UNIT",
+ "tMONTH", "tMONTH_UNIT", "tSEC_UNIT", "tYEAR_UNIT", "tZONE", "tSNUMBER",
+ "tUNUMBER", "':'", "','", "'/'", "spec", "item", "time", "local_zone",
+ "zone", "day", "date", "rel", "relunit", "number", "o_merid", NULL
+};
+#endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const short yyr1[] =
+{
+ 0, 22, 22, 23, 23, 23, 23, 23, 23, 23,
+ 24, 24, 24, 24, 24, 25, 25, 26, 26, 26,
+ 27, 27, 27, 28, 28, 28, 28, 28, 28, 28,
+ 28, 29, 29, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 31, 32, 32
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const short yyr2[] =
+{
+ 0, 0, 2, 1, 1, 1, 1, 1, 1, 1,
+ 2, 4, 4, 6, 6, 1, 2, 1, 1, 2,
+ 1, 2, 2, 3, 5, 3, 3, 2, 4, 2,
+ 3, 2, 1, 2, 2, 1, 2, 2, 1, 2,
+ 2, 1, 2, 2, 1, 2, 2, 1, 2, 2,
+ 1, 1, 0, 1
+};
+
+/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE
+ doesn't specify something else to do. Zero means the default is an
+ error. */
+static const short yydefact[] =
+{
+ 1, 0, 20, 41, 18, 44, 15, 47, 0, 38,
+ 50, 35, 17, 0, 51, 2, 3, 4, 5, 7,
+ 6, 8, 32, 9, 21, 16, 27, 19, 40, 43,
+ 46, 37, 49, 34, 22, 39, 42, 10, 45, 29,
+ 36, 48, 33, 0, 0, 0, 31, 0, 26, 30,
+ 25, 52, 23, 28, 53, 12, 0, 11, 0, 52,
+ 24, 14, 13, 0, 0
+};
+
+static const short yydefgoto[] =
+{
+ 1, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 57
+};
+
+static const short yypact[] =
+{
+ -32768, 0, 1,-32768,-32768,-32768, 19,-32768, -14,-32768,
+ -32768,-32768, 32, 26, 14,-32768,-32768,-32768,-32768,-32768,
+ -32768,-32768, 27,-32768,-32768,-32768, 22,-32768,-32768,-32768,
+ -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, -16,
+ -32768,-32768,-32768, 29, 25, 30,-32768, 31,-32768,-32768,
+ -32768, 28, 23,-32768,-32768,-32768, 33,-32768, 34, -7,
+ -32768,-32768,-32768, 50,-32768
+};
+
+static const short yypgoto[] =
+{
+ -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+ -6
+};
+
+
+#define YYLAST 53
+
+
+static const short yytable[] =
+{
+ 63, 48, 49, 54, 26, 2, 3, 4, 5, 6,
+ 61, 7, 8, 9, 10, 11, 12, 13, 14, 34,
+ 35, 24, 36, 25, 37, 38, 39, 40, 41, 42,
+ 46, 43, 28, 44, 29, 45, 27, 30, 54, 31,
+ 32, 33, 47, 51, 58, 55, 50, 56, 52, 53,
+ 64, 59, 60, 62
+};
+
+static const short yycheck[] =
+{
+ 0, 17, 18, 10, 18, 5, 6, 7, 8, 9,
+ 17, 11, 12, 13, 14, 15, 16, 17, 18, 5,
+ 6, 20, 8, 4, 10, 11, 12, 13, 14, 15,
+ 3, 17, 6, 19, 8, 21, 4, 11, 10, 13,
+ 14, 15, 20, 18, 21, 17, 17, 19, 18, 18,
+ 0, 18, 18, 59
+};
+#define YYPURE 1
+
+/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
+#line 3 "/opt/reb/share/bison/bison.simple"
+
+/* Skeleton output parser for bison,
+ Copyright 1984, 1989, 1990, 2000, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* This is the parser code that is written into each bison parser when
+ the %semantic_parser declaration is not specified in the grammar.
+ It was written by Richard Stallman by simplifying the hairy parser
+ used when %semantic_parser is specified. */
+
+#ifndef YYSTACK_USE_ALLOCA
+# ifdef alloca
+# define YYSTACK_USE_ALLOCA 1
+# else /* alloca not defined */
+# ifdef __GNUC__
+# define YYSTACK_USE_ALLOCA 1
+# define alloca __builtin_alloca
+# else /* not GNU C. */
+# if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
+# define YYSTACK_USE_ALLOCA 1
+# include <alloca.h>
+# else /* not sparc */
+ /* We think this test detects Watcom and Microsoft C. */
+ /* This used to test MSDOS, but that is a bad idea since that
+ symbol is in the user namespace. */
+# if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
+# if 0
+ /* No need for malloc.h, which pollutes the namespace; instead,
+ just don't use alloca. */
+# include <malloc.h>
+# endif
+# else /* not MSDOS, or __TURBOC__ */
+# if defined(_AIX)
+ /* I don't know what this was needed for, but it pollutes the
+ namespace. So I turned it off. rms, 2 May 1997. */
+ /* #include <malloc.h> */
+ #pragma alloca
+# define YYSTACK_USE_ALLOCA 1
+# else /* not MSDOS, or __TURBOC__, or _AIX */
+# if 0
+ /* haible@ilog.fr says this works for HPUX 9.05 and up, and on
+ HPUX 10. Eventually we can turn this on. */
+# ifdef __hpux
+# define YYSTACK_USE_ALLOCA 1
+# define alloca __builtin_alloca
+# endif /* __hpux */
+# endif
+# endif /* not _AIX */
+# endif /* not MSDOS, or __TURBOC__ */
+# endif /* not sparc */
+# endif /* not GNU C */
+# endif /* alloca not defined */
+#endif /* YYSTACK_USE_ALLOCA not defined */
+
+#if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+#else
+# define YYSTACK_ALLOC malloc
+#endif
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY -2
+#define YYEOF 0
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrlab1
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+#define YYFAIL goto yyerrlab
+#define YYRECOVERING() (!!yyerrstatus)
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yychar1 = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror ("syntax error: cannot back up"); \
+ YYERROR; \
+ } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run).
+
+ When YYLLOC_DEFAULT is run, CURRENT is set the location of the
+ first token. By default, to implement support for ranges, extend
+ its range to the last symbol. */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current.last_line = Rhs[N].last_line; \
+ Current.last_column = Rhs[N].last_column;
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#if YYPURE
+# if YYLSP_NEEDED
+# ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
+# else
+# define YYLEX yylex (&yylval, &yylloc)
+# endif
+# else /* !YYLSP_NEEDED */
+# ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+# else
+# define YYLEX yylex (&yylval)
+# endif
+# endif /* !YYLSP_NEEDED */
+#else /* !YYPURE */
+# define YYLEX yylex ()
+#endif /* !YYPURE */
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ fprintf Args; \
+} while (0)
+/* Nonzero means print parse trace. [The following comment makes no
+ sense to me. Could someone clarify it? --akim] Since this is
+ uninitialized, it does not stop multiple parsers from coexisting.
+ */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+#endif /* !YYDEBUG */
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used). */
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+/* Define __yy_memcpy. Note that the size argument
+ should be passed with type unsigned int, because that is what the non-GCC
+ definitions require. With GCC, __builtin_memcpy takes an arg
+ of type size_t, but it can handle unsigned int. */
+
+#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
+# define __yy_memcpy(To, From, Count) __builtin_memcpy (To, From, Count)
+#else /* not GNU C or C++ */
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+# ifndef __cplusplus
+__yy_memcpy (to, from, count)
+ char *to;
+ const char *from;
+ unsigned int count;
+# else /* __cplusplus */
+__yy_memcpy (char *to, const char *from, unsigned int count)
+# endif
+{
+ register const char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#endif
+
+#line 212 "/opt/reb/share/bison/bison.simple"
+
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+ into yyparse. The argument should have type void *.
+ It should actually point to an object.
+ Grammar actions can access the variable by casting it
+ to the proper pointer type. */
+
+#ifdef YYPARSE_PARAM
+# ifdef __cplusplus
+# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+# define YYPARSE_PARAM_DECL
+# else /* !__cplusplus */
+# define YYPARSE_PARAM_ARG YYPARSE_PARAM
+# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+# endif /* !__cplusplus */
+#else /* !YYPARSE_PARAM */
+# define YYPARSE_PARAM_ARG
+# define YYPARSE_PARAM_DECL
+#endif /* !YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes. */
+#ifdef __GNUC__
+# ifdef YYPARSE_PARAM
+int yyparse (void *);
+# else
+int yyparse (void);
+# endif
+#endif
+
+/* YY_DECL_VARIABLES -- depending whether we use a pure parser,
+ variables are global, or local to YYPARSE. */
+
+#define _YY_DECL_VARIABLES \
+/* The lookahead symbol. */ \
+int yychar; \
+ \
+/* The semantic value of the lookahead symbol. */ \
+YYSTYPE yylval; \
+ \
+/* Number of parse errors so far. */ \
+int yynerrs;
+
+#if YYLSP_NEEDED
+# define YY_DECL_VARIABLES \
+_YY_DECL_VARIABLES \
+ \
+/* Location data for the lookahead symbol. */ \
+YYLTYPE yylloc;
+#else
+# define YY_DECL_VARIABLES \
+_YY_DECL_VARIABLES
+#endif
+
+
+/* If nonreentrant, generate the variables here. */
+
+#if !YYPURE
+YY_DECL_VARIABLES
+#endif /* !YYPURE */
+
+int
+yyparse (YYPARSE_PARAM_ARG)
+ YYPARSE_PARAM_DECL
+{
+ /* If reentrant, generate the variables here. */
+#if YYPURE
+ YY_DECL_VARIABLES
+#endif /* !YYPURE */
+
+ register int yystate;
+ register int yyn;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yychar1 = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yysv': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
+ register short *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
+
+#if YYLSP_NEEDED
+ /* The location stack. */
+ YYLTYPE yylsa[YYINITDEPTH];
+ YYLTYPE *yyls = yylsa;
+ YYLTYPE *yylsp;
+#endif
+
+#if YYLSP_NEEDED
+# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
+#else
+# define YYPOPSTACK (yyvsp--, yyssp--)
+#endif
+
+ int yystacksize = YYINITDEPTH;
+ int yyfree_stacks = 0;
+
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+# if YYLSP_NEEDED
+ YYLTYPE yyloc;
+# endif
+
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
+ int yylen;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+#if YYLSP_NEEDED
+ yylsp = yyls;
+#endif
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into memory.
+ */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+#if YYLSP_NEEDED
+ YYLTYPE *yyls1 = yyls;
+#endif
+
+ /* Get the current used size of the three stacks, in elements. */
+ int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. */
+# if YYLSP_NEEDED
+ /* This used to be a conditional around just the two extra args,
+ but that might be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yyls1, size * sizeof (*yylsp),
+ &yystacksize);
+# else
+ yyoverflow ("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yystacksize);
+# endif
+
+ yyss = yyss1; yyvs = yyvs1;
+# if YYLSP_NEEDED
+ yyls = yyls1;
+# endif
+#else /* no yyoverflow */
+ /* Extend the stack our own way. */
+ if (yystacksize >= YYMAXDEPTH)
+ {
+ yyerror ("parser stack overflow");
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+# if YYLSP_NEEDED
+ free (yyls);
+# endif
+ }
+ return 2;
+ }
+ yystacksize *= 2;
+ if (yystacksize > YYMAXDEPTH)
+ yystacksize = YYMAXDEPTH;
+# ifndef YYSTACK_USE_ALLOCA
+ yyfree_stacks = 1;
+# endif
+ yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
+ __yy_memcpy ((char *)yyss, (char *)yyss1,
+ size * (unsigned int) sizeof (*yyssp));
+ yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
+ __yy_memcpy ((char *)yyvs, (char *)yyvs1,
+ size * (unsigned int) sizeof (*yyvsp));
+# if YYLSP_NEEDED
+ yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
+ __yy_memcpy ((char *)yyls, (char *)yyls1,
+ size * (unsigned int) sizeof (*yylsp));
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + size - 1;
+ yyvsp = yyvs + size - 1;
+#if YYLSP_NEEDED
+ yylsp = yyls + size - 1;
+#endif
+
+ YYDPRINTF ((stderr, "Stack size increased to %d\n", yystacksize));
+
+ if (yyssp >= yyss + yystacksize - 1)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* yychar is either YYEMPTY or YYEOF
+ or a valid token in external form. */
+
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ /* Convert token to internal form (in yychar1) for indexing tables with */
+
+ if (yychar <= 0) /* This means end of input. */
+ {
+ yychar1 = 0;
+ yychar = YYEOF; /* Don't call YYLEX any more */
+
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yychar1 = YYTRANSLATE (yychar);
+
+#if YYDEBUG
+ /* We have to keep this `#if YYDEBUG', since we use variables
+ which are defined only if `YYDEBUG' is set. */
+ if (yydebug)
+ {
+ fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+ /* Give the individual parser a way to print the precise
+ meaning of a token, for further debugging info. */
+# ifdef YYPRINT
+ YYPRINT (stderr, yychar, yylval);
+# endif
+ fprintf (stderr, ")\n");
+ }
+#endif
+ }
+
+ yyn += yychar1;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+ goto yydefault;
+
+ yyn = yytable[yyn];
+
+ /* yyn is what to do for this token type in this state.
+ Negative => reduce, -yyn is rule number.
+ Positive => shift, yyn is new state.
+ New state is final state => don't bother to shift,
+ just return success.
+ 0, or most negative number => error. */
+
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrlab;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+ YYDPRINTF ((stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]));
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+#if YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to the semantic value of
+ the lookahead token. This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+#if YYLSP_NEEDED
+ /* Similarly for the default location. Let the user run additional
+ commands if for instance locations are ranges. */
+ yyloc = yylsp[1-yylen];
+ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+#endif
+
+#if YYDEBUG
+ /* We have to keep this `#if YYDEBUG', since we use variables which
+ are defined only if `YYDEBUG' is set. */
+ if (yydebug)
+ {
+ int i;
+
+ fprintf (stderr, "Reducing via rule %d (line %d), ",
+ yyn, yyrline[yyn]);
+
+ /* Print the symbols being reduced, and their result. */
+ for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+ fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+ fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+ }
+#endif
+
+ switch (yyn) {
+
+case 3:
+#line 196 "getdate.y"
+{ PC.times_seen++; ;
+ break;}
+case 4:
+#line 198 "getdate.y"
+{ PC.local_zones_seen++; ;
+ break;}
+case 5:
+#line 200 "getdate.y"
+{ PC.zones_seen++; ;
+ break;}
+case 6:
+#line 202 "getdate.y"
+{ PC.dates_seen++; ;
+ break;}
+case 7:
+#line 204 "getdate.y"
+{ PC.days_seen++; ;
+ break;}
+case 8:
+#line 206 "getdate.y"
+{ PC.rels_seen++; ;
+ break;}
+case 10:
+#line 212 "getdate.y"
+{
+ PC.hour = yyvsp[-1].textintval.value;
+ PC.minutes = 0;
+ PC.seconds = 0;
+ PC.meridian = yyvsp[0].intval;
+ ;
+ break;}
+case 11:
+#line 219 "getdate.y"
+{
+ PC.hour = yyvsp[-3].textintval.value;
+ PC.minutes = yyvsp[-1].textintval.value;
+ PC.seconds = 0;
+ PC.meridian = yyvsp[0].intval;
+ ;
+ break;}
+case 12:
+#line 226 "getdate.y"
+{
+ PC.hour = yyvsp[-3].textintval.value;
+ PC.minutes = yyvsp[-1].textintval.value;
+ PC.meridian = MER24;
+ PC.zones_seen++;
+ PC.time_zone = yyvsp[0].textintval.value % 100 + (yyvsp[0].textintval.value / 100) * 60;
+ ;
+ break;}
+case 13:
+#line 234 "getdate.y"
+{
+ PC.hour = yyvsp[-5].textintval.value;
+ PC.minutes = yyvsp[-3].textintval.value;
+ PC.seconds = yyvsp[-1].textintval.value;
+ PC.meridian = yyvsp[0].intval;
+ ;
+ break;}
+case 14:
+#line 241 "getdate.y"
+{
+ PC.hour = yyvsp[-5].textintval.value;
+ PC.minutes = yyvsp[-3].textintval.value;
+ PC.seconds = yyvsp[-1].textintval.value;
+ PC.meridian = MER24;
+ PC.zones_seen++;
+ PC.time_zone = yyvsp[0].textintval.value % 100 + (yyvsp[0].textintval.value / 100) * 60;
+ ;
+ break;}
+case 15:
+#line 253 "getdate.y"
+{ PC.local_isdst = yyvsp[0].intval; ;
+ break;}
+case 16:
+#line 255 "getdate.y"
+{ PC.local_isdst = yyvsp[-1].intval < 0 ? 1 : yyvsp[-1].intval + 1; ;
+ break;}
+case 17:
+#line 260 "getdate.y"
+{ PC.time_zone = yyvsp[0].intval; ;
+ break;}
+case 18:
+#line 262 "getdate.y"
+{ PC.time_zone = yyvsp[0].intval + 60; ;
+ break;}
+case 19:
+#line 264 "getdate.y"
+{ PC.time_zone = yyvsp[-1].intval + 60; ;
+ break;}
+case 20:
+#line 269 "getdate.y"
+{
+ PC.day_ordinal = 1;
+ PC.day_number = yyvsp[0].intval;
+ ;
+ break;}
+case 21:
+#line 274 "getdate.y"
+{
+ PC.day_ordinal = 1;
+ PC.day_number = yyvsp[-1].intval;
+ ;
+ break;}
+case 22:
+#line 279 "getdate.y"
+{
+ PC.day_ordinal = yyvsp[-1].textintval.value;
+ PC.day_number = yyvsp[0].intval;
+ ;
+ break;}
+case 23:
+#line 287 "getdate.y"
+{
+ PC.month = yyvsp[-2].textintval.value;
+ PC.day = yyvsp[0].textintval.value;
+ ;
+ break;}
+case 24:
+#line 292 "getdate.y"
+{
+ /* Interpret as YYYY/MM/DD if the first value has 4 or more digits,
+ otherwise as MM/DD/YY.
+ The goal in recognizing YYYY/MM/DD is solely to support legacy
+ machine-generated dates like those in an RCS log listing. If
+ you want portability, use the ISO 8601 format. */
+ if (4 <= yyvsp[-4].textintval.digits)
+ {
+ PC.year = yyvsp[-4].textintval;
+ PC.month = yyvsp[-2].textintval.value;
+ PC.day = yyvsp[0].textintval.value;
+ }
+ else
+ {
+ PC.month = yyvsp[-4].textintval.value;
+ PC.day = yyvsp[-2].textintval.value;
+ PC.year = yyvsp[0].textintval;
+ }
+ ;
+ break;}
+case 25:
+#line 312 "getdate.y"
+{
+ /* ISO 8601 format. YYYY-MM-DD. */
+ PC.year = yyvsp[-2].textintval;
+ PC.month = -yyvsp[-1].textintval.value;
+ PC.day = -yyvsp[0].textintval.value;
+ ;
+ break;}
+case 26:
+#line 319 "getdate.y"
+{
+ /* e.g. 17-JUN-1992. */
+ PC.day = yyvsp[-2].textintval.value;
+ PC.month = yyvsp[-1].intval;
+ PC.year.value = -yyvsp[0].textintval.value;
+ PC.year.digits = yyvsp[0].textintval.digits;
+ ;
+ break;}
+case 27:
+#line 327 "getdate.y"
+{
+ PC.month = yyvsp[-1].intval;
+ PC.day = yyvsp[0].textintval.value;
+ ;
+ break;}
+case 28:
+#line 332 "getdate.y"
+{
+ PC.month = yyvsp[-3].intval;
+ PC.day = yyvsp[-2].textintval.value;
+ PC.year = yyvsp[0].textintval;
+ ;
+ break;}
+case 29:
+#line 338 "getdate.y"
+{
+ PC.day = yyvsp[-1].textintval.value;
+ PC.month = yyvsp[0].intval;
+ ;
+ break;}
+case 30:
+#line 343 "getdate.y"
+{
+ PC.day = yyvsp[-2].textintval.value;
+ PC.month = yyvsp[-1].intval;
+ PC.year = yyvsp[0].textintval;
+ ;
+ break;}
+case 31:
+#line 352 "getdate.y"
+{
+ PC.rel_seconds = -PC.rel_seconds;
+ PC.rel_minutes = -PC.rel_minutes;
+ PC.rel_hour = -PC.rel_hour;
+ PC.rel_day = -PC.rel_day;
+ PC.rel_month = -PC.rel_month;
+ PC.rel_year = -PC.rel_year;
+ ;
+ break;}
+case 33:
+#line 365 "getdate.y"
+{ PC.rel_year += yyvsp[-1].textintval.value * yyvsp[0].intval; ;
+ break;}
+case 34:
+#line 367 "getdate.y"
+{ PC.rel_year += yyvsp[-1].textintval.value * yyvsp[0].intval; ;
+ break;}
+case 35:
+#line 369 "getdate.y"
+{ PC.rel_year += yyvsp[0].intval; ;
+ break;}
+case 36:
+#line 371 "getdate.y"
+{ PC.rel_month += yyvsp[-1].textintval.value * yyvsp[0].intval; ;
+ break;}
+case 37:
+#line 373 "getdate.y"
+{ PC.rel_month += yyvsp[-1].textintval.value * yyvsp[0].intval; ;
+ break;}
+case 38:
+#line 375 "getdate.y"
+{ PC.rel_month += yyvsp[0].intval; ;
+ break;}
+case 39:
+#line 377 "getdate.y"
+{ PC.rel_day += yyvsp[-1].textintval.value * yyvsp[0].intval; ;
+ break;}
+case 40:
+#line 379 "getdate.y"
+{ PC.rel_day += yyvsp[-1].textintval.value * yyvsp[0].intval; ;
+ break;}
+case 41:
+#line 381 "getdate.y"
+{ PC.rel_day += yyvsp[0].intval ;
+ break;}
+case 42:
+#line 383 "getdate.y"
+{ PC.rel_hour += yyvsp[-1].textintval.value * yyvsp[0].intval; ;
+ break;}
+case 43:
+#line 385 "getdate.y"
+{ PC.rel_hour += yyvsp[-1].textintval.value * yyvsp[0].intval; ;
+ break;}
+case 44:
+#line 387 "getdate.y"
+{ PC.rel_hour += yyvsp[0].intval ;
+ break;}
+case 45:
+#line 389 "getdate.y"
+{ PC.rel_minutes += yyvsp[-1].textintval.value * yyvsp[0].intval; ;
+ break;}
+case 46:
+#line 391 "getdate.y"
+{ PC.rel_minutes += yyvsp[-1].textintval.value * yyvsp[0].intval; ;
+ break;}
+case 47:
+#line 393 "getdate.y"
+{ PC.rel_minutes += yyvsp[0].intval ;
+ break;}
+case 48:
+#line 395 "getdate.y"
+{ PC.rel_seconds += yyvsp[-1].textintval.value * yyvsp[0].intval; ;
+ break;}
+case 49:
+#line 397 "getdate.y"
+{ PC.rel_seconds += yyvsp[-1].textintval.value * yyvsp[0].intval; ;
+ break;}
+case 50:
+#line 399 "getdate.y"
+{ PC.rel_seconds += yyvsp[0].intval; ;
+ break;}
+case 51:
+#line 404 "getdate.y"
+{
+ if (PC.dates_seen
+ && ! PC.rels_seen && (PC.times_seen || 2 < yyvsp[0].textintval.digits))
+ PC.year = yyvsp[0].textintval;
+ else
+ {
+ if (4 < yyvsp[0].textintval.digits)
+ {
+ PC.dates_seen++;
+ PC.day = yyvsp[0].textintval.value % 100;
+ PC.month = (yyvsp[0].textintval.value / 100) % 100;
+ PC.year.value = yyvsp[0].textintval.value / 10000;
+ PC.year.digits = yyvsp[0].textintval.digits - 4;
+ }
+ else
+ {
+ PC.times_seen++;
+ if (yyvsp[0].textintval.digits <= 2)
+ {
+ PC.hour = yyvsp[0].textintval.value;
+ PC.minutes = 0;
+ }
+ else
+ {
+ PC.hour = yyvsp[0].textintval.value / 100;
+ PC.minutes = yyvsp[0].textintval.value % 100;
+ }
+ PC.seconds = 0;
+ PC.meridian = MER24;
+ }
+ }
+ ;
+ break;}
+case 52:
+#line 440 "getdate.y"
+{ yyval.intval = MER24; ;
+ break;}
+case 53:
+#line 442 "getdate.y"
+{ yyval.intval = yyvsp[0].intval; ;
+ break;}
+}
+
+#line 606 "/opt/reb/share/bison/bison.simple"
+
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+#if YYLSP_NEEDED
+ yylsp -= yylen;
+#endif
+
+#if YYDEBUG
+ if (yydebug)
+ {
+ short *ssp1 = yyss - 1;
+ fprintf (stderr, "state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ *++yyvsp = yyval;
+#if YYLSP_NEEDED
+ *++yylsp = yyloc;
+#endif
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+ if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTBASE];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (yyn > YYFLAG && yyn < YYLAST)
+ {
+ int size = 0;
+ char *msg;
+ int x, count;
+
+ count = 0;
+ /* Start X at -yyn if nec to avoid negative indexes in yycheck. */
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (int) (sizeof (yytname) / sizeof (char *)); x++)
+ if (yycheck[x + yyn] == x)
+ size += strlen (yytname[x]) + 15, count++;
+ size += strlen ("parse error, unexpected `") + 1;
+ size += strlen (yytname[YYTRANSLATE (yychar)]);
+ msg = (char *) malloc (size);
+ if (msg != 0)
+ {
+ strcpy (msg, "parse error, unexpected `");
+ strcat (msg, yytname[YYTRANSLATE (yychar)]);
+ strcat (msg, "'");
+
+ if (count < 5)
+ {
+ count = 0;
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (int) (sizeof (yytname) / sizeof (char *)); x++)
+ if (yycheck[x + yyn] == x)
+ {
+ strcat (msg, count == 0 ? ", expecting `" : " or `");
+ strcat (msg, yytname[x]);
+ strcat (msg, "'");
+ count++;
+ }
+ }
+ yyerror (msg);
+ free (msg);
+ }
+ else
+ yyerror ("parse error; also virtual memory exceeded");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror ("parse error");
+ }
+ goto yyerrlab1;
+
+
+/*--------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action |
+`--------------------------------------------------*/
+yyerrlab1:
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ /* return failure if at end of input */
+ if (yychar == YYEOF)
+ YYABORT;
+ YYDPRINTF ((stderr, "Discarding token %d (%s).\n",
+ yychar, yytname[yychar1]));
+ yychar = YYEMPTY;
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+
+ yyerrstatus = 3; /* Each real token shifted decrements this */
+
+ goto yyerrhandle;
+
+
+/*-------------------------------------------------------------------.
+| yyerrdefault -- current state does not do anything special for the |
+| error token. |
+`-------------------------------------------------------------------*/
+yyerrdefault:
+#if 0
+ /* This is wrong; only states that explicitly want error tokens
+ should shift them. */
+
+ /* If its default is to accept any token, ok. Otherwise pop it. */
+ yyn = yydefact[yystate];
+ if (yyn)
+ goto yydefault;
+#endif
+
+
+/*---------------------------------------------------------------.
+| yyerrpop -- pop the current state because it cannot handle the |
+| error token |
+`---------------------------------------------------------------*/
+yyerrpop:
+ if (yyssp == yyss)
+ YYABORT;
+ yyvsp--;
+ yystate = *--yyssp;
+#if YYLSP_NEEDED
+ yylsp--;
+#endif
+
+#if YYDEBUG
+ if (yydebug)
+ {
+ short *ssp1 = yyss - 1;
+ fprintf (stderr, "Error: state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+/*--------------.
+| yyerrhandle. |
+`--------------*/
+yyerrhandle:
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yyerrdefault;
+
+ yyn += YYTERROR;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+ goto yyerrdefault;
+
+ yyn = yytable[yyn];
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrpop;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrpop;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ YYDPRINTF ((stderr, "Shifting error token, "));
+
+ *++yyvsp = yylval;
+#if YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#if YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 0;
+
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#if YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 1;
+}
+#line 445 "getdate.y"
+
+
+/* Include this file down here because bison inserts code above which
+ may define-away `const'. We want the prototype for get_date to have
+ the same signature as the function definition. */
+#include "getdate.h"
+
+#ifndef gmtime
+struct tm *gmtime ();
+#endif
+#ifndef localtime
+struct tm *localtime ();
+#endif
+#ifndef mktime
+time_t mktime ();
+#endif
+
+static table const meridian_table[] =
+{
+ { "AM", tMERIDIAN, MERam },
+ { "A.M.", tMERIDIAN, MERam },
+ { "PM", tMERIDIAN, MERpm },
+ { "P.M.", tMERIDIAN, MERpm },
+ { 0, 0, 0 }
+};
+
+static table const dst_table[] =
+{
+ { "DST", tDST, 0 }
+};
+
+static table const month_and_day_table[] =
+{
+ { "JANUARY", tMONTH, 1 },
+ { "FEBRUARY", tMONTH, 2 },
+ { "MARCH", tMONTH, 3 },
+ { "APRIL", tMONTH, 4 },
+ { "MAY", tMONTH, 5 },
+ { "JUNE", tMONTH, 6 },
+ { "JULY", tMONTH, 7 },
+ { "AUGUST", tMONTH, 8 },
+ { "SEPTEMBER",tMONTH, 9 },
+ { "SEPT", tMONTH, 9 },
+ { "OCTOBER", tMONTH, 10 },
+ { "NOVEMBER", tMONTH, 11 },
+ { "DECEMBER", tMONTH, 12 },
+ { "SUNDAY", tDAY, 0 },
+ { "MONDAY", tDAY, 1 },
+ { "TUESDAY", tDAY, 2 },
+ { "TUES", tDAY, 2 },
+ { "WEDNESDAY",tDAY, 3 },
+ { "WEDNES", tDAY, 3 },
+ { "THURSDAY", tDAY, 4 },
+ { "THUR", tDAY, 4 },
+ { "THURS", tDAY, 4 },
+ { "FRIDAY", tDAY, 5 },
+ { "SATURDAY", tDAY, 6 },
+ { 0, 0, 0 }
+};
+
+static table const time_units_table[] =
+{
+ { "YEAR", tYEAR_UNIT, 1 },
+ { "MONTH", tMONTH_UNIT, 1 },
+ { "FORTNIGHT",tDAY_UNIT, 14 },
+ { "WEEK", tDAY_UNIT, 7 },
+ { "DAY", tDAY_UNIT, 1 },
+ { "HOUR", tHOUR_UNIT, 1 },
+ { "MINUTE", tMINUTE_UNIT, 1 },
+ { "MIN", tMINUTE_UNIT, 1 },
+ { "SECOND", tSEC_UNIT, 1 },
+ { "SEC", tSEC_UNIT, 1 },
+ { 0, 0, 0 }
+};
+
+/* Assorted relative-time words. */
+static table const relative_time_table[] =
+{
+ { "TOMORROW", tMINUTE_UNIT, 24 * 60 },
+ { "YESTERDAY",tMINUTE_UNIT, - (24 * 60) },
+ { "TODAY", tMINUTE_UNIT, 0 },
+ { "NOW", tMINUTE_UNIT, 0 },
+ { "LAST", tUNUMBER, -1 },
+ { "THIS", tUNUMBER, 0 },
+ { "NEXT", tUNUMBER, 1 },
+ { "FIRST", tUNUMBER, 1 },
+/*{ "SECOND", tUNUMBER, 2 }, */
+ { "THIRD", tUNUMBER, 3 },
+ { "FOURTH", tUNUMBER, 4 },
+ { "FIFTH", tUNUMBER, 5 },
+ { "SIXTH", tUNUMBER, 6 },
+ { "SEVENTH", tUNUMBER, 7 },
+ { "EIGHTH", tUNUMBER, 8 },
+ { "NINTH", tUNUMBER, 9 },
+ { "TENTH", tUNUMBER, 10 },
+ { "ELEVENTH", tUNUMBER, 11 },
+ { "TWELFTH", tUNUMBER, 12 },
+ { "AGO", tAGO, 1 },
+ { 0, 0, 0 }
+};
+
+/* The time zone table. This table is necessarily incomplete, as time
+ zone abbreviations are ambiguous; e.g. Australians interpret "EST"
+ as Eastern time in Australia, not as US Eastern Standard Time.
+ You cannot rely on getdate to handle arbitrary time zone
+ abbreviations; use numeric abbreviations like `-0500' instead. */
+static table const time_zone_table[] =
+{
+ { "GMT", tZONE, HOUR ( 0) }, /* Greenwich Mean */
+ { "UT", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */
+ { "UTC", tZONE, HOUR ( 0) },
+ { "WET", tZONE, HOUR ( 0) }, /* Western European */
+ { "WEST", tDAYZONE, HOUR ( 0) }, /* Western European Summer */
+ { "BST", tDAYZONE, HOUR ( 0) }, /* British Summer */
+ { "ART", tZONE, -HOUR ( 3) }, /* Argentina */
+ { "BRT", tZONE, -HOUR ( 3) }, /* Brazil */
+ { "BRST", tDAYZONE, -HOUR ( 3) }, /* Brazil Summer */
+ { "NST", tZONE, -(HOUR ( 3) + 30) }, /* Newfoundland Standard */
+ { "NDT", tDAYZONE,-(HOUR ( 3) + 30) }, /* Newfoundland Daylight */
+ { "AST", tZONE, -HOUR ( 4) }, /* Atlantic Standard */
+ { "ADT", tDAYZONE, -HOUR ( 4) }, /* Atlantic Daylight */
+ { "CLT", tZONE, -HOUR ( 4) }, /* Chile */
+ { "CLST", tDAYZONE, -HOUR ( 4) }, /* Chile Summer */
+ { "EST", tZONE, -HOUR ( 5) }, /* Eastern Standard */
+ { "EDT", tDAYZONE, -HOUR ( 5) }, /* Eastern Daylight */
+ { "CST", tZONE, -HOUR ( 6) }, /* Central Standard */
+ { "CDT", tDAYZONE, -HOUR ( 6) }, /* Central Daylight */
+ { "MST", tZONE, -HOUR ( 7) }, /* Mountain Standard */
+ { "MDT", tDAYZONE, -HOUR ( 7) }, /* Mountain Daylight */
+ { "PST", tZONE, -HOUR ( 8) }, /* Pacific Standard */
+ { "PDT", tDAYZONE, -HOUR ( 8) }, /* Pacific Daylight */
+ { "AKST", tZONE, -HOUR ( 9) }, /* Alaska Standard */
+ { "AKDT", tDAYZONE, -HOUR ( 9) }, /* Alaska Daylight */
+ { "HST", tZONE, -HOUR (10) }, /* Hawaii Standard */
+ { "HAST", tZONE, -HOUR (10) }, /* Hawaii-Aleutian Standard */
+ { "HADT", tDAYZONE, -HOUR (10) }, /* Hawaii-Aleutian Daylight */
+ { "SST", tZONE, -HOUR (12) }, /* Samoa Standard */
+ { "WAT", tZONE, HOUR ( 1) }, /* West Africa */
+ { "CET", tZONE, HOUR ( 1) }, /* Central European */
+ { "CEST", tDAYZONE, HOUR ( 1) }, /* Central European Summer */
+ { "MET", tZONE, HOUR ( 1) }, /* Middle European */
+ { "MEZ", tZONE, HOUR ( 1) }, /* Middle European */
+ { "MEST", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */
+ { "MESZ", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */
+ { "EET", tZONE, HOUR ( 2) }, /* Eastern European */
+ { "EEST", tDAYZONE, HOUR ( 2) }, /* Eastern European Summer */
+ { "CAT", tZONE, HOUR ( 2) }, /* Central Africa */
+ { "SAST", tZONE, HOUR ( 2) }, /* South Africa Standard */
+ { "EAT", tZONE, HOUR ( 3) }, /* East Africa */
+ { "MSK", tZONE, HOUR ( 3) }, /* Moscow */
+ { "MSD", tDAYZONE, HOUR ( 3) }, /* Moscow Daylight */
+ { "IST", tZONE, (HOUR ( 5) + 30) }, /* India Standard */
+ { "SGT", tZONE, HOUR ( 8) }, /* Singapore */
+ { "KST", tZONE, HOUR ( 9) }, /* Korea Standard */
+ { "JST", tZONE, HOUR ( 9) }, /* Japan Standard */
+ { "GST", tZONE, HOUR (10) }, /* Guam Standard */
+ { "NZST", tZONE, HOUR (12) }, /* New Zealand Standard */
+ { "NZDT", tDAYZONE, HOUR (12) }, /* New Zealand Daylight */
+ { 0, 0, 0 }
+};
+
+/* Military time zone table. */
+static table const military_table[] =
+{
+ { "A", tZONE, -HOUR ( 1) },
+ { "B", tZONE, -HOUR ( 2) },
+ { "C", tZONE, -HOUR ( 3) },
+ { "D", tZONE, -HOUR ( 4) },
+ { "E", tZONE, -HOUR ( 5) },
+ { "F", tZONE, -HOUR ( 6) },
+ { "G", tZONE, -HOUR ( 7) },
+ { "H", tZONE, -HOUR ( 8) },
+ { "I", tZONE, -HOUR ( 9) },
+ { "K", tZONE, -HOUR (10) },
+ { "L", tZONE, -HOUR (11) },
+ { "M", tZONE, -HOUR (12) },
+ { "N", tZONE, HOUR ( 1) },
+ { "O", tZONE, HOUR ( 2) },
+ { "P", tZONE, HOUR ( 3) },
+ { "Q", tZONE, HOUR ( 4) },
+ { "R", tZONE, HOUR ( 5) },
+ { "S", tZONE, HOUR ( 6) },
+ { "T", tZONE, HOUR ( 7) },
+ { "U", tZONE, HOUR ( 8) },
+ { "V", tZONE, HOUR ( 9) },
+ { "W", tZONE, HOUR (10) },
+ { "X", tZONE, HOUR (11) },
+ { "Y", tZONE, HOUR (12) },
+ { "Z", tZONE, HOUR ( 0) },
+ { 0, 0, 0 }
+};
+
+
+
+static int
+to_hour (int hours, int meridian)
+{
+ switch (meridian)
+ {
+ case MER24:
+ return 0 <= hours && hours < 24 ? hours : -1;
+ case MERam:
+ return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1;
+ case MERpm:
+ return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1;
+ default:
+ abort ();
+ }
+ /* NOTREACHED */
+}
+
+static int
+to_year (textint textyear)
+{
+ int year = textyear.value;
+
+ if (year < 0)
+ year = -year;
+
+ /* XPG4 suggests that years 00-68 map to 2000-2068, and
+ years 69-99 map to 1969-1999. */
+ if (textyear.digits == 2)
+ year += year < 69 ? 2000 : 1900;
+
+ return year;
+}
+
+static table const *
+lookup_zone (parser_control const *pc, char const *name)
+{
+ table const *tp;
+
+ /* Try local zone abbreviations first; they're more likely to be right. */
+ for (tp = pc->local_time_zone_table; tp->name; tp++)
+ if (strcmp (name, tp->name) == 0)
+ return tp;
+
+ for (tp = time_zone_table; tp->name; tp++)
+ if (strcmp (name, tp->name) == 0)
+ return tp;
+
+ return 0;
+}
+
+#if ! HAVE_TM_GMTOFF
+/* Yield the difference between *A and *B,
+ measured in seconds, ignoring leap seconds.
+ The body of this function is taken directly from the GNU C Library;
+ see src/strftime.c. */
+static int
+tm_diff (struct tm const *a, struct tm const *b)
+{
+ /* Compute intervening leap days correctly even if year is negative.
+ Take care to avoid int overflow in leap day calculations,
+ but it's OK to assume that A and B are close to each other. */
+ int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
+ int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = a100 >> 2;
+ int b400 = b100 >> 2;
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+ int years = a->tm_year - b->tm_year;
+ int days = (365 * years + intervening_leap_days
+ + (a->tm_yday - b->tm_yday));
+ return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+ + (a->tm_min - b->tm_min))
+ + (a->tm_sec - b->tm_sec));
+}
+#endif /* ! HAVE_TM_GMTOFF */
+
+static table const *
+lookup_word (parser_control const *pc, char *word)
+{
+ char *p;
+ char *q;
+ size_t wordlen;
+ table const *tp;
+ int i;
+ int abbrev;
+
+ /* Make it uppercase. */
+ for (p = word; *p; p++)
+ if (ISLOWER ((unsigned char) *p))
+ *p = toupper ((unsigned char) *p);
+
+ for (tp = meridian_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* See if we have an abbreviation for a month. */
+ wordlen = strlen (word);
+ abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.');
+
+ for (tp = month_and_day_table; tp->name; tp++)
+ if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0)
+ return tp;
+
+ if ((tp = lookup_zone (pc, word)))
+ return tp;
+
+ if (strcmp (word, dst_table[0].name) == 0)
+ return dst_table;
+
+ for (tp = time_units_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* Strip off any plural and try the units table again. */
+ if (word[wordlen - 1] == 'S')
+ {
+ word[wordlen - 1] = '\0';
+ for (tp = time_units_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+ word[wordlen - 1] = 'S'; /* For "this" in relative_time_table. */
+ }
+
+ for (tp = relative_time_table; tp->name; tp++)
+ if (strcmp (word, tp->name) == 0)
+ return tp;
+
+ /* Military time zones. */
+ if (wordlen == 1)
+ for (tp = military_table; tp->name; tp++)
+ if (word[0] == tp->name[0])
+ return tp;
+
+ /* Drop out any periods and try the time zone table again. */
+ for (i = 0, p = q = word; (*p = *q); q++)
+ if (*q == '.')
+ i = 1;
+ else
+ p++;
+ if (i && (tp = lookup_zone (pc, word)))
+ return tp;
+
+ return 0;
+}
+
+static int
+yylex (YYSTYPE *lvalp, parser_control *pc)
+{
+ unsigned char c;
+ int count;
+
+ for (;;)
+ {
+ while (c = *pc->input, ISSPACE (c))
+ pc->input++;
+
+ if (ISDIGIT (c) || c == '-' || c == '+')
+ {
+ char const *p;
+ int sign;
+ int value;
+ if (c == '-' || c == '+')
+ {
+ sign = c == '-' ? -1 : 1;
+ c = *++pc->input;
+ if (! ISDIGIT (c))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ p = pc->input;
+ value = 0;
+ do
+ {
+ value = 10 * value + c - '0';
+ c = *++p;
+ }
+ while (ISDIGIT (c));
+ lvalp->textintval.value = sign < 0 ? -value : value;
+ lvalp->textintval.digits = p - pc->input;
+ pc->input = p;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+
+ if (ISALPHA (c))
+ {
+ char buff[20];
+ char *p = buff;
+ table const *tp;
+
+ do
+ {
+ if (p < buff + sizeof buff - 1)
+ *p++ = c;
+ c = *++pc->input;
+ }
+ while (ISALPHA (c) || c == '.');
+
+ *p = '\0';
+ tp = lookup_word (pc, buff);
+ if (! tp)
+ return '?';
+ lvalp->intval = tp->value;
+ return tp->type;
+ }
+
+ if (c != '(')
+ return *pc->input++;
+ count = 0;
+ do
+ {
+ c = *pc->input++;
+ if (c == '\0')
+ return c;
+ if (c == '(')
+ count++;
+ else if (c == ')')
+ count--;
+ }
+ while (count > 0);
+ }
+}
+
+/* Do nothing if the parser reports an error. */
+static int
+yyerror (char *s ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+/* Parse a date/time string P. Return the corresponding time_t value,
+ or (time_t) -1 if there is an error. P can be an incomplete or
+ relative time specification; if so, use *NOW as the basis for the
+ returned time. */
+time_t
+get_date (const char *p, const time_t *now)
+{
+ time_t Start = now ? *now : time (0);
+ struct tm *tmp = localtime (&Start);
+ struct tm tm;
+ struct tm tm0;
+ parser_control pc;
+
+ if (! tmp)
+ return -1;
+
+ pc.input = p;
+ pc.year.value = tmp->tm_year + TM_YEAR_BASE;
+ pc.year.digits = 4;
+ pc.month = tmp->tm_mon + 1;
+ pc.day = tmp->tm_mday;
+ pc.hour = tmp->tm_hour;
+ pc.minutes = tmp->tm_min;
+ pc.seconds = tmp->tm_sec;
+ tm.tm_isdst = tmp->tm_isdst;
+
+ pc.meridian = MER24;
+ pc.rel_seconds = 0;
+ pc.rel_minutes = 0;
+ pc.rel_hour = 0;
+ pc.rel_day = 0;
+ pc.rel_month = 0;
+ pc.rel_year = 0;
+ pc.dates_seen = 0;
+ pc.days_seen = 0;
+ pc.rels_seen = 0;
+ pc.times_seen = 0;
+ pc.local_zones_seen = 0;
+ pc.zones_seen = 0;
+
+#if HAVE_TM_ZONE
+ pc.local_time_zone_table[0].name = tmp->tm_zone;
+ pc.local_time_zone_table[0].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[0].value = tmp->tm_isdst;
+ pc.local_time_zone_table[1].name = 0;
+
+ /* Probe the names used in the next three calendar quarters, looking
+ for a tm_isdst different from the one we already have. */
+ {
+ int quarter;
+ for (quarter = 1; quarter <= 3; quarter++)
+ {
+ time_t probe = Start + quarter * (90 * 24 * 60 * 60);
+ struct tm *probe_tm = localtime (&probe);
+ if (probe_tm && probe_tm->tm_zone
+ && probe_tm->tm_isdst != pc.local_time_zone_table[0].value)
+ {
+ {
+ pc.local_time_zone_table[1].name = probe_tm->tm_zone;
+ pc.local_time_zone_table[1].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[1].value = probe_tm->tm_isdst;
+ pc.local_time_zone_table[2].name = 0;
+ }
+ break;
+ }
+ }
+ }
+#else
+#if HAVE_TZNAME
+ {
+# ifndef tzname
+ extern char *tzname[];
+# endif
+ int i;
+ for (i = 0; i < 2; i++)
+ {
+ pc.local_time_zone_table[i].name = tzname[i];
+ pc.local_time_zone_table[i].type = tLOCAL_ZONE;
+ pc.local_time_zone_table[i].value = i;
+ }
+ pc.local_time_zone_table[i].name = 0;
+ }
+#else
+ pc.local_time_zone_table[0].name = 0;
+#endif
+#endif
+
+ if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name
+ && ! strcmp (pc.local_time_zone_table[0].name,
+ pc.local_time_zone_table[1].name))
+ {
+ /* This locale uses the same abbrevation for standard and
+ daylight times. So if we see that abbreviation, we don't
+ know whether it's daylight time. */
+ pc.local_time_zone_table[0].value = -1;
+ pc.local_time_zone_table[1].name = 0;
+ }
+
+ if (yyparse (&pc) != 0
+ || 1 < pc.times_seen || 1 < pc.dates_seen || 1 < pc.days_seen
+ || 1 < (pc.local_zones_seen + pc.zones_seen)
+ || (pc.local_zones_seen && 1 < pc.local_isdst))
+ return -1;
+
+ tm.tm_year = to_year (pc.year) - TM_YEAR_BASE + pc.rel_year;
+ tm.tm_mon = pc.month - 1 + pc.rel_month;
+ tm.tm_mday = pc.day + pc.rel_day;
+ if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen))
+ {
+ tm.tm_hour = to_hour (pc.hour, pc.meridian);
+ if (tm.tm_hour < 0)
+ return -1;
+ tm.tm_min = pc.minutes;
+ tm.tm_sec = pc.seconds;
+ }
+ else
+ {
+ tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+ }
+
+ /* Let mktime deduce tm_isdst if we have an absolute time stamp,
+ or if the relative time stamp mentions days, months, or years. */
+ if (pc.dates_seen | pc.days_seen | pc.times_seen | pc.rel_day
+ | pc.rel_month | pc.rel_year)
+ tm.tm_isdst = -1;
+
+ /* But if the input explicitly specifies local time with or without
+ DST, give mktime that information. */
+ if (pc.local_zones_seen)
+ tm.tm_isdst = pc.local_isdst;
+
+ tm0 = tm;
+
+ Start = mktime (&tm);
+
+ if (Start == (time_t) -1)
+ {
+
+ /* Guard against falsely reporting errors near the time_t boundaries
+ when parsing times in other time zones. For example, if the min
+ time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
+ of UTC, then the min localtime value is 1970-01-01 08:00:00; if
+ we apply mktime to 1970-01-01 00:00:00 we will get an error, so
+ we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
+ zone by 24 hours to compensate. This algorithm assumes that
+ there is no DST transition within a day of the time_t boundaries. */
+ if (pc.zones_seen)
+ {
+ tm = tm0;
+ if (tm.tm_year <= EPOCH_YEAR - TM_YEAR_BASE)
+ {
+ tm.tm_mday++;
+ pc.time_zone += 24 * 60;
+ }
+ else
+ {
+ tm.tm_mday--;
+ pc.time_zone -= 24 * 60;
+ }
+ Start = mktime (&tm);
+ }
+
+ if (Start == (time_t) -1)
+ return Start;
+ }
+
+ if (pc.days_seen && ! pc.dates_seen)
+ {
+ tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7
+ + 7 * (pc.day_ordinal - (0 < pc.day_ordinal)));
+ tm.tm_isdst = -1;
+ Start = mktime (&tm);
+ if (Start == (time_t) -1)
+ return Start;
+ }
+
+ if (pc.zones_seen)
+ {
+ int delta = pc.time_zone * 60;
+#ifdef HAVE_TM_GMTOFF
+ delta -= tm.tm_gmtoff;
+#else
+ struct tm *gmt = gmtime (&Start);
+ if (! gmt)
+ return -1;
+ delta -= tm_diff (&tm, gmt);
+#endif
+ if ((Start < Start - delta) != (delta < 0))
+ return -1; /* time_t overflow */
+ Start -= delta;
+ }
+
+ /* Add relative hours, minutes, and seconds. Ignore leap seconds;
+ i.e. "+ 10 minutes" means 600 seconds, even if one of them is a
+ leap second. Typically this is not what the user wants, but it's
+ too hard to do it the other way, because the time zone indicator
+ must be applied before relative times, and if mktime is applied
+ again the time zone will be lost. */
+ {
+ time_t t0 = Start;
+ long d1 = 60 * 60 * (long) pc.rel_hour;
+ time_t t1 = t0 + d1;
+ long d2 = 60 * (long) pc.rel_minutes;
+ time_t t2 = t1 + d2;
+ int d3 = pc.rel_seconds;
+ time_t t3 = t2 + d3;
+ if ((d1 / (60 * 60) ^ pc.rel_hour)
+ | (d2 / 60 ^ pc.rel_minutes)
+ | ((t0 + d1 < t0) ^ (d1 < 0))
+ | ((t1 + d2 < t1) ^ (d2 < 0))
+ | ((t2 + d3 < t2) ^ (d3 < 0)))
+ return -1;
+ Start = t3;
+ }
+
+ return Start;
+}
+
+#if TEST
+
+#include <stdio.h>
+
+int
+main (int ac, char **av)
+{
+ char buff[BUFSIZ];
+ time_t d;
+
+ printf ("Enter date, or blank line to exit.\n\t> ");
+ fflush (stdout);
+
+ buff[BUFSIZ - 1] = 0;
+ while (fgets (buff, BUFSIZ - 1, stdin) && buff[0])
+ {
+ d = get_date (buff, 0);
+ if (d == (time_t) -1)
+ printf ("Bad format - couldn't convert.\n");
+ else
+ printf ("%s", ctime (&d));
+ printf ("\t> ");
+ fflush (stdout);
+ }
+ return 0;
+}
+#endif /* defined TEST */
diff --git a/contrib/tar/lib/getdate.h b/contrib/tar/lib/getdate.h
new file mode 100644
index 0000000..674c474
--- /dev/null
+++ b/contrib/tar/lib/getdate.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+#endif
+
+#ifdef vms
+# include <types.h>
+# include <time.h>
+#else
+# include <sys/types.h>
+# if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+#endif /* defined (vms) */
+
+time_t get_date PARAMS ((const char *p, const time_t *now));
diff --git a/contrib/tar/lib/getline.c b/contrib/tar/lib/getline.c
new file mode 100644
index 0000000..657ff32
--- /dev/null
+++ b/contrib/tar/lib/getline.c
@@ -0,0 +1,57 @@
+/* getline.c -- Replacement for GNU C library function getline
+
+Copyright (C) 1993, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* The `getdelim' function is only declared if the following symbol
+ is defined. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#if defined __GNU_LIBRARY__ && HAVE_GETDELIM
+
+int
+getline (char **lineptr, size_t *n, FILE *stream)
+{
+ return getdelim (lineptr, n, '\n', stream);
+}
+
+#else /* ! have getdelim */
+
+# include "getstr.h"
+
+int
+getline (char **lineptr, size_t *n, FILE *stream)
+{
+ return getstr (lineptr, n, stream, '\n', 0, 0);
+}
+
+int
+getdelim (char **lineptr, size_t *n, int delimiter, FILE *stream)
+{
+ return getstr (lineptr, n, stream, delimiter, 0, 0);
+}
+#endif
diff --git a/contrib/tar/lib/getline.h b/contrib/tar/lib/getline.h
new file mode 100644
index 0000000..991184c
--- /dev/null
+++ b/contrib/tar/lib/getline.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 1995, 1997, 1999 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef GETLINE_H_
+# define GETLINE_H_ 1
+
+# include <stdio.h>
+
+# ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+# endif
+
+# if __GLIBC__ < 2
+int
+getline PARAMS ((char **_lineptr, size_t *_n, FILE *_stream));
+
+int
+getdelim PARAMS ((char **_lineptr, size_t *_n, int _delimiter, FILE *_stream));
+# endif
+
+#endif /* not GETLINE_H_ */
diff --git a/contrib/tar/lib/getopt.c b/contrib/tar/lib/getopt.c
new file mode 100644
index 0000000..eeaf378
--- /dev/null
+++ b/contrib/tar/lib/getopt.c
@@ -0,0 +1,1067 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to drepper@gnu.org
+ before changing it!
+ Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+# ifndef const
+# define const
+# endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+# define ELIDE_CODE
+# endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+# include <stdlib.h>
+# include <unistd.h>
+#endif /* GNU C library. */
+
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+# include <string.h>
+# endif
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages. */
+# if defined HAVE_LIBINTL_H || defined _LIBC
+# include <libintl.h>
+# ifndef _
+# define _(msgid) gettext (msgid)
+# endif
+# else
+# define _(msgid) (msgid)
+# endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+ causes problems with re-calling getopt as programs generally don't
+ know that. */
+
+int __getopt_initialized;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return -1 with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+# include <string.h>
+# define my_index strchr
+#else
+
+# if HAVE_STRING_H
+# include <string.h>
+# else
+# include <strings.h>
+# endif
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+# endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+ indicating ARGV elements that should not be considered arguments. */
+
+#ifdef USE_NONOPTION_FLAGS
+/* Defined in getopt_init.c */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+#endif
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+ is valid for the getopt call we must make sure that the ARGV passed
+ to getopt is that one passed to the process. */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+ /* XXX This is no good solution. We should rather copy the args so
+ that we can compare them later. But we must not use malloc(3). */
+ original_argc = argc;
+ original_argv = argv;
+}
+# ifdef text_set_element
+text_set_element (__libc_subinit, store_args_and_env);
+# endif /* text_set_element */
+
+# ifdef USE_NONOPTION_FLAGS
+# define SWAP_FLAGS(ch1, ch2) \
+ if (nonoption_flags_len > 0) \
+ { \
+ char __tmp = __getopt_nonoption_flags[ch1]; \
+ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
+ __getopt_nonoption_flags[ch2] = __tmp; \
+ }
+# else
+# define SWAP_FLAGS(ch1, ch2)
+# endif
+#else /* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif /* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+#if defined __STDC__ && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+ /* First make sure the handling of the `__getopt_nonoption_flags'
+ string can work normally. Our top argument must be in the range
+ of the string. */
+ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+ {
+ /* We must extend the array. The user plays games with us and
+ presents new arguments. */
+ char *new_str = malloc (top + 1);
+ if (new_str == NULL)
+ nonoption_flags_len = nonoption_flags_max_len = 0;
+ else
+ {
+ memset (__mempcpy (new_str, __getopt_nonoption_flags,
+ nonoption_flags_max_len),
+ '\0', top + 1 - nonoption_flags_max_len);
+ nonoption_flags_max_len = top + 1;
+ __getopt_nonoption_flags = new_str;
+ }
+ }
+#endif
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ SWAP_FLAGS (bottom + i, middle + i);
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+#if defined __STDC__ && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = optind;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+ if (posixly_correct == NULL
+ && argc == original_argc && argv == original_argv)
+ {
+ if (nonoption_flags_max_len == 0)
+ {
+ if (__getopt_nonoption_flags == NULL
+ || __getopt_nonoption_flags[0] == '\0')
+ nonoption_flags_max_len = -1;
+ else
+ {
+ const char *orig_str = __getopt_nonoption_flags;
+ int len = nonoption_flags_max_len = strlen (orig_str);
+ if (nonoption_flags_max_len < argc)
+ nonoption_flags_max_len = argc;
+ __getopt_nonoption_flags =
+ (char *) malloc (nonoption_flags_max_len);
+ if (__getopt_nonoption_flags == NULL)
+ nonoption_flags_max_len = -1;
+ else
+ memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+ '\0', nonoption_flags_max_len - len);
+ }
+ }
+ nonoption_flags_len = nonoption_flags_max_len;
+ }
+ else
+ nonoption_flags_len = 0;
+#endif
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns -1.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ int print_errors = opterr;
+ if (optstring[0] == ':')
+ print_errors = 0;
+
+ if (argc < 1)
+ return -1;
+
+ optarg = NULL;
+
+ if (optind == 0 || !__getopt_initialized)
+ {
+ if (optind == 0)
+ optind = 1; /* Don't scan ARGV[0], the program name. */
+ optstring = _getopt_initialize (argc, argv, optstring);
+ __getopt_initialized = 1;
+ }
+
+ /* Test whether ARGV[optind] points to a non-option argument.
+ Either it does not have option syntax, or there is an environment flag
+ from the shell indicating it is not an option. The later information
+ is only used when the used in the GNU libc. */
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
+ || (optind < nonoption_flags_len \
+ && __getopt_nonoption_flags[optind] == '1'))
+#else
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+ moved back by the user (who may also have changed the arguments). */
+ if (last_nonopt > optind)
+ last_nonopt = optind;
+ if (first_nonopt > optind)
+ first_nonopt = optind;
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc && NONOPTION_P)
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return -1;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if (NONOPTION_P)
+ {
+ if (ordering == REQUIRE_ORDER)
+ return -1;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = -1;
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar)
+ == (unsigned int) strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else if (long_only
+ || pfound->has_arg != p->has_arg
+ || pfound->flag != p->flag
+ || pfound->val != p->val)
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (print_errors)
+ fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (print_errors)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ _("%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ _("%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+
+ nextchar += strlen (nextchar);
+
+ optopt = pfound->val;
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (print_errors)
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ optopt = pfound->val;
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (print_errors)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (print_errors)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: illegal option -- %c\n"),
+ argv[0], c);
+ else
+ fprintf (stderr, _("%s: invalid option -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ return '?';
+ }
+ /* Convenience. Treat POSIX -W foo same as long option --foo */
+ if (temp[0] == 'W' && temp[1] == ';')
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = 0;
+ int option_index;
+
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (print_errors)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ return c;
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+
+ /* optarg is now the argument, see if it's in the
+ table of longopts. */
+
+ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+ if (ambig && !exact)
+ {
+ if (print_errors)
+ fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (print_errors)
+ fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (print_errors)
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ nextchar = NULL;
+ return 'W'; /* Let the application handle it. */
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (print_errors)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr,
+ _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/contrib/tar/lib/getopt.h b/contrib/tar/lib/getopt.h
new file mode 100644
index 0000000..18e1026
--- /dev/null
+++ b/contrib/tar/lib/getopt.h
@@ -0,0 +1,179 @@
+/* Declarations for getopt.
+ Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _GETOPT_H
+
+#ifndef __need_getopt
+# define _GETOPT_H 1
+#endif
+
+/* If __GNU_LIBRARY__ is not already defined, either we are being used
+ standalone, or this is the first header included in the source file.
+ If we are being used with glibc, we need to include <features.h>, but
+ that does not exist if we are standalone. So: if __GNU_LIBRARY__ is
+ not defined, include <ctype.h>, which will pull in <features.h> for us
+ if it's from glibc. (Why ctype.h? It's guaranteed to exist and it
+ doesn't flood the namespace with stuff the way some other headers do.) */
+#if !defined __GNU_LIBRARY__
+# include <ctype.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+#ifndef __need_getopt
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+# if (defined __STDC__ && __STDC__) || defined __cplusplus
+ const char *name;
+# else
+ char *name;
+# endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+# define no_argument 0
+# define required_argument 1
+# define optional_argument 2
+#endif /* need getopt */
+
+
+/* Get definitions and prototypes for functions to process the
+ arguments in ARGV (ARGC of them, minus the program name) for
+ options given in OPTS.
+
+ Return the option character from OPTS just read. Return -1 when
+ there are no more options. For unrecognized options, or options
+ missing arguments, `optopt' is set to the option letter, and '?' is
+ returned.
+
+ The OPTS string is a list of characters which are recognized option
+ letters, optionally followed by colons, specifying that that letter
+ takes an argument, to be placed in `optarg'.
+
+ If a letter in OPTS is followed by two colons, its argument is
+ optional. This behavior is specific to the GNU `getopt'.
+
+ The argument `--' causes premature termination of argument
+ scanning, explicitly telling `getopt' that there are no more
+ options.
+
+ If OPTS begins with `--', then non-option arguments are treated as
+ arguments to the option '\0'. This behavior is specific to the GNU
+ `getopt'. */
+
+#if (defined __STDC__ && __STDC__) || defined __cplusplus
+# ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int __argc, char *const *__argv, const char *__shortopts);
+# else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+# endif /* __GNU_LIBRARY__ */
+
+# ifndef __need_getopt
+extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts,
+ const struct option *__longopts, int *__longind);
+extern int getopt_long_only (int __argc, char *const *__argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int __argc, char *const *__argv,
+ const char *__shortopts,
+ const struct option *__longopts, int *__longind,
+ int __long_only);
+# endif
+#else /* not __STDC__ */
+extern int getopt ();
+# ifndef __need_getopt
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+# endif
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Make sure we later can get all the definitions and declarations. */
+#undef __need_getopt
+
+#endif /* getopt.h */
diff --git a/contrib/tar/lib/getopt1.c b/contrib/tar/lib/getopt1.c
new file mode 100644
index 0000000..62c55cf
--- /dev/null
+++ b/contrib/tar/lib/getopt1.c
@@ -0,0 +1,187 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "getopt.h"
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/contrib/tar/lib/getstr.c b/contrib/tar/lib/getstr.c
new file mode 100644
index 0000000..66e44fe
--- /dev/null
+++ b/contrib/tar/lib/getstr.c
@@ -0,0 +1,114 @@
+/* getstr.c -- core function for GNU C library getline replacement function
+
+ Copyright (C) 1993, 1996-2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <assert.h>
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+char *malloc (), *realloc ();
+#endif
+
+/* Always add at least this many bytes when extending the buffer. */
+#define MIN_CHUNK 64
+
+/* Read up to (and including) a delimiter DELIM1 from STREAM into *LINEPTR
+ + OFFSET (and NUL-terminate it). If DELIM2 is non-zero, then read up
+ and including the first occurrence of DELIM1 or DELIM2. *LINEPTR is
+ a pointer returned from malloc (or NULL), pointing to *N characters of
+ space. It is realloc'd as necessary. Return the number of characters
+ read (not including the NUL terminator), or -1 on error or EOF. */
+
+int
+getstr (char **lineptr, size_t *n, FILE *stream, int delim1, int delim2,
+ size_t offset)
+{
+ int nchars_avail; /* Allocated but unused chars in *LINEPTR. */
+ char *read_pos; /* Where we're reading into *LINEPTR. */
+ int ret;
+
+ if (!lineptr || !n || !stream)
+ return -1;
+
+ if (!*lineptr)
+ {
+ *n = MIN_CHUNK;
+ *lineptr = malloc (*n);
+ if (!*lineptr)
+ return -1;
+ }
+
+ nchars_avail = *n - offset;
+ read_pos = *lineptr + offset;
+
+ for (;;)
+ {
+ register int c = getc (stream);
+
+ /* We always want at least one char left in the buffer, since we
+ always (unless we get an error while reading the first char)
+ NUL-terminate the line buffer. */
+
+ assert(*n - nchars_avail == read_pos - *lineptr);
+ if (nchars_avail < 2)
+ {
+ if (*n > MIN_CHUNK)
+ *n *= 2;
+ else
+ *n += MIN_CHUNK;
+
+ nchars_avail = *n + *lineptr - read_pos;
+ *lineptr = realloc (*lineptr, *n);
+ if (!*lineptr)
+ return -1;
+ read_pos = *n - nchars_avail + *lineptr;
+ assert(*n - nchars_avail == read_pos - *lineptr);
+ }
+
+ if (c == EOF || ferror (stream))
+ {
+ /* Return partial line, if any. */
+ if (read_pos == *lineptr)
+ return -1;
+ else
+ break;
+ }
+
+ *read_pos++ = c;
+ nchars_avail--;
+
+ if (c == delim1 || (delim2 && c == delim2))
+ /* Return the line. */
+ break;
+ }
+
+ /* Done - NUL terminate and return the number of chars read. */
+ *read_pos = '\0';
+
+ ret = read_pos - (*lineptr + offset);
+ return ret;
+}
diff --git a/contrib/tar/lib/getstr.h b/contrib/tar/lib/getstr.h
new file mode 100644
index 0000000..367bf4e
--- /dev/null
+++ b/contrib/tar/lib/getstr.h
@@ -0,0 +1,19 @@
+#ifndef GETSTR_H_
+# define GETSTR_H_ 1
+
+# include <stdio.h>
+
+# ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+# endif
+
+int
+getstr PARAMS ((char **lineptr, size_t *n, FILE *stream,
+ int delim1, int delim2,
+ size_t offset));
+
+#endif
diff --git a/contrib/tar/lib/hash.c b/contrib/tar/lib/hash.c
new file mode 100644
index 0000000..a94a549
--- /dev/null
+++ b/contrib/tar/lib/hash.c
@@ -0,0 +1,1009 @@
+/* hash - hashing table processing.
+ Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ Written by Jim Meyering, 1992.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* A generic hash table package. */
+
+/* Define USE_OBSTACK to 1 if you want the allocator to use obstacks instead
+ of malloc. If you change USE_OBSTACK, you have to recompile! */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+typedef enum {false = 0, true = 1} bool;
+#endif
+#include <stdio.h>
+#include <assert.h>
+
+#ifndef HAVE_DECL_FREE
+"this configure-time declaration test was not run"
+#endif
+#if !HAVE_DECL_FREE
+void free ();
+#endif
+
+#ifndef HAVE_DECL_MALLOC
+"this configure-time declaration test was not run"
+#endif
+#if !HAVE_DECL_MALLOC
+char *malloc ();
+#endif
+
+#if USE_OBSTACK
+# include "obstack.h"
+# ifndef obstack_chunk_alloc
+# define obstack_chunk_alloc malloc
+# endif
+# ifndef obstack_chunk_free
+# define obstack_chunk_free free
+# endif
+#endif
+
+#include "hash.h"
+
+/* A hash table contains many internal entries, each holding a pointer to
+ some user provided data (also called a user entry). An entry indistinctly
+ refers to both the internal entry and its associated user entry. A user
+ entry contents may be hashed by a randomization function (the hashing
+ function, or just `hasher' for short) into a number (or `slot') between 0
+ and the current table size. At each slot position in the hash table,
+ starts a linked chain of entries for which the user data all hash to this
+ slot. A bucket is the collection of all entries hashing to the same slot.
+
+ A good `hasher' function will distribute entries rather evenly in buckets.
+ In the ideal case, the length of each bucket is roughly the number of
+ entries divided by the table size. Finding the slot for a data is usually
+ done in constant time by the `hasher', and the later finding of a precise
+ entry is linear in time with the size of the bucket. Consequently, a
+ larger hash table size (that is, a larger number of buckets) is prone to
+ yielding shorter chains, *given* the `hasher' function behaves properly.
+
+ Long buckets slow down the lookup algorithm. One might use big hash table
+ sizes in hope to reduce the average length of buckets, but this might
+ become inordinate, as unused slots in the hash table take some space. The
+ best bet is to make sure you are using a good `hasher' function (beware
+ that those are not that easy to write! :-), and to use a table size
+ larger than the actual number of entries. */
+
+/* If an insertion makes the ratio of nonempty buckets to table size larger
+ than the growth threshold (a number between 0.0 and 1.0), then increase
+ the table size by multiplying by the growth factor (a number greater than
+ 1.0). The growth threshold defaults to 0.8, and the growth factor
+ defaults to 1.414, meaning that the table will have doubled its size
+ every second time 80% of the buckets get used. */
+#define DEFAULT_GROWTH_THRESHOLD 0.8
+#define DEFAULT_GROWTH_FACTOR 1.414
+
+/* If a deletion empties a bucket and causes the ratio of used buckets to
+ table size to become smaller than the shrink threshold (a number between
+ 0.0 and 1.0), then shrink the table by multiplying by the shrink factor (a
+ number greater than the shrink threshold but smaller than 1.0). The shrink
+ threshold and factor default to 0.0 and 1.0, meaning that the table never
+ shrinks. */
+#define DEFAULT_SHRINK_THRESHOLD 0.0
+#define DEFAULT_SHRINK_FACTOR 1.0
+
+/* Use this to initialize or reset a TUNING structure to
+ some sensible values. */
+static const Hash_tuning default_tuning =
+ {
+ DEFAULT_SHRINK_THRESHOLD,
+ DEFAULT_SHRINK_FACTOR,
+ DEFAULT_GROWTH_THRESHOLD,
+ DEFAULT_GROWTH_FACTOR,
+ false
+ };
+
+/* Information and lookup. */
+
+/* The following few functions provide information about the overall hash
+ table organization: the number of entries, number of buckets and maximum
+ length of buckets. */
+
+/* Return the number of buckets in the hash table. The table size, the total
+ number of buckets (used plus unused), or the maximum number of slots, are
+ the same quantity. */
+
+unsigned
+hash_get_n_buckets (const Hash_table *table)
+{
+ return table->n_buckets;
+}
+
+/* Return the number of slots in use (non-empty buckets). */
+
+unsigned
+hash_get_n_buckets_used (const Hash_table *table)
+{
+ return table->n_buckets_used;
+}
+
+/* Return the number of active entries. */
+
+unsigned
+hash_get_n_entries (const Hash_table *table)
+{
+ return table->n_entries;
+}
+
+/* Return the length of the longest chain (bucket). */
+
+unsigned
+hash_get_max_bucket_length (const Hash_table *table)
+{
+ struct hash_entry *bucket;
+ unsigned max_bucket_length = 0;
+
+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+ {
+ if (bucket->data)
+ {
+ struct hash_entry *cursor = bucket;
+ unsigned bucket_length = 1;
+
+ while (cursor = cursor->next, cursor)
+ bucket_length++;
+
+ if (bucket_length > max_bucket_length)
+ max_bucket_length = bucket_length;
+ }
+ }
+
+ return max_bucket_length;
+}
+
+/* Do a mild validation of a hash table, by traversing it and checking two
+ statistics. */
+
+bool
+hash_table_ok (const Hash_table *table)
+{
+ struct hash_entry *bucket;
+ unsigned n_buckets_used = 0;
+ unsigned n_entries = 0;
+
+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+ {
+ if (bucket->data)
+ {
+ struct hash_entry *cursor = bucket;
+
+ /* Count bucket head. */
+ n_buckets_used++;
+ n_entries++;
+
+ /* Count bucket overflow. */
+ while (cursor = cursor->next, cursor)
+ n_entries++;
+ }
+ }
+
+ if (n_buckets_used == table->n_buckets_used && n_entries == table->n_entries)
+ return true;
+
+ return false;
+}
+
+void
+hash_print_statistics (const Hash_table *table, FILE *stream)
+{
+ unsigned n_entries = hash_get_n_entries (table);
+ unsigned n_buckets = hash_get_n_buckets (table);
+ unsigned n_buckets_used = hash_get_n_buckets_used (table);
+ unsigned max_bucket_length = hash_get_max_bucket_length (table);
+
+ fprintf (stream, "# entries: %u\n", n_entries);
+ fprintf (stream, "# buckets: %u\n", n_buckets);
+ fprintf (stream, "# buckets used: %u (%.2f%%)\n", n_buckets_used,
+ (100.0 * n_buckets_used) / n_buckets);
+ fprintf (stream, "max bucket length: %u\n", max_bucket_length);
+}
+
+/* If ENTRY matches an entry already in the hash table, return the
+ entry from the table. Otherwise, return NULL. */
+
+void *
+hash_lookup (const Hash_table *table, const void *entry)
+{
+ struct hash_entry *bucket
+ = table->bucket + table->hasher (entry, table->n_buckets);
+ struct hash_entry *cursor;
+
+ assert (bucket < table->bucket_limit);
+
+ if (bucket->data == NULL)
+ return NULL;
+
+ for (cursor = bucket; cursor; cursor = cursor->next)
+ if (table->comparator (entry, cursor->data))
+ return cursor->data;
+
+ return NULL;
+}
+
+/* Walking. */
+
+/* The functions in this page traverse the hash table and process the
+ contained entries. For the traversal to work properly, the hash table
+ should not be resized nor modified while any particular entry is being
+ processed. In particular, entries should not be added or removed. */
+
+/* Return the first data in the table, or NULL if the table is empty. */
+
+void *
+hash_get_first (const Hash_table *table)
+{
+ struct hash_entry *bucket;
+
+ if (table->n_entries == 0)
+ return NULL;
+
+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+ if (bucket->data)
+ return bucket->data;
+
+ assert (0);
+ return NULL;
+}
+
+/* Return the user data for the entry following ENTRY, where ENTRY has been
+ returned by a previous call to either `hash_get_first' or `hash_get_next'.
+ Return NULL if there are no more entries. */
+
+void *
+hash_get_next (const Hash_table *table, const void *entry)
+{
+ struct hash_entry *bucket
+ = table->bucket + table->hasher (entry, table->n_buckets);
+ struct hash_entry *cursor;
+
+ assert (bucket < table->bucket_limit);
+
+ /* Find next entry in the same bucket. */
+ for (cursor = bucket; cursor; cursor = cursor->next)
+ if (cursor->data == entry && cursor->next)
+ return cursor->next->data;
+
+ /* Find first entry in any subsequent bucket. */
+ while (++bucket < table->bucket_limit)
+ if (bucket->data)
+ return bucket->data;
+
+ /* None found. */
+ return NULL;
+}
+
+/* Fill BUFFER with pointers to active user entries in the hash table, then
+ return the number of pointers copied. Do not copy more than BUFFER_SIZE
+ pointers. */
+
+unsigned
+hash_get_entries (const Hash_table *table, void **buffer,
+ unsigned buffer_size)
+{
+ unsigned counter = 0;
+ struct hash_entry *bucket;
+ struct hash_entry *cursor;
+
+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+ {
+ if (bucket->data)
+ {
+ for (cursor = bucket; cursor; cursor = cursor->next)
+ {
+ if (counter >= buffer_size)
+ return counter;
+ buffer[counter++] = cursor->data;
+ }
+ }
+ }
+
+ return counter;
+}
+
+/* Call a PROCESSOR function for each entry of a hash table, and return the
+ number of entries for which the processor function returned success. A
+ pointer to some PROCESSOR_DATA which will be made available to each call to
+ the processor function. The PROCESSOR accepts two arguments: the first is
+ the user entry being walked into, the second is the value of PROCESSOR_DATA
+ as received. The walking continue for as long as the PROCESSOR function
+ returns nonzero. When it returns zero, the walking is interrupted. */
+
+unsigned
+hash_do_for_each (const Hash_table *table, Hash_processor processor,
+ void *processor_data)
+{
+ unsigned counter = 0;
+ struct hash_entry *bucket;
+ struct hash_entry *cursor;
+
+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+ {
+ if (bucket->data)
+ {
+ for (cursor = bucket; cursor; cursor = cursor->next)
+ {
+ if (!(*processor) (cursor->data, processor_data))
+ return counter;
+ counter++;
+ }
+ }
+ }
+
+ return counter;
+}
+
+/* Allocation and clean-up. */
+
+/* Return a hash index for a NUL-terminated STRING between 0 and N_BUCKETS-1.
+ This is a convenience routine for constructing other hashing functions. */
+
+#if USE_DIFF_HASH
+
+/* About hashings, Paul Eggert writes to me (FP), on 1994-01-01: "Please see
+ B. J. McKenzie, R. Harries & T. Bell, Selecting a hashing algorithm,
+ Software--practice & experience 20, 2 (Feb 1990), 209-224. Good hash
+ algorithms tend to be domain-specific, so what's good for [diffutils'] io.c
+ may not be good for your application." */
+
+unsigned
+hash_string (const char *string, unsigned n_buckets)
+{
+# ifndef CHAR_BIT
+# define CHAR_BIT 8
+# endif
+# define ROTATE_LEFT(Value, Shift) \
+ ((Value) << (Shift) | (Value) >> ((sizeof (unsigned) * CHAR_BIT) - (Shift)))
+# define HASH_ONE_CHAR(Value, Byte) \
+ ((Byte) + ROTATE_LEFT (Value, 7))
+
+ unsigned value = 0;
+
+ for (; *string; string++)
+ value = HASH_ONE_CHAR (value, *(const unsigned char *) string);
+ return value % n_buckets;
+
+# undef ROTATE_LEFT
+# undef HASH_ONE_CHAR
+}
+
+#else /* not USE_DIFF_HASH */
+
+/* This one comes from `recode', and performs a bit better than the above as
+ per a few experiments. It is inspired from a hashing routine found in the
+ very old Cyber `snoop', itself written in typical Greg Mansfield style.
+ (By the way, what happened to this excellent man? Is he still alive?) */
+
+unsigned
+hash_string (const char *string, unsigned n_buckets)
+{
+ unsigned value = 0;
+
+ while (*string)
+ value = ((value * 31 + (int) *(const unsigned char *) string++)
+ % n_buckets);
+ return value;
+}
+
+#endif /* not USE_DIFF_HASH */
+
+/* Return true if CANDIDATE is a prime number. CANDIDATE should be an odd
+ number at least equal to 11. */
+
+static bool
+is_prime (unsigned long candidate)
+{
+ unsigned long divisor = 3;
+ unsigned long square = divisor * divisor;
+
+ while (square < candidate && (candidate % divisor))
+ {
+ divisor++;
+ square += 4 * divisor;
+ divisor++;
+ }
+
+ return (candidate % divisor ? true : false);
+}
+
+/* Round a given CANDIDATE number up to the nearest prime, and return that
+ prime. Primes lower than 10 are merely skipped. */
+
+static unsigned long
+next_prime (unsigned long candidate)
+{
+ /* Skip small primes. */
+ if (candidate < 10)
+ candidate = 10;
+
+ /* Make it definitely odd. */
+ candidate |= 1;
+
+ while (!is_prime (candidate))
+ candidate += 2;
+
+ return candidate;
+}
+
+void
+hash_reset_tuning (Hash_tuning *tuning)
+{
+ *tuning = default_tuning;
+}
+
+/* For the given hash TABLE, check the user supplied tuning structure for
+ reasonable values, and return true if there is no gross error with it.
+ Otherwise, definitively reset the TUNING field to some acceptable default
+ in the hash table (that is, the user loses the right of further modifying
+ tuning arguments), and return false. */
+
+static bool
+check_tuning (Hash_table *table)
+{
+ const Hash_tuning *tuning = table->tuning;
+
+ if (tuning->growth_threshold > 0.0
+ && tuning->growth_threshold < 1.0
+ && tuning->growth_factor > 1.0
+ && tuning->shrink_threshold >= 0.0
+ && tuning->shrink_threshold < 1.0
+ && tuning->shrink_factor > tuning->shrink_threshold
+ && tuning->shrink_factor <= 1.0
+ && tuning->shrink_threshold < tuning->growth_threshold)
+ return true;
+
+ table->tuning = &default_tuning;
+ return false;
+}
+
+/* Allocate and return a new hash table, or NULL upon failure. The initial
+ number of buckets is automatically selected so as to _guarantee_ that you
+ may insert at least CANDIDATE different user entries before any growth of
+ the hash table size occurs. So, if have a reasonably tight a-priori upper
+ bound on the number of entries you intend to insert in the hash table, you
+ may save some table memory and insertion time, by specifying it here. If
+ the IS_N_BUCKETS field of the TUNING structure is true, the CANDIDATE
+ argument has its meaning changed to the wanted number of buckets.
+
+ TUNING points to a structure of user-supplied values, in case some fine
+ tuning is wanted over the default behavior of the hasher. If TUNING is
+ NULL, the default tuning parameters are used instead.
+
+ The user-supplied HASHER function should be provided. It accepts two
+ arguments ENTRY and TABLE_SIZE. It computes, by hashing ENTRY contents, a
+ slot number for that entry which should be in the range 0..TABLE_SIZE-1.
+ This slot number is then returned.
+
+ The user-supplied COMPARATOR function should be provided. It accepts two
+ arguments pointing to user data, it then returns true for a pair of entries
+ that compare equal, or false otherwise. This function is internally called
+ on entries which are already known to hash to the same bucket index.
+
+ The user-supplied DATA_FREER function, when not NULL, may be later called
+ with the user data as an argument, just before the entry containing the
+ data gets freed. This happens from within `hash_free' or `hash_clear'.
+ You should specify this function only if you want these functions to free
+ all of your `data' data. This is typically the case when your data is
+ simply an auxiliary struct that you have malloc'd to aggregate several
+ values. */
+
+Hash_table *
+hash_initialize (unsigned candidate, const Hash_tuning *tuning,
+ Hash_hasher hasher, Hash_comparator comparator,
+ Hash_data_freer data_freer)
+{
+ Hash_table *table;
+ struct hash_entry *bucket;
+
+ if (hasher == NULL || comparator == NULL)
+ return NULL;
+
+ table = (Hash_table *) malloc (sizeof (Hash_table));
+ if (table == NULL)
+ return NULL;
+
+ if (!tuning)
+ tuning = &default_tuning;
+ table->tuning = tuning;
+ if (!check_tuning (table))
+ {
+ /* Fail if the tuning options are invalid. This is the only occasion
+ when the user gets some feedback about it. Once the table is created,
+ if the user provides invalid tuning options, we silently revert to
+ using the defaults, and ignore further request to change the tuning
+ options. */
+ free (table);
+ return NULL;
+ }
+
+ table->n_buckets
+ = next_prime (tuning->is_n_buckets ? candidate
+ : (unsigned) (candidate / tuning->growth_threshold));
+
+ table->bucket = (struct hash_entry *)
+ malloc (table->n_buckets * sizeof (struct hash_entry));
+ if (table->bucket == NULL)
+ {
+ free (table);
+ return NULL;
+ }
+ table->bucket_limit = table->bucket + table->n_buckets;
+
+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+ {
+ bucket->data = NULL;
+ bucket->next = NULL;
+ }
+ table->n_buckets_used = 0;
+ table->n_entries = 0;
+
+ table->hasher = hasher;
+ table->comparator = comparator;
+ table->data_freer = data_freer;
+
+ table->free_entry_list = NULL;
+#if USE_OBSTACK
+ obstack_init (&table->entry_stack);
+#endif
+ return table;
+}
+
+/* Make all buckets empty, placing any chained entries on the free list.
+ Apply the user-specified function data_freer (if any) to the datas of any
+ affected entries. */
+
+void
+hash_clear (Hash_table *table)
+{
+ struct hash_entry *bucket;
+ struct hash_entry *cursor;
+
+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+ {
+ if (bucket->data)
+ {
+ /* Free the bucket overflow. */
+ for (cursor = bucket->next; cursor; cursor = cursor->next)
+ {
+ if (table->data_freer)
+ (*table->data_freer) (cursor->data);
+ cursor->data = NULL;
+
+ /* Relinking is done one entry at a time, as it is to be expected
+ that overflows are either rare or short. */
+ cursor->next = table->free_entry_list;
+ table->free_entry_list = cursor;
+ }
+
+ /* Free the bucket head. */
+ if (table->data_freer)
+ (*table->data_freer) (bucket->data);
+ bucket->data = NULL;
+ bucket->next = NULL;
+ }
+ }
+
+ table->n_buckets_used = 0;
+ table->n_entries = 0;
+}
+
+/* Reclaim all storage associated with a hash table. If a data_freer
+ function has been supplied by the user when the hash table was created,
+ this function applies it to the data of each entry before freeing that
+ entry. */
+
+void
+hash_free (Hash_table *table)
+{
+ struct hash_entry *bucket;
+ struct hash_entry *cursor;
+ struct hash_entry *next;
+
+ /* Call the user data_freer function. */
+ if (table->data_freer && table->n_entries)
+ {
+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+ {
+ if (bucket->data)
+ {
+ for (cursor = bucket; cursor; cursor = cursor->next)
+ {
+ (*table->data_freer) (cursor->data);
+ }
+ }
+ }
+ }
+
+#if USE_OBSTACK
+
+ obstack_free (&table->entry_stack, NULL);
+
+#else
+
+ /* Free all bucket overflowed entries. */
+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+ {
+ for (cursor = bucket->next; cursor; cursor = next)
+ {
+ next = cursor->next;
+ free (cursor);
+ }
+ }
+
+ /* Also reclaim the internal list of previously freed entries. */
+ for (cursor = table->free_entry_list; cursor; cursor = next)
+ {
+ next = cursor->next;
+ free (cursor);
+ }
+
+#endif
+
+ /* Free the remainder of the hash table structure. */
+ free (table->bucket);
+ free (table);
+}
+
+/* Insertion and deletion. */
+
+/* Get a new hash entry for a bucket overflow, possibly by reclying a
+ previously freed one. If this is not possible, allocate a new one. */
+
+static struct hash_entry *
+allocate_entry (Hash_table *table)
+{
+ struct hash_entry *new;
+
+ if (table->free_entry_list)
+ {
+ new = table->free_entry_list;
+ table->free_entry_list = new->next;
+ }
+ else
+ {
+#if USE_OBSTACK
+ new = (struct hash_entry *)
+ obstack_alloc (&table->entry_stack, sizeof (struct hash_entry));
+#else
+ new = (struct hash_entry *) malloc (sizeof (struct hash_entry));
+#endif
+ }
+
+ return new;
+}
+
+/* Free a hash entry which was part of some bucket overflow,
+ saving it for later recycling. */
+
+static void
+free_entry (Hash_table *table, struct hash_entry *entry)
+{
+ entry->data = NULL;
+ entry->next = table->free_entry_list;
+ table->free_entry_list = entry;
+}
+
+/* This private function is used to help with insertion and deletion. When
+ ENTRY matches an entry in the table, return a pointer to the corresponding
+ user data and set *BUCKET_HEAD to the head of the selected bucket.
+ Otherwise, return NULL. When DELETE is true and ENTRY matches an entry in
+ the table, unlink the matching entry. */
+
+static void *
+hash_find_entry (Hash_table *table, const void *entry,
+ struct hash_entry **bucket_head, bool delete)
+{
+ struct hash_entry *bucket
+ = table->bucket + table->hasher (entry, table->n_buckets);
+ struct hash_entry *cursor;
+
+ assert (bucket < table->bucket_limit);
+ *bucket_head = bucket;
+
+ /* Test for empty bucket. */
+ if (bucket->data == NULL)
+ return NULL;
+
+ /* See if the entry is the first in the bucket. */
+ if ((*table->comparator) (entry, bucket->data))
+ {
+ void *data = bucket->data;
+
+ if (delete)
+ {
+ if (bucket->next)
+ {
+ struct hash_entry *next = bucket->next;
+
+ /* Bump the first overflow entry into the bucket head, then save
+ the previous first overflow entry for later recycling. */
+ *bucket = *next;
+ free_entry (table, next);
+ }
+ else
+ {
+ bucket->data = NULL;
+ }
+ }
+
+ return data;
+ }
+
+ /* Scan the bucket overflow. */
+ for (cursor = bucket; cursor->next; cursor = cursor->next)
+ {
+ if ((*table->comparator) (entry, cursor->next->data))
+ {
+ void *data = cursor->next->data;
+
+ if (delete)
+ {
+ struct hash_entry *next = cursor->next;
+
+ /* Unlink the entry to delete, then save the freed entry for later
+ recycling. */
+ cursor->next = next->next;
+ free_entry (table, next);
+ }
+
+ return data;
+ }
+ }
+
+ /* No entry found. */
+ return NULL;
+}
+
+/* For an already existing hash table, change the number of buckets through
+ specifying CANDIDATE. The contents of the hash table are preserved. The
+ new number of buckets is automatically selected so as to _guarantee_ that
+ the table may receive at least CANDIDATE different user entries, including
+ those already in the table, before any other growth of the hash table size
+ occurs. If TUNING->IS_N_BUCKETS is true, then CANDIDATE specifies the
+ exact number of buckets desired. */
+
+bool
+hash_rehash (Hash_table *table, unsigned candidate)
+{
+ Hash_table *new_table;
+ struct hash_entry *bucket;
+ struct hash_entry *cursor;
+ struct hash_entry *next;
+
+ new_table = hash_initialize (candidate, table->tuning, table->hasher,
+ table->comparator, table->data_freer);
+ if (new_table == NULL)
+ return false;
+
+ /* Merely reuse the extra old space into the new table. */
+#if USE_OBSTACK
+ obstack_free (&new_table->entry_stack, NULL);
+ new_table->entry_stack = table->entry_stack;
+#endif
+ new_table->free_entry_list = table->free_entry_list;
+
+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+ if (bucket->data)
+ for (cursor = bucket; cursor; cursor = next)
+ {
+ void *data = cursor->data;
+ struct hash_entry *new_bucket
+ = (new_table->bucket
+ + new_table->hasher (data, new_table->n_buckets));
+
+ assert (new_bucket < new_table->bucket_limit);
+ next = cursor->next;
+
+ if (new_bucket->data)
+ {
+ if (cursor == bucket)
+ {
+ /* Allocate or recycle an entry, when moving from a bucket
+ header into a bucket overflow. */
+ struct hash_entry *new_entry = allocate_entry (new_table);
+
+ if (new_entry == NULL)
+ return false;
+
+ new_entry->data = data;
+ new_entry->next = new_bucket->next;
+ new_bucket->next = new_entry;
+ }
+ else
+ {
+ /* Merely relink an existing entry, when moving from a
+ bucket overflow into a bucket overflow. */
+ cursor->next = new_bucket->next;
+ new_bucket->next = cursor;
+ }
+ }
+ else
+ {
+ /* Free an existing entry, when moving from a bucket
+ overflow into a bucket header. Also take care of the
+ simple case of moving from a bucket header into a bucket
+ header. */
+ new_bucket->data = data;
+ new_table->n_buckets_used++;
+ if (cursor != bucket)
+ free_entry (new_table, cursor);
+ }
+ }
+
+ free (table->bucket);
+ table->bucket = new_table->bucket;
+ table->bucket_limit = new_table->bucket_limit;
+ table->n_buckets = new_table->n_buckets;
+ table->n_buckets_used = new_table->n_buckets_used;
+ table->free_entry_list = new_table->free_entry_list;
+ /* table->n_entries already holds its value. */
+#if USE_OBSTACK
+ table->entry_stack = new_table->entry_stack;
+#endif
+ free (new_table);
+
+ return true;
+}
+
+/* If ENTRY matches an entry already in the hash table, return the pointer
+ to the entry from the table. Otherwise, insert ENTRY and return ENTRY.
+ Return NULL if the storage required for insertion cannot be allocated. */
+
+void *
+hash_insert (Hash_table *table, const void *entry)
+{
+ void *data;
+ struct hash_entry *bucket;
+
+ assert (entry); /* cannot insert a NULL entry */
+
+ /* If there's a matching entry already in the table, return that. */
+ if ((data = hash_find_entry (table, entry, &bucket, false)) != NULL)
+ return data;
+
+ /* ENTRY is not matched, it should be inserted. */
+
+ if (bucket->data)
+ {
+ struct hash_entry *new_entry = allocate_entry (table);
+
+ if (new_entry == NULL)
+ return NULL;
+
+ /* Add ENTRY in the overflow of the bucket. */
+
+ new_entry->data = (void *) entry;
+ new_entry->next = bucket->next;
+ bucket->next = new_entry;
+ table->n_entries++;
+ return (void *) entry;
+ }
+
+ /* Add ENTRY right in the bucket head. */
+
+ bucket->data = (void *) entry;
+ table->n_entries++;
+ table->n_buckets_used++;
+
+ /* If the growth threshold of the buckets in use has been reached, increase
+ the table size and rehash. There's no point in checking the number of
+ entries: if the hashing function is ill-conditioned, rehashing is not
+ likely to improve it. */
+
+ if (table->n_buckets_used
+ > table->tuning->growth_threshold * table->n_buckets)
+ {
+ /* Check more fully, before starting real work. If tuning arguments
+ became invalid, the second check will rely on proper defaults. */
+ check_tuning (table);
+ if (table->n_buckets_used
+ > table->tuning->growth_threshold * table->n_buckets)
+ {
+ const Hash_tuning *tuning = table->tuning;
+ unsigned candidate
+ = (unsigned) (tuning->is_n_buckets
+ ? (table->n_buckets * tuning->growth_factor)
+ : (table->n_buckets * tuning->growth_factor
+ * tuning->growth_threshold));
+
+ /* If the rehash fails, arrange to return NULL. */
+ if (!hash_rehash (table, candidate))
+ entry = NULL;
+ }
+ }
+
+ return (void *) entry;
+}
+
+/* If ENTRY is already in the table, remove it and return the just-deleted
+ data (the user may want to deallocate its storage). If ENTRY is not in the
+ table, don't modify the table and return NULL. */
+
+void *
+hash_delete (Hash_table *table, const void *entry)
+{
+ void *data;
+ struct hash_entry *bucket;
+
+ data = hash_find_entry (table, entry, &bucket, true);
+ if (!data)
+ return NULL;
+
+ table->n_entries--;
+ if (!bucket->data)
+ {
+ table->n_buckets_used--;
+
+ /* If the shrink threshold of the buckets in use has been reached,
+ rehash into a smaller table. */
+
+ if (table->n_buckets_used
+ < table->tuning->shrink_threshold * table->n_buckets)
+ {
+ /* Check more fully, before starting real work. If tuning arguments
+ became invalid, the second check will rely on proper defaults. */
+ check_tuning (table);
+ if (table->n_buckets_used
+ < table->tuning->shrink_threshold * table->n_buckets)
+ {
+ const Hash_tuning *tuning = table->tuning;
+ unsigned candidate
+ = (unsigned) (tuning->is_n_buckets
+ ? table->n_buckets * tuning->shrink_factor
+ : (table->n_buckets * tuning->shrink_factor
+ * tuning->growth_threshold));
+
+ hash_rehash (table, candidate);
+ }
+ }
+ }
+
+ return data;
+}
+
+/* Testing. */
+
+#if TESTING
+
+void
+hash_print (const Hash_table *table)
+{
+ struct hash_entry *bucket;
+
+ for (bucket = table->bucket; bucket < table->bucket_limit; bucket++)
+ {
+ struct hash_entry *cursor;
+
+ if (bucket)
+ printf ("%d:\n", slot);
+
+ for (cursor = bucket; cursor; cursor = cursor->next)
+ {
+ char *s = (char *) cursor->data;
+ /* FIXME */
+ printf (" %s\n", s);
+ }
+ }
+}
+
+#endif /* TESTING */
diff --git a/contrib/tar/lib/hash.h b/contrib/tar/lib/hash.h
new file mode 100644
index 0000000..27b6fa4
--- /dev/null
+++ b/contrib/tar/lib/hash.h
@@ -0,0 +1,120 @@
+/* hash - hashing table processing.
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ Written by Jim Meyering <meyering@ascend.com>, 1998.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* A generic hash table package. */
+
+/* Make sure USE_OBSTACK is defined to 1 if you want the allocator to use
+ obstacks instead of malloc, and recompile `hash.c' with same setting. */
+
+#ifndef PARAMS
+# if PROTOTYPES || __STDC__
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+#endif
+
+typedef unsigned (*Hash_hasher) PARAMS ((const void *, unsigned));
+typedef bool (*Hash_comparator) PARAMS ((const void *, const void *));
+typedef void (*Hash_data_freer) PARAMS ((void *));
+typedef bool (*Hash_processor) PARAMS ((void *, void *));
+
+struct hash_entry
+ {
+ void *data;
+ struct hash_entry *next;
+ };
+
+struct hash_tuning
+ {
+ /* This structure is mainly used for `hash_initialize', see the block
+ documentation of `hash_reset_tuning' for more complete comments. */
+
+ float shrink_threshold; /* ratio of used buckets to trigger a shrink */
+ float shrink_factor; /* ratio of new smaller size to original size */
+ float growth_threshold; /* ratio of used buckets to trigger a growth */
+ float growth_factor; /* ratio of new bigger size to original size */
+ bool is_n_buckets; /* if CANDIDATE really means table size */
+ };
+
+typedef struct hash_tuning Hash_tuning;
+
+struct hash_table
+ {
+ /* The array of buckets starts at BUCKET and extends to BUCKET_LIMIT-1,
+ for a possibility of N_BUCKETS. Among those, N_BUCKETS_USED buckets
+ are not empty, there are N_ENTRIES active entries in the table. */
+ struct hash_entry *bucket;
+ struct hash_entry *bucket_limit;
+ unsigned n_buckets;
+ unsigned n_buckets_used;
+ unsigned n_entries;
+
+ /* Tuning arguments, kept in a physicaly separate structure. */
+ const Hash_tuning *tuning;
+
+ /* Three functions are given to `hash_initialize', see the documentation
+ block for this function. In a word, HASHER randomizes a user entry
+ into a number up from 0 up to some maximum minus 1; COMPARATOR returns
+ true if two user entries compare equally; and DATA_FREER is the cleanup
+ function for a user entry. */
+ Hash_hasher hasher;
+ Hash_comparator comparator;
+ Hash_data_freer data_freer;
+
+ /* A linked list of freed struct hash_entry structs. */
+ struct hash_entry *free_entry_list;
+
+#if USE_OBSTACK
+ /* Whenever obstacks are used, it is possible to allocate all overflowed
+ entries into a single stack, so they all can be freed in a single
+ operation. It is not clear if the speedup is worth the trouble. */
+ struct obstack entry_stack;
+#endif
+ };
+
+typedef struct hash_table Hash_table;
+
+/* Information and lookup. */
+unsigned hash_get_n_buckets PARAMS ((const Hash_table *));
+unsigned hash_get_n_buckets_used PARAMS ((const Hash_table *));
+unsigned hash_get_n_entries PARAMS ((const Hash_table *));
+unsigned hash_get_max_bucket_length PARAMS ((const Hash_table *));
+bool hash_table_ok PARAMS ((const Hash_table *));
+void hash_print_statistics PARAMS ((const Hash_table *, FILE *));
+void *hash_lookup PARAMS ((const Hash_table *, const void *));
+
+/* Walking. */
+void *hash_get_first PARAMS ((const Hash_table *));
+void *hash_get_next PARAMS ((const Hash_table *, const void *));
+unsigned hash_get_entries PARAMS ((const Hash_table *, void **, unsigned));
+unsigned hash_do_for_each PARAMS ((const Hash_table *, Hash_processor, void *));
+
+/* Allocation and clean-up. */
+unsigned hash_string PARAMS ((const char *, unsigned));
+void hash_reset_tuning PARAMS ((Hash_tuning *));
+Hash_table *hash_initialize PARAMS ((unsigned, const Hash_tuning *,
+ Hash_hasher, Hash_comparator,
+ Hash_data_freer));
+void hash_clear PARAMS ((Hash_table *));
+void hash_free PARAMS ((Hash_table *));
+
+/* Insertion and deletion. */
+bool hash_rehash PARAMS ((Hash_table *, unsigned));
+void *hash_insert PARAMS ((Hash_table *, const void *));
+void *hash_delete PARAMS ((Hash_table *, const void *));
diff --git a/contrib/tar/lib/human.c b/contrib/tar/lib/human.c
new file mode 100644
index 0000000..92b051c
--- /dev/null
+++ b/contrib/tar/lib/human.c
@@ -0,0 +1,342 @@
+/* human.c -- print human readable file size
+ Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Originally contributed by lm@sgi.com;
+ --si, output block size selection, and large file support
+ added by eggert@twinsun.com. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#ifndef CHAR_BIT
+# define CHAR_BIT 8
+#endif
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifndef HAVE_DECL_GETENV
+"this configure-time declaration test was not run"
+#endif
+#if !HAVE_DECL_GETENV
+char *getenv ();
+#endif
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# define _(Text) Text
+#endif
+
+#include <argmatch.h>
+#include <error.h>
+#include <xstrtol.h>
+
+#include "human.h"
+
+static const char suffixes[] =
+{
+ 0, /* not used */
+ 'k', /* kilo */
+ 'M', /* Mega */
+ 'G', /* Giga */
+ 'T', /* Tera */
+ 'P', /* Peta */
+ 'E', /* Exa */
+ 'Z', /* Zetta */
+ 'Y' /* Yotta */
+};
+
+/* If INEXACT_STYLE is not human_round_to_even, and if easily
+ possible, adjust VALUE according to the style. */
+static double
+adjust_value (enum human_inexact_style inexact_style, double value)
+{
+ /* Do not use the floor or ceil functions, as that would mean
+ linking with the standard math library, which is a porting pain.
+ So leave the value alone if it is too large to easily round. */
+ if (inexact_style != human_round_to_even && value < (uintmax_t) -1)
+ {
+ uintmax_t u = value;
+ value = u + (inexact_style == human_ceiling && u != value);
+ }
+
+ return value;
+}
+
+/* Like human_readable_inexact, except always round to even. */
+char *
+human_readable (uintmax_t n, char *buf,
+ int from_block_size, int output_block_size)
+{
+ return human_readable_inexact (n, buf, from_block_size, output_block_size,
+ human_round_to_even);
+}
+
+/* Convert N to a human readable format in BUF.
+
+ N is expressed in units of FROM_BLOCK_SIZE. FROM_BLOCK_SIZE must
+ be nonnegative.
+
+ OUTPUT_BLOCK_SIZE must be nonzero. If it is positive, use units of
+ OUTPUT_BLOCK_SIZE in the output number.
+
+ Use INEXACT_STYLE to determine whether to take the ceiling or floor
+ of any result that cannot be expressed exactly.
+
+ If OUTPUT_BLOCK_SIZE is negative, use a format like "127k" if
+ possible, using powers of -OUTPUT_BLOCK_SIZE; otherwise, use
+ ordinary decimal format. Normally -OUTPUT_BLOCK_SIZE is either
+ 1000 or 1024; it must be at least 2. Most people visually process
+ strings of 3-4 digits effectively, but longer strings of digits are
+ more prone to misinterpretation. Hence, converting to an
+ abbreviated form usually improves readability. Use a suffix
+ indicating which power is being used. For example, assuming
+ -OUTPUT_BLOCK_SIZE is 1024, 8500 would be converted to 8.3k,
+ 133456345 to 127M, 56990456345 to 53G, and so on. Numbers smaller
+ than -OUTPUT_BLOCK_SIZE aren't modified. */
+
+char *
+human_readable_inexact (uintmax_t n, char *buf,
+ int from_block_size, int output_block_size,
+ enum human_inexact_style inexact_style)
+{
+ uintmax_t amt;
+ int base;
+ int to_block_size;
+ int tenths = 0;
+ int power;
+ char *p;
+
+ /* 0 means adjusted N == AMT.TENTHS;
+ 1 means AMT.TENTHS < adjusted N < AMT.TENTHS + 0.05;
+ 2 means adjusted N == AMT.TENTHS + 0.05;
+ 3 means AMT.TENTHS + 0.05 < adjusted N < AMT.TENTHS + 0.1. */
+ int rounding = 0;
+
+ if (output_block_size < 0)
+ {
+ base = -output_block_size;
+ to_block_size = 1;
+ }
+ else
+ {
+ base = 0;
+ to_block_size = output_block_size;
+ }
+
+ p = buf + LONGEST_HUMAN_READABLE;
+ *p = '\0';
+
+#ifdef lint
+ /* Suppress `used before initialized' warning. */
+ power = 0;
+#endif
+
+ /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE units. */
+
+ {
+ int multiplier;
+ int divisor;
+ int r2;
+ int r10;
+ if (to_block_size <= from_block_size
+ ? (from_block_size % to_block_size != 0
+ || (multiplier = from_block_size / to_block_size,
+ (amt = n * multiplier) / multiplier != n))
+ : (from_block_size == 0
+ || to_block_size % from_block_size != 0
+ || (divisor = to_block_size / from_block_size,
+ r10 = (n % divisor) * 10,
+ r2 = (r10 % divisor) * 2,
+ amt = n / divisor,
+ tenths = r10 / divisor,
+ rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2),
+ 0)))
+ {
+ /* Either the result cannot be computed easily using uintmax_t,
+ or from_block_size is zero. Fall back on floating point.
+ FIXME: This can yield answers that are slightly off. */
+
+ double damt = n * (from_block_size / (double) to_block_size);
+
+ if (! base)
+ sprintf (buf, "%.0f", adjust_value (inexact_style, damt));
+ else
+ {
+ double e = 1;
+ power = 0;
+
+ do
+ {
+ e *= base;
+ power++;
+ }
+ while (e * base <= damt && power < sizeof suffixes - 1);
+
+ damt /= e;
+
+ sprintf (buf, "%.1f%c", adjust_value (inexact_style, damt),
+ suffixes[power]);
+ if (4 < strlen (buf))
+ sprintf (buf, "%.0f%c",
+ adjust_value (inexact_style, damt * 10) / 10,
+ suffixes[power]);
+ }
+
+ return buf;
+ }
+ }
+
+ /* Use power of BASE notation if adjusted AMT is large enough. */
+
+ if (base && base <= amt)
+ {
+ power = 0;
+
+ do
+ {
+ int r10 = (amt % base) * 10 + tenths;
+ int r2 = (r10 % base) * 2 + (rounding >> 1);
+ amt /= base;
+ tenths = r10 / base;
+ rounding = (r2 < base
+ ? 0 < r2 + rounding
+ : 2 + (base < r2 + rounding));
+ power++;
+ }
+ while (base <= amt && power < sizeof suffixes - 1);
+
+ *--p = suffixes[power];
+
+ if (amt < 10)
+ {
+ if (2 * (1 - (int) inexact_style)
+ < rounding + (tenths & (inexact_style == human_round_to_even)))
+ {
+ tenths++;
+ rounding = 0;
+
+ if (tenths == 10)
+ {
+ amt++;
+ tenths = 0;
+ }
+ }
+
+ if (amt < 10)
+ {
+ *--p = '0' + tenths;
+ *--p = '.';
+ tenths = rounding = 0;
+ }
+ }
+ }
+
+ if (inexact_style == human_ceiling
+ ? 0 < tenths + rounding
+ : inexact_style == human_round_to_even
+ ? 5 < tenths + (2 < rounding + (amt & 1))
+ : /* inexact_style == human_floor */ 0)
+ {
+ amt++;
+
+ if (amt == base && power < sizeof suffixes - 1)
+ {
+ *p = suffixes[power + 1];
+ *--p = '0';
+ *--p = '.';
+ amt = 1;
+ }
+ }
+
+ do
+ *--p = '0' + (int) (amt % 10);
+ while ((amt /= 10) != 0);
+
+ return p;
+}
+
+
+/* The default block size used for output. This number may change in
+ the future as disks get larger. */
+#ifndef DEFAULT_BLOCK_SIZE
+# define DEFAULT_BLOCK_SIZE 1024
+#endif
+
+static char const *const block_size_args[] = { "human-readable", "si", 0 };
+static int const block_size_types[] = { -1024, -1000 };
+
+static int
+default_block_size (void)
+{
+ return getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE;
+}
+
+static strtol_error
+humblock (char const *spec, int *block_size)
+{
+ int i;
+
+ if (! spec && ! (spec = getenv ("BLOCK_SIZE")))
+ *block_size = default_block_size ();
+ else if (0 <= (i = ARGMATCH (spec, block_size_args, block_size_types)))
+ *block_size = block_size_types[i];
+ else
+ {
+ char *ptr;
+ unsigned long val;
+ strtol_error e = xstrtoul (spec, &ptr, 0, &val, "eEgGkKmMpPtTyYzZ0");
+ if (e != LONGINT_OK)
+ return e;
+ if (*ptr)
+ return LONGINT_INVALID_SUFFIX_CHAR;
+ if ((int) val < 0 || val != (int) val)
+ return LONGINT_OVERFLOW;
+ *block_size = (int) val;
+ }
+
+ return LONGINT_OK;
+}
+
+void
+human_block_size (char const *spec, int report_errors, int *block_size)
+{
+ strtol_error e = humblock (spec, block_size);
+ if (*block_size == 0)
+ {
+ *block_size = default_block_size ();
+ e = LONGINT_INVALID;
+ }
+ if (e != LONGINT_OK && report_errors)
+ STRTOL_FATAL_ERROR (spec, _("block size"), e);
+}
diff --git a/contrib/tar/lib/human.h b/contrib/tar/lib/human.h
new file mode 100644
index 0000000..4ec9f0d
--- /dev/null
+++ b/contrib/tar/lib/human.h
@@ -0,0 +1,39 @@
+#ifndef HUMAN_H_
+# define HUMAN_H_ 1
+
+# if HAVE_CONFIG_H
+# include <config.h>
+# endif
+
+# if HAVE_INTTYPES_H
+# include <inttypes.h>
+# endif
+
+/* A conservative bound on the maximum length of a human-readable string.
+ The output can be the product of the largest uintmax_t and the largest int,
+ so add their sizes before converting to a bound on digits. */
+# define LONGEST_HUMAN_READABLE ((sizeof (uintmax_t) + sizeof (int)) \
+ * CHAR_BIT / 3)
+
+# ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+# endif
+
+enum human_inexact_style
+{
+ human_floor = -1,
+ human_round_to_even = 0,
+ human_ceiling = 1
+};
+
+char *human_readable PARAMS ((uintmax_t, char *, int, int));
+char *human_readable_inexact PARAMS ((uintmax_t, char *, int, int,
+ enum human_inexact_style));
+
+void human_block_size PARAMS ((char const *, int, int *));
+
+#endif /* HUMAN_H_ */
diff --git a/contrib/tar/lib/lchown.c b/contrib/tar/lib/lchown.c
new file mode 100644
index 0000000..9604b54
--- /dev/null
+++ b/contrib/tar/lib/lchown.c
@@ -0,0 +1,56 @@
+/* Provide a stub lchown function for systems that lack it.
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* written by Jim Meyering */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#include "lchown.h"
+
+#ifdef STAT_MACROS_BROKEN
+# undef S_ISLNK
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+
+/* Declare chown to avoid a warning. Don't include unistd.h,
+ because it may have a conflicting prototype for lchown. */
+int chown ();
+
+/* Work just like chown, except when FILE is a symbolic link.
+ In that case, set errno to ENOSYS and return -1. */
+
+int
+lchown (const char *file, uid_t uid, gid_t gid)
+{
+ struct stat stats;
+
+ if (lstat (file, &stats) == 0 && S_ISLNK (stats.st_mode))
+ {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return chown (file, uid, gid);
+}
diff --git a/contrib/tar/lib/lchown.h b/contrib/tar/lib/lchown.h
new file mode 100644
index 0000000..46fa0ed
--- /dev/null
+++ b/contrib/tar/lib/lchown.h
@@ -0,0 +1,9 @@
+/* Some systems don't have ENOSYS. */
+#ifndef ENOSYS
+# ifdef ENOTSUP
+# define ENOSYS ENOTSUP
+# else
+/* Some systems don't have ENOTSUP either. */
+# define ENOSYS EINVAL
+# endif
+#endif
diff --git a/contrib/tar/lib/malloc.c b/contrib/tar/lib/malloc.c
new file mode 100644
index 0000000..5e7674b
--- /dev/null
+++ b/contrib/tar/lib/malloc.c
@@ -0,0 +1,38 @@
+/* Work around bug on some systems where malloc (0) fails.
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* written by Jim Meyering */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+#undef malloc
+
+#include <sys/types.h>
+
+char *malloc ();
+
+/* Allocate an N-byte block of memory from the heap.
+ If N is zero, allocate a 1-byte block. */
+
+char *
+rpl_malloc (size_t n)
+{
+ if (n == 0)
+ n = 1;
+ return malloc (n);
+}
diff --git a/contrib/tar/lib/memset.c b/contrib/tar/lib/memset.c
new file mode 100644
index 0000000..5744bcb
--- /dev/null
+++ b/contrib/tar/lib/memset.c
@@ -0,0 +1,26 @@
+/* memset.c -- set an area of memory to a given value
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+char *
+memset (char *str, int c, unsigned int len)
+{
+ register char *st = str;
+
+ while (len-- > 0)
+ *st++ = c;
+ return str;
+}
diff --git a/contrib/tar/lib/mktime.c b/contrib/tar/lib/mktime.c
new file mode 100644
index 0000000..06b3dcb
--- /dev/null
+++ b/contrib/tar/lib/mktime.c
@@ -0,0 +1,527 @@
+/* Convert a `struct tm' to a time_t value.
+ Copyright (C) 1993, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Paul Eggert (eggert@twinsun.com).
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Define this to have a standalone program to test this implementation of
+ mktime. */
+/* #define DEBUG 1 */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# define HAVE_LIMITS_H 1
+# define STDC_HEADERS 1
+#endif
+
+/* Assume that leap seconds are possible, unless told otherwise.
+ If the host has a `zic' command with a `-L leapsecondfilename' option,
+ then it supports leap seconds; otherwise it probably doesn't. */
+#ifndef LEAP_SECONDS_POSSIBLE
+# define LEAP_SECONDS_POSSIBLE 1
+#endif
+
+#include <sys/types.h> /* Some systems define `time_t' here. */
+#include <time.h>
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#if DEBUG
+# include <stdio.h>
+# if STDC_HEADERS
+# include <stdlib.h>
+# endif
+/* Make it work even if the system's libc has its own mktime routine. */
+# define mktime my_mktime
+#endif /* DEBUG */
+
+#ifndef __P
+# if defined __GNUC__ || (defined __STDC__ && __STDC__)
+# define __P(args) args
+# else
+# define __P(args) ()
+# endif /* GCC. */
+#endif /* Not __P. */
+
+#ifndef CHAR_BIT
+# define CHAR_BIT 8
+#endif
+
+/* The extra casts work around common compiler bugs. */
+#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
+ It is necessary at least when t == time_t. */
+#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
+ ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
+#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
+
+#ifndef INT_MIN
+# define INT_MIN TYPE_MINIMUM (int)
+#endif
+#ifndef INT_MAX
+# define INT_MAX TYPE_MAXIMUM (int)
+#endif
+
+#ifndef TIME_T_MIN
+# define TIME_T_MIN TYPE_MINIMUM (time_t)
+#endif
+#ifndef TIME_T_MAX
+# define TIME_T_MAX TYPE_MAXIMUM (time_t)
+#endif
+
+#define TM_YEAR_BASE 1900
+#define EPOCH_YEAR 1970
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+ except every 100th isn't, and every 400th is). */
+# define __isleap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#endif
+
+/* How many days come before each month (0-12). */
+const unsigned short int __mon_yday[2][13] =
+ {
+ /* Normal years. */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ /* Leap years. */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+ };
+
+
+#ifdef _LIBC
+# define my_mktime_localtime_r __localtime_r
+#else
+/* If we're a mktime substitute in a GNU program, then prefer
+ localtime to localtime_r, since many localtime_r implementations
+ are buggy. */
+static struct tm *
+my_mktime_localtime_r (const time_t *t, struct tm *tp)
+{
+ struct tm *l = localtime (t);
+ if (! l)
+ return 0;
+ *tp = *l;
+ return tp;
+}
+#endif /* ! _LIBC */
+
+
+/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
+ measured in seconds, ignoring leap seconds.
+ YEAR uses the same numbering as TM->tm_year.
+ All values are in range, except possibly YEAR.
+ If TP is null, return a nonzero value.
+ If overflow occurs, yield the low order bits of the correct answer. */
+static time_t
+ydhms_tm_diff (int year, int yday, int hour, int min, int sec,
+ const struct tm *tp)
+{
+ if (!tp)
+ return 1;
+ else
+ {
+ /* Compute intervening leap days correctly even if year is negative.
+ Take care to avoid int overflow. time_t overflow is OK, since
+ only the low order bits of the correct time_t answer are needed.
+ Don't convert to time_t until after all divisions are done, since
+ time_t might be unsigned. */
+ int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
+ int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = a100 >> 2;
+ int b400 = b100 >> 2;
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+ time_t years = year - (time_t) tp->tm_year;
+ time_t days = (365 * years + intervening_leap_days
+ + (yday - tp->tm_yday));
+ return (60 * (60 * (24 * days + (hour - tp->tm_hour))
+ + (min - tp->tm_min))
+ + (sec - tp->tm_sec));
+ }
+}
+
+/* Use CONVERT to convert *T to a broken down time in *TP.
+ If *T is out of range for conversion, adjust it so that
+ it is the nearest in-range value and then convert that. */
+static struct tm *
+ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
+ time_t *t, struct tm *tp)
+{
+ struct tm *r;
+
+ if (! (r = (*convert) (t, tp)) && *t)
+ {
+ time_t bad = *t;
+ time_t ok = 0;
+ struct tm tm;
+
+ /* BAD is a known unconvertible time_t, and OK is a known good one.
+ Use binary search to narrow the range between BAD and OK until
+ they differ by 1. */
+ while (bad != ok + (bad < 0 ? -1 : 1))
+ {
+ time_t mid = *t = (bad < 0
+ ? bad + ((ok - bad) >> 1)
+ : ok + ((bad - ok) >> 1));
+ if ((r = (*convert) (t, tp)))
+ {
+ tm = *r;
+ ok = mid;
+ }
+ else
+ bad = mid;
+ }
+
+ if (!r && ok)
+ {
+ /* The last conversion attempt failed;
+ revert to the most recent successful attempt. */
+ *t = ok;
+ *tp = tm;
+ r = tp;
+ }
+ }
+
+ return r;
+}
+
+
+/* Convert *TP to a time_t value, inverting
+ the monotonic and mostly-unit-linear conversion function CONVERT.
+ Use *OFFSET to keep track of a guess at the offset of the result,
+ compared to what the result would be for UTC without leap seconds.
+ If *OFFSET's guess is correct, only one CONVERT call is needed. */
+time_t
+__mktime_internal (struct tm *tp,
+ struct tm *(*convert) (const time_t *, struct tm *),
+ time_t *offset)
+{
+ time_t t, dt, t0, t1, t2;
+ struct tm tm;
+
+ /* The maximum number of probes (calls to CONVERT) should be enough
+ to handle any combinations of time zone rule changes, solar time,
+ leap seconds, and oscillations around a spring-forward gap.
+ POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
+ int remaining_probes = 6;
+
+ /* Time requested. Copy it in case CONVERT modifies *TP; this can
+ occur if TP is localtime's returned value and CONVERT is localtime. */
+ int sec = tp->tm_sec;
+ int min = tp->tm_min;
+ int hour = tp->tm_hour;
+ int mday = tp->tm_mday;
+ int mon = tp->tm_mon;
+ int year_requested = tp->tm_year;
+ int isdst = tp->tm_isdst;
+
+ /* Ensure that mon is in range, and set year accordingly. */
+ int mon_remainder = mon % 12;
+ int negative_mon_remainder = mon_remainder < 0;
+ int mon_years = mon / 12 - negative_mon_remainder;
+ int year = year_requested + mon_years;
+
+ /* The other values need not be in range:
+ the remaining code handles minor overflows correctly,
+ assuming int and time_t arithmetic wraps around.
+ Major overflows are caught at the end. */
+
+ /* Calculate day of year from year, month, and day of month.
+ The result need not be in range. */
+ int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
+ [mon_remainder + 12 * negative_mon_remainder])
+ + mday - 1);
+
+ int sec_requested = sec;
+#if LEAP_SECONDS_POSSIBLE
+ /* Handle out-of-range seconds specially,
+ since ydhms_tm_diff assumes every minute has 60 seconds. */
+ if (sec < 0)
+ sec = 0;
+ if (59 < sec)
+ sec = 59;
+#endif
+
+ /* Invert CONVERT by probing. First assume the same offset as last time.
+ Then repeatedly use the error to improve the guess. */
+
+ tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
+ tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+ t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
+
+ for (t = t1 = t2 = t0 + *offset;
+ (dt = ydhms_tm_diff (year, yday, hour, min, sec,
+ ranged_convert (convert, &t, &tm)));
+ t1 = t2, t2 = t, t += dt)
+ if (t == t1 && t != t2
+ && (isdst < 0 || tm.tm_isdst < 0
+ || (isdst != 0) != (tm.tm_isdst != 0)))
+ /* We can't possibly find a match, as we are oscillating
+ between two values. The requested time probably falls
+ within a spring-forward gap of size DT. Follow the common
+ practice in this case, which is to return a time that is DT
+ away from the requested time, preferring a time whose
+ tm_isdst differs from the requested value. In practice,
+ this is more useful than returning -1. */
+ break;
+ else if (--remaining_probes == 0)
+ return -1;
+
+ /* If we have a match, check whether tm.tm_isdst has the requested
+ value, if any. */
+ if (dt == 0 && isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst)
+ {
+ /* tm.tm_isdst has the wrong value. Look for a neighboring
+ time with the right value, and use its UTC offset.
+ Heuristic: probe the previous three calendar quarters (approximately),
+ looking for the desired isdst. This isn't perfect,
+ but it's good enough in practice. */
+ int quarter = 7889238; /* seconds per average 1/4 Gregorian year */
+ int i;
+
+ /* If we're too close to the time_t limit, look in future quarters. */
+ if (t < TIME_T_MIN + 3 * quarter)
+ quarter = -quarter;
+
+ for (i = 1; i <= 3; i++)
+ {
+ time_t ot = t - i * quarter;
+ struct tm otm;
+ ranged_convert (convert, &ot, &otm);
+ if (otm.tm_isdst == isdst)
+ {
+ /* We found the desired tm_isdst.
+ Extrapolate back to the desired time. */
+ t = ot + ydhms_tm_diff (year, yday, hour, min, sec, &otm);
+ ranged_convert (convert, &t, &tm);
+ break;
+ }
+ }
+ }
+
+ *offset = t - t0;
+
+#if LEAP_SECONDS_POSSIBLE
+ if (sec_requested != tm.tm_sec)
+ {
+ /* Adjust time to reflect the tm_sec requested, not the normalized value.
+ Also, repair any damage from a false match due to a leap second. */
+ t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
+ if (! (*convert) (&t, &tm))
+ return -1;
+ }
+#endif
+
+ if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
+ {
+ /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
+ so check for major overflows. A gross check suffices,
+ since if t has overflowed, it is off by a multiple of
+ TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
+ the difference that is bounded by a small value. */
+
+ double dyear = (double) year_requested + mon_years - tm.tm_year;
+ double dday = 366 * dyear + mday;
+ double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
+
+ /* On Irix4.0.5 cc, dividing TIME_T_MIN by 3 does not produce
+ correct results, ie., it erroneously gives a positive value
+ of 715827882. Setting a variable first then doing math on it
+ seems to work. (ghazi@caip.rutgers.edu) */
+
+ const time_t time_t_max = TIME_T_MAX;
+ const time_t time_t_min = TIME_T_MIN;
+
+ if (time_t_max / 3 - time_t_min / 3 < (dsec < 0 ? - dsec : dsec))
+ return -1;
+ }
+
+ *tp = tm;
+ return t;
+}
+
+
+static time_t localtime_offset;
+
+/* Convert *TP to a time_t value. */
+time_t
+mktime (tp)
+ struct tm *tp;
+{
+#ifdef _LIBC
+ /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
+ time zone names contained in the external variable `tzname' shall
+ be set as if the tzset() function had been called. */
+ __tzset ();
+#endif
+
+ return __mktime_internal (tp, my_mktime_localtime_r, &localtime_offset);
+}
+
+#ifdef weak_alias
+weak_alias (mktime, timelocal)
+#endif
+
+#if DEBUG
+
+static int
+not_equal_tm (a, b)
+ struct tm *a;
+ struct tm *b;
+{
+ return ((a->tm_sec ^ b->tm_sec)
+ | (a->tm_min ^ b->tm_min)
+ | (a->tm_hour ^ b->tm_hour)
+ | (a->tm_mday ^ b->tm_mday)
+ | (a->tm_mon ^ b->tm_mon)
+ | (a->tm_year ^ b->tm_year)
+ | (a->tm_mday ^ b->tm_mday)
+ | (a->tm_yday ^ b->tm_yday)
+ | (a->tm_isdst ^ b->tm_isdst));
+}
+
+static void
+print_tm (tp)
+ struct tm *tp;
+{
+ if (tp)
+ printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
+ tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec,
+ tp->tm_yday, tp->tm_wday, tp->tm_isdst);
+ else
+ printf ("0");
+}
+
+static int
+check_result (tk, tmk, tl, lt)
+ time_t tk;
+ struct tm tmk;
+ time_t tl;
+ struct tm *lt;
+{
+ if (tk != tl || !lt || not_equal_tm (&tmk, lt))
+ {
+ printf ("mktime (");
+ print_tm (&tmk);
+ printf (")\nyields (");
+ print_tm (lt);
+ printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int status = 0;
+ struct tm tm, tmk, tml;
+ struct tm *lt;
+ time_t tk, tl;
+ char trailer;
+
+ if ((argc == 3 || argc == 4)
+ && (sscanf (argv[1], "%d-%d-%d%c",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
+ == 3)
+ && (sscanf (argv[2], "%d:%d:%d%c",
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
+ == 3))
+ {
+ tm.tm_year -= TM_YEAR_BASE;
+ tm.tm_mon--;
+ tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
+ tmk = tm;
+ tl = mktime (&tmk);
+ lt = localtime (&tl);
+ if (lt)
+ {
+ tml = *lt;
+ lt = &tml;
+ }
+ printf ("mktime returns %ld == ", (long) tl);
+ print_tm (&tmk);
+ printf ("\n");
+ status = check_result (tl, tmk, tl, lt);
+ }
+ else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
+ {
+ time_t from = atol (argv[1]);
+ time_t by = atol (argv[2]);
+ time_t to = atol (argv[3]);
+
+ if (argc == 4)
+ for (tl = from; tl <= to; tl += by)
+ {
+ lt = localtime (&tl);
+ if (lt)
+ {
+ tmk = tml = *lt;
+ tk = mktime (&tmk);
+ status |= check_result (tk, tmk, tl, tml);
+ }
+ else
+ {
+ printf ("localtime (%ld) yields 0\n", (long) tl);
+ status = 1;
+ }
+ }
+ else
+ for (tl = from; tl <= to; tl += by)
+ {
+ /* Null benchmark. */
+ lt = localtime (&tl);
+ if (lt)
+ {
+ tmk = tml = *lt;
+ tk = tl;
+ status |= check_result (tk, tmk, tl, tml);
+ }
+ else
+ {
+ printf ("localtime (%ld) yields 0\n", (long) tl);
+ status = 1;
+ }
+ }
+ }
+ else
+ printf ("Usage:\
+\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
+\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
+\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
+ argv[0], argv[0], argv[0]);
+
+ return status;
+}
+
+#endif /* DEBUG */
+
+/*
+Local Variables:
+compile-command: "gcc -DDEBUG -DHAVE_LIMITS_H -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"
+End:
+*/
diff --git a/contrib/tar/lib/modechange.c b/contrib/tar/lib/modechange.c
new file mode 100644
index 0000000..c768116
--- /dev/null
+++ b/contrib/tar/lib/modechange.c
@@ -0,0 +1,481 @@
+/* modechange.c -- file mode manipulation
+ Copyright (C) 1989, 1990, 1997, 1998, 1999, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by David MacKenzie <djm@ai.mit.edu> */
+
+/* The ASCII mode string is compiled into a linked list of `struct
+ modechange', which can then be applied to each file to be changed.
+ We do this instead of re-parsing the ASCII string for each file
+ because the compiled form requires less computation to use; when
+ changing the mode of many files, this probably results in a
+ performance gain. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "modechange.h"
+#include <sys/stat.h>
+#include "xstrtol.h"
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+char *malloc ();
+#endif
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+#if STAT_MACROS_BROKEN
+# undef S_ISDIR
+#endif
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+/* The traditional octal values corresponding to each mode bit. */
+#define SUID 04000
+#define SGID 02000
+#define SVTX 01000
+#define RUSR 00400
+#define WUSR 00200
+#define XUSR 00100
+#define RGRP 00040
+#define WGRP 00020
+#define XGRP 00010
+#define ROTH 00004
+#define WOTH 00002
+#define XOTH 00001
+#define ALLM 07777 /* all octal mode bits */
+
+#ifndef S_ISUID
+# define S_ISUID SUID
+#endif
+#ifndef S_ISGID
+# define S_ISGID SGID
+#endif
+#ifndef S_ISVTX
+# define S_ISVTX SVTX
+#endif
+#ifndef S_IRUSR
+# define S_IRUSR RUSR
+#endif
+#ifndef S_IWUSR
+# define S_IWUSR WUSR
+#endif
+#ifndef S_IXUSR
+# define S_IXUSR XUSR
+#endif
+#ifndef S_IRGRP
+# define S_IRGRP RGRP
+#endif
+#ifndef S_IWGRP
+# define S_IWGRP WGRP
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP XGRP
+#endif
+#ifndef S_IROTH
+# define S_IROTH ROTH
+#endif
+#ifndef S_IWOTH
+# define S_IWOTH WOTH
+#endif
+#ifndef S_IXOTH
+# define S_IXOTH XOTH
+#endif
+#ifndef S_IRWXU
+# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
+#endif
+#ifndef S_IRWXG
+# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
+#endif
+#ifndef S_IRWXO
+# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
+#endif
+
+/* All the mode bits that can be affected by chmod. */
+#define CHMOD_MODE_BITS \
+ (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
+
+/* Return newly allocated memory to hold one element of type TYPE. */
+#define talloc(type) ((type *) malloc (sizeof (type)))
+
+/* Create a mode_change entry with the specified `=ddd'-style
+ mode change operation, where NEW_MODE is `ddd'. Return the
+ new entry, or NULL upon failure. */
+
+static struct mode_change *
+make_node_op_equals (mode_t new_mode)
+{
+ struct mode_change *p;
+ p = talloc (struct mode_change);
+ if (p == NULL)
+ return p;
+ p->next = NULL;
+ p->op = '=';
+ p->flags = 0;
+ p->value = new_mode;
+ p->affected = CHMOD_MODE_BITS; /* Affect all permissions. */
+ return p;
+}
+
+/* Append entry E to the end of the link list with the specified
+ HEAD and TAIL. */
+
+static void
+mode_append_entry (struct mode_change **head,
+ struct mode_change **tail,
+ struct mode_change *e)
+{
+ if (*head == NULL)
+ *head = *tail = e;
+ else
+ {
+ (*tail)->next = e;
+ *tail = e;
+ }
+}
+
+/* Return a linked list of file mode change operations created from
+ MODE_STRING, an ASCII string that contains either an octal number
+ specifying an absolute mode, or symbolic mode change operations with
+ the form:
+ [ugoa...][[+-=][rwxXstugo...]...][,...]
+ MASKED_OPS is a bitmask indicating which symbolic mode operators (=+-)
+ should not affect bits set in the umask when no users are given.
+ Operators not selected in MASKED_OPS ignore the umask.
+
+ Return MODE_INVALID if `mode_string' does not contain a valid
+ representation of file mode change operations;
+ return MODE_MEMORY_EXHAUSTED if there is insufficient memory. */
+
+struct mode_change *
+mode_compile (const char *mode_string, unsigned int masked_ops)
+{
+ struct mode_change *head; /* First element of the linked list. */
+ struct mode_change *tail; /* An element of the linked list. */
+ unsigned long octal_value; /* The mode value, if octal. */
+ mode_t umask_value; /* The umask value (surprise). */
+
+ head = NULL;
+#ifdef lint
+ tail = NULL;
+#endif
+
+ if (xstrtoul (mode_string, NULL, 8, &octal_value, "") == LONGINT_OK)
+ {
+ struct mode_change *p;
+ mode_t mode;
+ if (octal_value != (octal_value & ALLM))
+ return MODE_INVALID;
+
+ /* Help the compiler optimize the usual case where mode_t uses
+ the traditional octal representation. */
+ mode = ((S_ISUID == SUID && S_ISGID == SGID && S_ISVTX == SVTX
+ && S_IRUSR == RUSR && S_IWUSR == WUSR && S_IXUSR == XUSR
+ && S_IRGRP == RGRP && S_IWGRP == WGRP && S_IXGRP == XGRP
+ && S_IROTH == ROTH && S_IWOTH == WOTH && S_IXOTH == XOTH)
+ ? octal_value
+ : ((octal_value & SUID ? S_ISUID : 0)
+ | (octal_value & SGID ? S_ISGID : 0)
+ | (octal_value & SVTX ? S_ISVTX : 0)
+ | (octal_value & RUSR ? S_IRUSR : 0)
+ | (octal_value & WUSR ? S_IWUSR : 0)
+ | (octal_value & XUSR ? S_IXUSR : 0)
+ | (octal_value & RGRP ? S_IRGRP : 0)
+ | (octal_value & WGRP ? S_IWGRP : 0)
+ | (octal_value & XGRP ? S_IXGRP : 0)
+ | (octal_value & ROTH ? S_IROTH : 0)
+ | (octal_value & WOTH ? S_IWOTH : 0)
+ | (octal_value & XOTH ? S_IXOTH : 0)));
+
+ p = make_node_op_equals (mode);
+ if (p == NULL)
+ return MODE_MEMORY_EXHAUSTED;
+ mode_append_entry (&head, &tail, p);
+ return head;
+ }
+
+ umask_value = umask (0);
+ umask (umask_value); /* Restore the old value. */
+ --mode_string;
+
+ /* One loop iteration for each "ugoa...=+-rwxXstugo...[=+-rwxXstugo...]". */
+ do
+ {
+ /* Which bits in the mode are operated on. */
+ mode_t affected_bits = 0;
+ /* `affected_bits' modified by umask. */
+ mode_t affected_masked;
+ /* Operators to actually use umask on. */
+ unsigned ops_to_mask = 0;
+
+ int who_specified_p;
+
+ affected_bits = 0;
+ ops_to_mask = 0;
+ /* Turn on all the bits in `affected_bits' for each group given. */
+ for (++mode_string;; ++mode_string)
+ switch (*mode_string)
+ {
+ case 'u':
+ affected_bits |= S_ISUID | S_IRWXU;
+ break;
+ case 'g':
+ affected_bits |= S_ISGID | S_IRWXG;
+ break;
+ case 'o':
+ affected_bits |= S_ISVTX | S_IRWXO;
+ break;
+ case 'a':
+ affected_bits |= CHMOD_MODE_BITS;
+ break;
+ default:
+ goto no_more_affected;
+ }
+
+ no_more_affected:
+ /* If none specified, affect all bits, except perhaps those
+ set in the umask. */
+ if (affected_bits)
+ who_specified_p = 1;
+ else
+ {
+ who_specified_p = 0;
+ affected_bits = CHMOD_MODE_BITS;
+ ops_to_mask = masked_ops;
+ }
+
+ while (*mode_string == '=' || *mode_string == '+' || *mode_string == '-')
+ {
+ struct mode_change *change = talloc (struct mode_change);
+ if (change == NULL)
+ {
+ mode_free (head);
+ return MODE_MEMORY_EXHAUSTED;
+ }
+
+ change->next = NULL;
+ change->op = *mode_string; /* One of "=+-". */
+ affected_masked = affected_bits;
+
+ /* Per the Single Unix Spec, if `who' is not specified and the
+ `=' operator is used, then clear all the bits first. */
+ if (!who_specified_p &&
+ ops_to_mask & (*mode_string == '=' ? MODE_MASK_EQUALS : 0))
+ {
+ struct mode_change *p = make_node_op_equals (0);
+ if (p == NULL)
+ return MODE_MEMORY_EXHAUSTED;
+ mode_append_entry (&head, &tail, p);
+ }
+
+ if (ops_to_mask & (*mode_string == '=' ? MODE_MASK_EQUALS
+ : *mode_string == '+' ? MODE_MASK_PLUS
+ : MODE_MASK_MINUS))
+ affected_masked &= ~umask_value;
+ change->affected = affected_masked;
+ change->value = 0;
+ change->flags = 0;
+
+ /* Add the element to the tail of the list, so the operations
+ are performed in the correct order. */
+ mode_append_entry (&head, &tail, change);
+
+ /* Set `value' according to the bits set in `affected_masked'. */
+ for (++mode_string;; ++mode_string)
+ switch (*mode_string)
+ {
+ case 'r':
+ change->value |= ((S_IRUSR | S_IRGRP | S_IROTH)
+ & affected_masked);
+ break;
+ case 'w':
+ change->value |= ((S_IWUSR | S_IWGRP | S_IWOTH)
+ & affected_masked);
+ break;
+ case 'X':
+ change->flags |= MODE_X_IF_ANY_X;
+ /* Fall through. */
+ case 'x':
+ change->value |= ((S_IXUSR | S_IXGRP | S_IXOTH)
+ & affected_masked);
+ break;
+ case 's':
+ /* Set the setuid/gid bits if `u' or `g' is selected. */
+ change->value |= (S_ISUID | S_ISGID) & affected_masked;
+ break;
+ case 't':
+ /* Set the "save text image" bit if `o' is selected. */
+ change->value |= S_ISVTX & affected_masked;
+ break;
+ case 'u':
+ /* Set the affected bits to the value of the `u' bits
+ on the same file. */
+ if (change->value)
+ goto invalid;
+ change->value = S_IRWXU;
+ change->flags |= MODE_COPY_EXISTING;
+ break;
+ case 'g':
+ /* Set the affected bits to the value of the `g' bits
+ on the same file. */
+ if (change->value)
+ goto invalid;
+ change->value = S_IRWXG;
+ change->flags |= MODE_COPY_EXISTING;
+ break;
+ case 'o':
+ /* Set the affected bits to the value of the `o' bits
+ on the same file. */
+ if (change->value)
+ goto invalid;
+ change->value = S_IRWXO;
+ change->flags |= MODE_COPY_EXISTING;
+ break;
+ default:
+ goto no_more_values;
+ }
+ no_more_values:;
+ }
+ } while (*mode_string == ',');
+ if (*mode_string == 0)
+ return head;
+invalid:
+ mode_free (head);
+ return MODE_INVALID;
+}
+
+/* Return a file mode change operation that sets permissions to match those
+ of REF_FILE. Return MODE_BAD_REFERENCE if REF_FILE can't be accessed. */
+
+struct mode_change *
+mode_create_from_ref (const char *ref_file)
+{
+ struct mode_change *change; /* the only change element */
+ struct stat ref_stats;
+
+ if (stat (ref_file, &ref_stats))
+ return MODE_BAD_REFERENCE;
+
+ change = talloc (struct mode_change);
+
+ if (change == NULL)
+ return MODE_MEMORY_EXHAUSTED;
+
+ change->op = '=';
+ change->flags = 0;
+ change->affected = CHMOD_MODE_BITS;
+ change->value = ref_stats.st_mode;
+ change->next = NULL;
+
+ return change;
+}
+
+/* Return file mode OLDMODE, adjusted as indicated by the list of change
+ operations CHANGES. If OLDMODE is a directory, the type `X'
+ change affects it even if no execute bits were set in OLDMODE.
+ The returned value has the S_IFMT bits cleared. */
+
+mode_t
+mode_adjust (mode_t oldmode, const struct mode_change *changes)
+{
+ mode_t newmode; /* The adjusted mode and one operand. */
+ mode_t value; /* The other operand. */
+
+ newmode = oldmode & CHMOD_MODE_BITS;
+
+ for (; changes; changes = changes->next)
+ {
+ if (changes->flags & MODE_COPY_EXISTING)
+ {
+ /* Isolate in `value' the bits in `newmode' to copy, given in
+ the mask `changes->value'. */
+ value = newmode & changes->value;
+
+ if (changes->value & S_IRWXU)
+ /* Copy `u' permissions onto `g' and `o'. */
+ value |= ((value & S_IRUSR ? S_IRGRP | S_IROTH : 0)
+ | (value & S_IWUSR ? S_IWGRP | S_IROTH : 0)
+ | (value & S_IXUSR ? S_IXGRP | S_IXOTH : 0));
+ else if (changes->value & S_IRWXG)
+ /* Copy `g' permissions onto `u' and `o'. */
+ value |= ((value & S_IRGRP ? S_IRUSR | S_IROTH : 0)
+ | (value & S_IWGRP ? S_IWUSR | S_IROTH : 0)
+ | (value & S_IXGRP ? S_IXUSR | S_IXOTH : 0));
+ else
+ /* Copy `o' permissions onto `u' and `g'. */
+ value |= ((value & S_IROTH ? S_IRUSR | S_IRGRP : 0)
+ | (value & S_IWOTH ? S_IWUSR | S_IRGRP : 0)
+ | (value & S_IXOTH ? S_IXUSR | S_IXGRP : 0));
+
+ /* In order to change only `u', `g', or `o' permissions,
+ or some combination thereof, clear unselected bits.
+ This cannot be done in mode_compile because the value
+ to which the `changes->affected' mask is applied depends
+ on the old mode of each file. */
+ value &= changes->affected;
+ }
+ else
+ {
+ value = changes->value;
+ /* If `X', do not affect the execute bits if the file is not a
+ directory and no execute bits are already set. */
+ if ((changes->flags & MODE_X_IF_ANY_X)
+ && !S_ISDIR (oldmode)
+ && (newmode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)
+ /* Clear the execute bits. */
+ value &= ~ (S_IXUSR | S_IXGRP | S_IXOTH);
+ }
+
+ switch (changes->op)
+ {
+ case '=':
+ /* Preserve the previous values in `newmode' of bits that are
+ not affected by this change operation. */
+ newmode = (newmode & ~changes->affected) | value;
+ break;
+ case '+':
+ newmode |= value;
+ break;
+ case '-':
+ newmode &= ~value;
+ break;
+ }
+ }
+ return newmode;
+}
+
+/* Free the memory used by the list of file mode change operations
+ CHANGES. */
+
+void
+mode_free (register struct mode_change *changes)
+{
+ register struct mode_change *next;
+
+ while (changes)
+ {
+ next = changes->next;
+ free (changes);
+ changes = next;
+ }
+}
diff --git a/contrib/tar/lib/modechange.h b/contrib/tar/lib/modechange.h
new file mode 100644
index 0000000..922f85a
--- /dev/null
+++ b/contrib/tar/lib/modechange.h
@@ -0,0 +1,71 @@
+/* modechange.h -- definitions for file mode manipulation
+ Copyright (C) 1989, 1990, 1997 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Masks for the `flags' field in a `struct mode_change'. */
+
+#if ! defined MODECHANGE_H_
+# define MODECHANGE_H_
+
+# if HAVE_CONFIG_H
+# include <config.h>
+# endif
+
+# include <sys/types.h>
+
+/* Affect the execute bits only if at least one execute bit is set already,
+ or if the file is a directory. */
+# define MODE_X_IF_ANY_X 01
+
+/* If set, copy some existing permissions for u, g, or o onto the other two.
+ Which of u, g, or o is copied is determined by which bits are set in the
+ `value' field. */
+# define MODE_COPY_EXISTING 02
+
+struct mode_change
+{
+ char op; /* One of "=+-". */
+ char flags; /* Special operations. */
+ mode_t affected; /* Set for u/g/o/s/s/t, if to be affected. */
+ mode_t value; /* Bits to add/remove. */
+ struct mode_change *next; /* Link to next change in list. */
+};
+
+/* Masks for mode_compile argument. */
+# define MODE_MASK_EQUALS 1
+# define MODE_MASK_PLUS 2
+# define MODE_MASK_MINUS 4
+# define MODE_MASK_ALL (MODE_MASK_EQUALS | MODE_MASK_PLUS | MODE_MASK_MINUS)
+
+/* Error return values for mode_compile. */
+# define MODE_INVALID (struct mode_change *) 0
+# define MODE_MEMORY_EXHAUSTED (struct mode_change *) 1
+# define MODE_BAD_REFERENCE (struct mode_change *) 2
+
+# ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+# endif
+
+struct mode_change *mode_compile PARAMS ((const char *, unsigned));
+struct mode_change *mode_create_from_ref PARAMS ((const char *));
+mode_t mode_adjust PARAMS ((mode_t, const struct mode_change *));
+void mode_free PARAMS ((struct mode_change *));
+
+#endif
diff --git a/contrib/tar/lib/msleep.c b/contrib/tar/lib/msleep.c
new file mode 100644
index 0000000..38dfed2
--- /dev/null
+++ b/contrib/tar/lib/msleep.c
@@ -0,0 +1,131 @@
+/* Sleep a given number of milliseconds.
+ Copyright (C) 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
+ François Pinard <pinard@iro.umontreal.ca>, 1992.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* This code is heavily borrowed from Taylor UUCP 1.03. Ian picks one of
+ usleep, nap, napms, poll, select and sleep, in decreasing order of
+ preference. The sleep function is always available. */
+
+/* In many cases, we will sleep if the wanted number of milliseconds
+ is higher than this value. */
+#define THRESHOLD_FOR_SLEEP 30000
+
+/* Include some header files. */
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_POLL
+# if HAVE_STROPTS_H
+# include <stropts.h>
+# endif
+# if HAVE_POLL_H
+# include <sys/types.h>
+# include <poll.h>
+# endif
+# if !HAVE_STROPTS_H && !HAVE_POLL_H
+/* We need a definition for struct pollfd, although it doesn't matter
+ what it contains. */
+struct pollfd
+{
+ int idummy;
+};
+# endif
+#else
+# if HAVE_SELECT
+# include <sys/time.h>
+# endif
+#endif
+
+/*---------------------------------------.
+| Sleep a given number of milliseconds. |
+`---------------------------------------*/
+
+void
+msleep (milliseconds)
+ int milliseconds;
+{
+#if HAVE_USLEEP
+
+ if (milliseconds > 0)
+ usleep (milliseconds * (long) 1000);
+
+#else
+# if HAVE_NAP
+
+ if (milliseconds > 0)
+ nap ((long) milliseconds);
+
+# else
+# if HAVE_NAPMS
+
+ if (milliseconds >= THRESHOLD_FOR_SLEEP)
+ {
+ sleep (milliseconds / 1000);
+ milliseconds %= 1000;
+ }
+ if (milliseconds > 0)
+ napms (milliseconds);
+
+# else
+# if HAVE_POLL
+
+ struct pollfd sdummy; /* poll(2) checks this address */
+
+ if (milliseconds >= THRESHOLD_FOR_SLEEP)
+ {
+ sleep (milliseconds / 1000);
+ milliseconds %= 1000;
+ }
+ if (milliseconds > 0)
+ poll (&sdummy, 0, milliseconds);
+
+# else
+# if HAVE_SELECT
+
+ struct timeval s;
+
+ if (milliseconds >= THRESHOLD_FOR_SLEEP)
+ {
+ sleep (milliseconds / 1000);
+ milliseconds %= 1000;
+ }
+ if (milliseconds > 0)
+ {
+ s.tv_sec = milliseconds / 1000;
+ s.tv_usec = (milliseconds % 1000) * (long) 1000;
+ select (0, NULL, NULL, NULL, &s);
+ }
+
+# else
+
+ /* Round the time up to the next full second. */
+
+ if (milliseconds > 0)
+ sleep ((milliseconds + 999) / 1000);
+
+# endif
+# endif
+# endif
+# endif
+#endif
+}
diff --git a/contrib/tar/lib/prepargs.c b/contrib/tar/lib/prepargs.c
new file mode 100644
index 0000000..2003b33
--- /dev/null
+++ b/contrib/tar/lib/prepargs.c
@@ -0,0 +1,95 @@
+/* Parse arguments from a string and prepend them to an argv.
+ Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+/* Written by Paul Eggert <eggert@twinsun.com>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "prepargs.h"
+#include <sys/types.h>
+#include <xalloc.h>
+
+#if HAVE_STRING_H
+# include <string.h>
+#endif
+
+#include <ctype.h>
+
+/* IN_CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given
+ as an argument to <ctype.h> macros like "isspace". */
+#ifdef STDC_HEADERS
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) ((c) <= 0177)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+
+/* Find the white-space-separated options specified by OPTIONS, and
+ using BUF to store copies of these options, set ARGV[0], ARGV[1],
+ etc. to the option copies. Return the number N of options found.
+ Do not set ARGV[N]. If ARGV is null, do not store ARGV[0]
+ etc. Backslash can be used to escape whitespace (and backslashes). */
+static int
+prepend_args (char const *options, char *buf, char **argv)
+{
+ char const *o = options;
+ char *b = buf;
+ int n = 0;
+
+ for (;;)
+ {
+ while (ISSPACE ((unsigned char) *o))
+ o++;
+ if (!*o)
+ return n;
+ if (argv)
+ argv[n] = b;
+ n++;
+
+ do
+ if ((*b++ = *o++) == '\\' && *o)
+ b[-1] = *o++;
+ while (*o && ! ISSPACE ((unsigned char) *o));
+
+ *b++ = '\0';
+ }
+}
+
+/* Prepend the whitespace-separated options in OPTIONS to the argument
+ vector of a main program with argument count *PARGC and argument
+ vector *PARGV. */
+void
+prepend_default_options (char const *options, int *pargc, char ***pargv)
+{
+ if (options)
+ {
+ char *buf = xmalloc (strlen (options) + 1);
+ int prepended = prepend_args (options, buf, (char **) 0);
+ int argc = *pargc;
+ char * const *argv = *pargv;
+ char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp);
+ *pargc = prepended + argc;
+ *pargv = pp;
+ *pp++ = *argv++;
+ pp += prepend_args (options, buf, pp);
+ while ((*pp++ = *argv++))
+ continue;
+ }
+}
diff --git a/contrib/tar/lib/prepargs.h b/contrib/tar/lib/prepargs.h
new file mode 100644
index 0000000..ce93ea8
--- /dev/null
+++ b/contrib/tar/lib/prepargs.h
@@ -0,0 +1,3 @@
+/* Parse arguments from a string and prepend them to an argv. */
+
+void prepend_default_options (char const *, int *, char ***);
diff --git a/contrib/tar/lib/print-copyr.c b/contrib/tar/lib/print-copyr.c
new file mode 100644
index 0000000..6abaccf
--- /dev/null
+++ b/contrib/tar/lib/print-copyr.c
@@ -0,0 +1,52 @@
+/* Print a copyright notice suitable for the current locale.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Paul Eggert. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "unicodeio.h"
+#include "print-copyr.h"
+
+#include <stdio.h>
+
+#define COPYRIGHT_SIGN 0x00A9
+
+/* Print "(C)". */
+
+static int
+print_parenthesized_c (unsigned int code, void *callback_arg)
+{
+ FILE *stream = callback_arg;
+ return fputs ("(C)", stream);
+}
+
+/* Print "Copyright (C) " followed by NOTICE and then a newline,
+ transliterating "(C)" to an actual copyright sign (C-in-a-circle)
+ if possible. */
+
+void
+print_copyright (char const *notice)
+{
+ fputs ("Copyright ", stdout);
+ unicode_to_mb (COPYRIGHT_SIGN, print_unicode_success, print_parenthesized_c,
+ stdout);
+ fputc (' ', stdout);
+ puts (notice);
+}
diff --git a/contrib/tar/lib/print-copyr.h b/contrib/tar/lib/print-copyr.h
new file mode 100644
index 0000000..ff98158
--- /dev/null
+++ b/contrib/tar/lib/print-copyr.h
@@ -0,0 +1,9 @@
+# ifndef PARAMS
+# if PROTOTYPES || (defined (__STDC__) && __STDC__)
+# define PARAMS(args) args
+# else
+# define PARAMS(args) ()
+# endif
+# endif
+
+void print_copyright PARAMS((char const *));
diff --git a/contrib/tar/lib/quote.c b/contrib/tar/lib/quote.c
new file mode 100644
index 0000000..0ce935c
--- /dev/null
+++ b/contrib/tar/lib/quote.c
@@ -0,0 +1,28 @@
+/* Written by Paul Eggert <eggert@twinsun.com> */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if HAVE_STDDEF_H
+# include <stddef.h> /* For the definition of size_t on windows w/MSVC. */
+#endif
+#include <sys/types.h>
+#include <quotearg.h>
+#include <quote.h>
+
+/* Return an unambiguous printable representated, allocated in slot N,
+ for NAME, suitable for diagnostics. */
+char const *
+quote_n (int n, char const *name)
+{
+ return quotearg_n_style (n, locale_quoting_style, name);
+}
+
+/* Return an unambiguous printable representation of NAME, suitable
+ for diagnostics. */
+char const *
+quote (char const *name)
+{
+ return quote_n (0, name);
+}
diff --git a/contrib/tar/lib/quote.h b/contrib/tar/lib/quote.h
new file mode 100644
index 0000000..5de896b
--- /dev/null
+++ b/contrib/tar/lib/quote.h
@@ -0,0 +1,12 @@
+/* prototypes for quote.c */
+
+#ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+#endif
+
+char const *quote_n PARAMS ((int n, char const *name));
+char const *quote PARAMS ((char const *name));
diff --git a/contrib/tar/lib/quotearg.c b/contrib/tar/lib/quotearg.c
new file mode 100644
index 0000000..ca42365
--- /dev/null
+++ b/contrib/tar/lib/quotearg.c
@@ -0,0 +1,622 @@
+/* quotearg.c - quote arguments for output
+ Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Paul Eggert <eggert@twinsun.com> */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if HAVE_STDDEF_H
+# include <stddef.h> /* For the definition of size_t on windows w/MSVC. */
+#endif
+#include <sys/types.h>
+#include <quotearg.h>
+#include <xalloc.h>
+
+#include <ctype.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(text) gettext (text)
+#else
+# define _(text) text
+#endif
+#define N_(text) text
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#ifndef CHAR_BIT
+# define CHAR_BIT 8
+#endif
+#ifndef UCHAR_MAX
+# define UCHAR_MAX ((unsigned char) -1)
+#endif
+
+#if HAVE_C_BACKSLASH_A
+# define ALERT_CHAR '\a'
+#else
+# define ALERT_CHAR '\7'
+#endif
+
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#if HAVE_STRING_H
+# include <string.h>
+#endif
+
+#if HAVE_WCHAR_H
+
+/* BSD/OS 4.1 wchar.h requires FILE and struct tm to be declared. */
+# include <stdio.h>
+# include <time.h>
+
+# include <wchar.h>
+#endif
+
+#if !HAVE_MBRTOWC
+/* Disable multibyte processing entirely. Since MB_CUR_MAX is 1, the
+ other macros are defined only for documentation and to satisfy C
+ syntax. */
+# undef MB_CUR_MAX
+# define MB_CUR_MAX 1
+# define mbrtowc(pwc, s, n, ps) ((*(pwc) = *(s)) != 0)
+# define iswprint(wc) ISPRINT ((unsigned char) (wc))
+# undef HAVE_MBSINIT
+#endif
+
+#if !defined mbsinit && !HAVE_MBSINIT
+# define mbsinit(ps) 1
+#endif
+
+#ifndef iswprint
+# if HAVE_WCTYPE_H
+# include <wctype.h>
+# endif
+# if !defined iswprint && !HAVE_ISWPRINT
+# define iswprint(wc) 1
+# endif
+#endif
+
+#define INT_BITS (sizeof (int) * CHAR_BIT)
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+#endif
+
+/* Undefine to protect against the definition in wctype.h of solaris2.6. */
+#undef ISPRINT
+#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
+
+struct quoting_options
+{
+ /* Basic quoting style. */
+ enum quoting_style style;
+
+ /* Quote the characters indicated by this bit vector even if the
+ quoting style would not normally require them to be quoted. */
+ int quote_these_too[(UCHAR_MAX / INT_BITS) + 1];
+};
+
+/* Names of quoting styles. */
+char const *const quoting_style_args[] =
+{
+ "literal",
+ "shell",
+ "shell-always",
+ "c",
+ "escape",
+ "locale",
+ "clocale",
+ 0
+};
+
+/* Correspondences to quoting style names. */
+enum quoting_style const quoting_style_vals[] =
+{
+ literal_quoting_style,
+ shell_quoting_style,
+ shell_always_quoting_style,
+ c_quoting_style,
+ escape_quoting_style,
+ locale_quoting_style,
+ clocale_quoting_style
+};
+
+/* The default quoting options. */
+static struct quoting_options default_quoting_options;
+
+/* Allocate a new set of quoting options, with contents initially identical
+ to O if O is not null, or to the default if O is null.
+ It is the caller's responsibility to free the result. */
+struct quoting_options *
+clone_quoting_options (struct quoting_options *o)
+{
+ struct quoting_options *p
+ = (struct quoting_options *) xmalloc (sizeof (struct quoting_options));
+ *p = *(o ? o : &default_quoting_options);
+ return p;
+}
+
+/* Get the value of O's quoting style. If O is null, use the default. */
+enum quoting_style
+get_quoting_style (struct quoting_options *o)
+{
+ return (o ? o : &default_quoting_options)->style;
+}
+
+/* In O (or in the default if O is null),
+ set the value of the quoting style to S. */
+void
+set_quoting_style (struct quoting_options *o, enum quoting_style s)
+{
+ (o ? o : &default_quoting_options)->style = s;
+}
+
+/* In O (or in the default if O is null),
+ set the value of the quoting options for character C to I.
+ Return the old value. Currently, the only values defined for I are
+ 0 (the default) and 1 (which means to quote the character even if
+ it would not otherwise be quoted). */
+int
+set_char_quoting (struct quoting_options *o, char c, int i)
+{
+ unsigned char uc = c;
+ int *p = (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS;
+ int shift = uc % INT_BITS;
+ int r = (*p >> shift) & 1;
+ *p ^= ((i & 1) ^ r) << shift;
+ return r;
+}
+
+/* MSGID approximates a quotation mark. Return its translation if it
+ has one; otherwise, return either it or "\"", depending on S. */
+static char const *
+gettext_quote (char const *msgid, enum quoting_style s)
+{
+ char const *translation = _(msgid);
+ if (translation == msgid && s == clocale_quoting_style)
+ translation = "\"";
+ return translation;
+}
+
+/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
+ argument ARG (of size ARGSIZE), using QUOTING_STYLE and the
+ non-quoting-style part of O to control quoting.
+ Terminate the output with a null character, and return the written
+ size of the output, not counting the terminating null.
+ If BUFFERSIZE is too small to store the output string, return the
+ value that would have been returned had BUFFERSIZE been large enough.
+ If ARGSIZE is -1, use the string length of the argument for ARGSIZE.
+
+ This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG,
+ ARGSIZE, O), except it uses QUOTING_STYLE instead of the quoting
+ style specified by O, and O may not be null. */
+
+static size_t
+quotearg_buffer_restyled (char *buffer, size_t buffersize,
+ char const *arg, size_t argsize,
+ enum quoting_style quoting_style,
+ struct quoting_options const *o)
+{
+ size_t i;
+ size_t len = 0;
+ char const *quote_string = 0;
+ size_t quote_string_len = 0;
+ int backslash_escapes = 0;
+ int unibyte_locale = MB_CUR_MAX == 1;
+
+#define STORE(c) \
+ do \
+ { \
+ if (len < buffersize) \
+ buffer[len] = (c); \
+ len++; \
+ } \
+ while (0)
+
+ switch (quoting_style)
+ {
+ case c_quoting_style:
+ STORE ('"');
+ backslash_escapes = 1;
+ quote_string = "\"";
+ quote_string_len = 1;
+ break;
+
+ case escape_quoting_style:
+ backslash_escapes = 1;
+ break;
+
+ case locale_quoting_style:
+ case clocale_quoting_style:
+ {
+ /* Get translations for open and closing quotation marks.
+
+ The message catalog should translate "`" to a left
+ quotation mark suitable for the locale, and similarly for
+ "'". If the catalog has no translation,
+ locale_quoting_style quotes `like this', and
+ clocale_quoting_style quotes "like this".
+
+ For example, an American English Unicode locale should
+ translate "`" to U+201C (LEFT DOUBLE QUOTATION MARK), and
+ should translate "'" to U+201D (RIGHT DOUBLE QUOTATION
+ MARK). A British English Unicode locale should instead
+ translate these to U+2018 (LEFT SINGLE QUOTATION MARK) and
+ U+2019 (RIGHT SINGLE QUOTATION MARK), respectively. */
+
+ char const *left = gettext_quote (N_("`"), quoting_style);
+ char const *right = gettext_quote (N_("'"), quoting_style);
+ for (quote_string = left; *quote_string; quote_string++)
+ STORE (*quote_string);
+ backslash_escapes = 1;
+ quote_string = right;
+ quote_string_len = strlen (quote_string);
+ }
+ break;
+
+ case shell_always_quoting_style:
+ STORE ('\'');
+ quote_string = "'";
+ quote_string_len = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ for (i = 0; ! (argsize == (size_t) -1 ? arg[i] == '\0' : i == argsize); i++)
+ {
+ unsigned char c;
+ unsigned char esc;
+
+ if (backslash_escapes
+ && quote_string_len
+ && i + quote_string_len <= argsize
+ && memcmp (arg + i, quote_string, quote_string_len) == 0)
+ STORE ('\\');
+
+ c = arg[i];
+ switch (c)
+ {
+ case '?':
+ switch (quoting_style)
+ {
+ case shell_quoting_style:
+ goto use_shell_always_quoting_style;
+
+ case c_quoting_style:
+ if (i + 2 < argsize && arg[i + 1] == '?')
+ switch (arg[i + 2])
+ {
+ case '!': case '\'':
+ case '(': case ')': case '-': case '/':
+ case '<': case '=': case '>':
+ /* Escape the second '?' in what would otherwise be
+ a trigraph. */
+ i += 2;
+ c = arg[i + 2];
+ STORE ('?');
+ STORE ('\\');
+ STORE ('?');
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case ALERT_CHAR: esc = 'a'; goto c_escape;
+ case '\b': esc = 'b'; goto c_escape;
+ case '\f': esc = 'f'; goto c_escape;
+ case '\n': esc = 'n'; goto c_and_shell_escape;
+ case '\r': esc = 'r'; goto c_and_shell_escape;
+ case '\t': esc = 't'; goto c_and_shell_escape;
+ case '\v': esc = 'v'; goto c_escape;
+ case '\\': esc = c; goto c_and_shell_escape;
+
+ c_and_shell_escape:
+ if (quoting_style == shell_quoting_style)
+ goto use_shell_always_quoting_style;
+ c_escape:
+ if (backslash_escapes)
+ {
+ c = esc;
+ goto store_escape;
+ }
+ break;
+
+ case '#': case '~':
+ if (i != 0)
+ break;
+ /* Fall through. */
+ case ' ':
+ case '!': /* special in bash */
+ case '"': case '$': case '&':
+ case '(': case ')': case '*': case ';':
+ case '<': case '>': case '[':
+ case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
+ case '`': case '|':
+ /* A shell special character. In theory, '$' and '`' could
+ be the first bytes of multibyte characters, which means
+ we should check them with mbrtowc, but in practice this
+ doesn't happen so it's not worth worrying about. */
+ if (quoting_style == shell_quoting_style)
+ goto use_shell_always_quoting_style;
+ break;
+
+ case '\'':
+ switch (quoting_style)
+ {
+ case shell_quoting_style:
+ goto use_shell_always_quoting_style;
+
+ case shell_always_quoting_style:
+ STORE ('\'');
+ STORE ('\\');
+ STORE ('\'');
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case '%': case '+': case ',': case '-': case '.': case '/':
+ case '0': case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9': case ':': case '=':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+ case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+ case 'Y': case 'Z': case ']': case '_': case 'a': case 'b':
+ case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
+ case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
+ case 'o': case 'p': case 'q': case 'r': case 's': case 't':
+ case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
+ case '{': case '}':
+ /* These characters don't cause problems, no matter what the
+ quoting style is. They cannot start multibyte sequences. */
+ break;
+
+ default:
+ /* If we have a multibyte sequence, copy it until we reach
+ its end, find an error, or come back to the initial shift
+ state. For C-like styles, if the sequence has
+ unprintable characters, escape the whole sequence, since
+ we can't easily escape single characters within it. */
+ {
+ /* Length of multibyte sequence found so far. */
+ size_t m;
+
+ int printable;
+
+ if (unibyte_locale)
+ {
+ m = 1;
+ printable = ISPRINT (c);
+ }
+ else
+ {
+ mbstate_t mbstate;
+ memset (&mbstate, 0, sizeof mbstate);
+
+ m = 0;
+ printable = 1;
+ if (argsize == (size_t) -1)
+ argsize = strlen (arg);
+
+ do
+ {
+ wchar_t w;
+ size_t bytes = mbrtowc (&w, &arg[i + m],
+ argsize - (i + m), &mbstate);
+ if (bytes == 0)
+ break;
+ else if (bytes == (size_t) -1)
+ {
+ printable = 0;
+ break;
+ }
+ else if (bytes == (size_t) -2)
+ {
+ printable = 0;
+ while (i + m < argsize && arg[i + m])
+ m++;
+ break;
+ }
+ else
+ {
+ if (! iswprint (w))
+ printable = 0;
+ m += bytes;
+ }
+ }
+ while (! mbsinit (&mbstate));
+ }
+
+ if (1 < m || (backslash_escapes && ! printable))
+ {
+ /* Output a multibyte sequence, or an escaped
+ unprintable unibyte character. */
+ size_t ilim = i + m;
+
+ for (;;)
+ {
+ if (backslash_escapes && ! printable)
+ {
+ STORE ('\\');
+ STORE ('0' + (c >> 6));
+ STORE ('0' + ((c >> 3) & 7));
+ c = '0' + (c & 7);
+ }
+ if (ilim <= i + 1)
+ break;
+ STORE (c);
+ c = arg[++i];
+ }
+
+ goto store_c;
+ }
+ }
+ }
+
+ if (! (backslash_escapes
+ && o->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS))))
+ goto store_c;
+
+ store_escape:
+ STORE ('\\');
+
+ store_c:
+ STORE (c);
+ }
+
+ if (quote_string)
+ for (; *quote_string; quote_string++)
+ STORE (*quote_string);
+
+ if (len < buffersize)
+ buffer[len] = '\0';
+ return len;
+
+ use_shell_always_quoting_style:
+ return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
+ shell_always_quoting_style, o);
+}
+
+/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
+ argument ARG (of size ARGSIZE), using O to control quoting.
+ If O is null, use the default.
+ Terminate the output with a null character, and return the written
+ size of the output, not counting the terminating null.
+ If BUFFERSIZE is too small to store the output string, return the
+ value that would have been returned had BUFFERSIZE been large enough.
+ If ARGSIZE is -1, use the string length of the argument for ARGSIZE. */
+size_t
+quotearg_buffer (char *buffer, size_t buffersize,
+ char const *arg, size_t argsize,
+ struct quoting_options const *o)
+{
+ struct quoting_options const *p = o ? o : &default_quoting_options;
+ return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
+ p->style, p);
+}
+
+/* Use storage slot N to return a quoted version of the string ARG.
+ OPTIONS specifies the quoting options.
+ The returned value points to static storage that can be
+ reused by the next call to this function with the same value of N.
+ N must be nonnegative. N is deliberately declared with type "int"
+ to allow for future extensions (using negative values). */
+static char *
+quotearg_n_options (int n, char const *arg,
+ struct quoting_options const *options)
+{
+ /* Preallocate a slot 0 buffer, so that the caller can always quote
+ one small component of a "memory exhausted" message in slot 0. */
+ static char slot0[256];
+ static unsigned int nslots = 1;
+ struct slotvec
+ {
+ size_t size;
+ char *val;
+ };
+ static struct slotvec slotvec0 = {sizeof slot0, slot0};
+ static struct slotvec *slotvec = &slotvec0;
+
+ if (nslots <= n)
+ {
+ int n1 = n + 1;
+ size_t s = n1 * sizeof (struct slotvec);
+ if (! (0 < n1 && n1 == s / sizeof (struct slotvec)))
+ abort ();
+ if (slotvec == &slotvec0)
+ {
+ slotvec = (struct slotvec *) xmalloc (sizeof (struct slotvec));
+ *slotvec = slotvec0;
+ }
+ slotvec = (struct slotvec *) xrealloc (slotvec, s);
+ memset (slotvec + nslots, 0, (n1 - nslots) * sizeof (struct slotvec));
+ nslots = n;
+ }
+
+ {
+ size_t size = slotvec[n].size;
+ char *val = slotvec[n].val;
+ size_t qsize = quotearg_buffer (val, size, arg, (size_t) -1, options);
+
+ if (size <= qsize)
+ {
+ slotvec[n].size = size = qsize + 1;
+ slotvec[n].val = val = xrealloc (val == slot0 ? 0 : val, size);
+ quotearg_buffer (val, size, arg, (size_t) -1, options);
+ }
+
+ return val;
+ }
+}
+
+char *
+quotearg_n (unsigned int n, char const *arg)
+{
+ return quotearg_n_options (n, arg, &default_quoting_options);
+}
+
+char *
+quotearg (char const *arg)
+{
+ return quotearg_n (0, arg);
+}
+
+char *
+quotearg_n_style (unsigned int n, enum quoting_style s, char const *arg)
+{
+ struct quoting_options o;
+ o.style = s;
+ memset (o.quote_these_too, 0, sizeof o.quote_these_too);
+ return quotearg_n_options (n, arg, &o);
+}
+
+char *
+quotearg_style (enum quoting_style s, char const *arg)
+{
+ return quotearg_n_style (0, s, arg);
+}
+
+char *
+quotearg_char (char const *arg, char ch)
+{
+ struct quoting_options options;
+ options = default_quoting_options;
+ set_char_quoting (&options, ch, 1);
+ return quotearg_n_options (0, arg, &options);
+}
+
+char *
+quotearg_colon (char const *arg)
+{
+ return quotearg_char (arg, ':');
+}
diff --git a/contrib/tar/lib/quotearg.h b/contrib/tar/lib/quotearg.h
new file mode 100644
index 0000000..f6463b1
--- /dev/null
+++ b/contrib/tar/lib/quotearg.h
@@ -0,0 +1,110 @@
+/* quotearg.h - quote arguments for output
+ Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Paul Eggert <eggert@twinsun.com> */
+
+/* Basic quoting styles. */
+enum quoting_style
+ {
+ literal_quoting_style, /* --quoting-style=literal */
+ shell_quoting_style, /* --quoting-style=shell */
+ shell_always_quoting_style, /* --quoting-style=shell-always */
+ c_quoting_style, /* --quoting-style=c */
+ escape_quoting_style, /* --quoting-style=escape */
+ locale_quoting_style, /* --quoting-style=locale */
+ clocale_quoting_style /* --quoting-style=clocale */
+ };
+
+/* For now, --quoting-style=literal is the default, but this may change. */
+#ifndef DEFAULT_QUOTING_STYLE
+# define DEFAULT_QUOTING_STYLE literal_quoting_style
+#endif
+
+/* Names of quoting styles and their corresponding values. */
+extern char const *const quoting_style_args[];
+extern enum quoting_style const quoting_style_vals[];
+
+struct quoting_options;
+
+#ifndef PARAMS
+# if defined PROTOTYPES || defined __STDC__
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+#endif
+
+/* The functions listed below set and use a hidden variable
+ that contains the default quoting style options. */
+
+/* Allocate a new set of quoting options, with contents initially identical
+ to O if O is not null, or to the default if O is null.
+ It is the caller's responsibility to free the result. */
+struct quoting_options *clone_quoting_options
+ PARAMS ((struct quoting_options *o));
+
+/* Get the value of O's quoting style. If O is null, use the default. */
+enum quoting_style get_quoting_style PARAMS ((struct quoting_options *o));
+
+/* In O (or in the default if O is null),
+ set the value of the quoting style to S. */
+void set_quoting_style PARAMS ((struct quoting_options *o,
+ enum quoting_style s));
+
+/* In O (or in the default if O is null),
+ set the value of the quoting options for character C to I.
+ Return the old value. Currently, the only values defined for I are
+ 0 (the default) and 1 (which means to quote the character even if
+ it would not otherwise be quoted). */
+int set_char_quoting PARAMS ((struct quoting_options *o, char c, int i));
+
+/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
+ argument ARG (of size ARGSIZE), using O to control quoting.
+ If O is null, use the default.
+ Terminate the output with a null character, and return the written
+ size of the output, not counting the terminating null.
+ If BUFFERSIZE is too small to store the output string, return the
+ value that would have been returned had BUFFERSIZE been large enough.
+ If ARGSIZE is -1, use the string length of the argument for ARGSIZE. */
+size_t quotearg_buffer PARAMS ((char *buffer, size_t buffersize,
+ char const *arg, size_t argsize,
+ struct quoting_options const *o));
+
+/* Use storage slot N to return a quoted version of the string ARG.
+ Use the default quoting options.
+ The returned value points to static storage that can be
+ reused by the next call to this function with the same value of N.
+ N must be nonnegative. */
+char *quotearg_n PARAMS ((unsigned int n, char const *arg));
+
+/* Equivalent to quotearg_n (0, ARG). */
+char *quotearg PARAMS ((char const *arg));
+
+/* Use style S and storage slot N to return a quoted version of the string ARG.
+ This is like quotearg_n (N, ARG), except that it uses S with no other
+ options to specify the quoting method. */
+char *quotearg_n_style PARAMS ((unsigned int n, enum quoting_style s,
+ char const *arg));
+
+/* Equivalent to quotearg_n_style (0, S, ARG). */
+char *quotearg_style PARAMS ((enum quoting_style s, char const *arg));
+
+/* Like quotearg (ARG), except also quote any instances of CH. */
+char *quotearg_char PARAMS ((char const *arg, char ch));
+
+/* Equivalent to quotearg_char (ARG, ':'). */
+char *quotearg_colon PARAMS ((char const *arg));
diff --git a/contrib/tar/lib/readutmp.c b/contrib/tar/lib/readutmp.c
new file mode 100644
index 0000000..29b24a5
--- /dev/null
+++ b/contrib/tar/lib/readutmp.c
@@ -0,0 +1,133 @@
+/* GNU's read utmp module.
+ Copyright (C) 1992-2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by jla; revised by djm */
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+# include <string.h>
+#else
+# include <strings.h>
+#endif /* STDC_HEADERS || HAVE_STRING_H */
+
+#include "readutmp.h"
+
+char *xmalloc ();
+char *realloc ();
+
+/* Copy UT->ut_name into storage obtained from malloc. Then remove any
+ trailing spaces from the copy, NUL terminate it, and return the copy. */
+
+char *
+extract_trimmed_name (const STRUCT_UTMP *ut)
+{
+ char *p, *trimmed_name;
+
+ trimmed_name = xmalloc (sizeof (UT_USER (ut)) + 1);
+ strncpy (trimmed_name, UT_USER (ut), sizeof (UT_USER (ut)));
+ /* Append a trailing space character. Some systems pad names shorter than
+ the maximum with spaces, others pad with NULs. Remove any spaces. */
+ trimmed_name[sizeof (UT_USER (ut))] = ' ';
+ p = strchr (trimmed_name, ' ');
+ if (p != NULL)
+ *p = '\0';
+ return trimmed_name;
+}
+
+/* Read the utmp entries corresponding to file FILENAME into freshly-
+ malloc'd storage, set *UTMP_BUF to that pointer, set *N_ENTRIES to
+ the number of entries, and return zero. If there is any error,
+ return non-zero and don't modify the parameters. */
+
+#ifdef UTMP_NAME_FUNCTION
+
+int
+read_utmp (const char *filename, int *n_entries, STRUCT_UTMP **utmp_buf)
+{
+ int n_read;
+ STRUCT_UTMP *u;
+ STRUCT_UTMP *utmp = NULL;
+
+ /* Ignore the return value for now.
+ Solaris' utmpname returns 1 upon success -- which is contrary
+ to what the GNU libc version does. In addition, older GNU libc
+ versions are actually void. */
+ UTMP_NAME_FUNCTION (filename);
+
+ SET_UTMP_ENT ();
+
+ n_read = 0;
+ while ((u = GET_UTMP_ENT ()) != NULL)
+ {
+ ++n_read;
+ utmp = (STRUCT_UTMP *) realloc (utmp, n_read * sizeof (STRUCT_UTMP));
+ if (utmp == NULL)
+ return 1;
+ utmp[n_read - 1] = *u;
+ }
+
+ END_UTMP_ENT ();
+
+ *n_entries = n_read;
+ *utmp_buf = utmp;
+
+ return 0;
+}
+
+#else
+
+int
+read_utmp (const char *filename, int *n_entries, STRUCT_UTMP **utmp_buf)
+{
+ FILE *utmp;
+ struct stat file_stats;
+ size_t n_read;
+ size_t size;
+ STRUCT_UTMP *buf;
+
+ utmp = fopen (filename, "r");
+ if (utmp == NULL)
+ return 1;
+
+ fstat (fileno (utmp), &file_stats);
+ size = file_stats.st_size;
+ if (size > 0)
+ buf = (STRUCT_UTMP *) xmalloc (size);
+ else
+ {
+ fclose (utmp);
+ return 1;
+ }
+
+ /* Use < instead of != in case the utmp just grew. */
+ n_read = fread (buf, 1, size, utmp);
+ if (ferror (utmp) || fclose (utmp) == EOF
+ || n_read < size)
+ return 1;
+
+ *n_entries = size / sizeof (STRUCT_UTMP);
+ *utmp_buf = buf;
+
+ return 0;
+}
+
+#endif
diff --git a/contrib/tar/lib/realloc.c b/contrib/tar/lib/realloc.c
new file mode 100644
index 0000000..d0d3e4a
--- /dev/null
+++ b/contrib/tar/lib/realloc.c
@@ -0,0 +1,44 @@
+/* Work around bug on some systems where realloc (NULL, 0) fails.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* written by Jim Meyering */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+#undef realloc
+
+#include <sys/types.h>
+
+char *malloc ();
+char *realloc ();
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking. If N is zero, change it to 1. If P is NULL,
+ use malloc. */
+
+char *
+rpl_realloc (p, n)
+ char *p;
+ size_t n;
+{
+ if (n == 0)
+ n = 1;
+ if (p == 0)
+ return malloc (n);
+ return realloc (p, n);
+}
diff --git a/contrib/tar/lib/rename.c b/contrib/tar/lib/rename.c
new file mode 100644
index 0000000..13b86d0
--- /dev/null
+++ b/contrib/tar/lib/rename.c
@@ -0,0 +1,67 @@
+/* Work around the bug in some systems whereby rename fails when the source
+ path has a trailing slash. The rename from SunOS 4.1.1_U1 has this bug.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* written by Volker Borchert */
+
+#include <config.h>
+#include <stdio.h>
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#include "dirname.h"
+#include "xalloc.h"
+
+#ifndef HAVE_DECL_FREE
+"this configure-time declaration test was not run"
+#endif
+#if !HAVE_DECL_FREE
+void free ();
+#endif
+
+/* Rename the file SRC_PATH to DST_PATH, removing any trailing
+ slashes from SRC_PATH. Needed for SunOS 4.1.1_U1. */
+
+int
+rpl_rename (const char *src_path, const char *dst_path)
+{
+ char *src_temp;
+ int ret_val;
+ size_t s_len = strlen (src_path);
+
+ if (s_len && src_path[s_len - 1] == '/')
+ {
+ src_temp = xstrdup (src_path);
+ strip_trailing_slashes (src_temp);
+ }
+ else
+ src_temp = (char *) src_path;
+
+ ret_val = rename (src_temp, dst_path);
+
+ if (src_temp != src_path)
+ free (src_temp);
+
+ return ret_val;
+}
diff --git a/contrib/tar/lib/rmdir.c b/contrib/tar/lib/rmdir.c
new file mode 100644
index 0000000..2a92803
--- /dev/null
+++ b/contrib/tar/lib/rmdir.c
@@ -0,0 +1,87 @@
+/* BSD compatible remove directory function for System V
+ Copyright (C) 1988, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#if STAT_MACROS_BROKEN
+# undef S_ISDIR
+#endif
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+/* rmdir adapted from GNU tar. */
+
+/* Remove directory DPATH.
+ Return 0 if successful, -1 if not. */
+
+int
+rmdir (dpath)
+ char *dpath;
+{
+ pid_t cpid;
+ int status;
+ struct stat statbuf;
+
+ if (stat (dpath, &statbuf) != 0)
+ return -1; /* errno already set */
+
+ if (!S_ISDIR (statbuf.st_mode))
+ {
+ errno = ENOTDIR;
+ return -1;
+ }
+
+ cpid = fork ();
+ switch (cpid)
+ {
+ case -1: /* cannot fork */
+ return -1; /* errno already set */
+
+ case 0: /* child process */
+ execl ("/bin/rmdir", "rmdir", dpath, (char *) 0);
+ _exit (1);
+
+ default: /* parent process */
+
+ /* Wait for kid to finish. */
+
+ while (wait (&status) != cpid)
+ /* Do nothing. */ ;
+
+ if (status)
+ {
+
+ /* /bin/rmdir failed. */
+
+ errno = EIO;
+ return -1;
+ }
+ return 0;
+ }
+}
diff --git a/contrib/tar/lib/safe-read.c b/contrib/tar/lib/safe-read.c
new file mode 100644
index 0000000..e404586
--- /dev/null
+++ b/contrib/tar/lib/safe-read.c
@@ -0,0 +1,59 @@
+/* safe-read.c -- an interface to read that retries after interrupts
+ Copyright (C) 1993, 1994, 1998 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#include "safe-read.h"
+
+/* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted.
+ Return the actual number of bytes read, zero for EOF, or negative
+ for an error. */
+
+ssize_t
+safe_read (int desc, void *ptr, size_t len)
+{
+ ssize_t n_chars;
+
+ if (len <= 0)
+ return len;
+
+#ifdef EINTR
+ do
+ {
+ n_chars = read (desc, ptr, len);
+ }
+ while (n_chars < 0 && errno == EINTR);
+#else
+ n_chars = read (desc, ptr, len);
+#endif
+
+ return n_chars;
+}
diff --git a/contrib/tar/lib/safe-read.h b/contrib/tar/lib/safe-read.h
new file mode 100644
index 0000000..8e4b165
--- /dev/null
+++ b/contrib/tar/lib/safe-read.h
@@ -0,0 +1,10 @@
+#ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+#endif
+
+ssize_t
+safe_read PARAMS ((int desc, void *ptr, size_t len));
diff --git a/contrib/tar/lib/save-cwd.c b/contrib/tar/lib/save-cwd.c
new file mode 100644
index 0000000..b77edb3
--- /dev/null
+++ b/contrib/tar/lib/save-cwd.c
@@ -0,0 +1,153 @@
+/* save-cwd.c -- Save and restore current working directory.
+ Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Jim Meyering <meyering@na-net.ornl.gov>. */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#else
+# include <sys/file.h>
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#ifndef O_DIRECTORY
+# define O_DIRECTORY 0
+#endif
+
+#include "save-cwd.h"
+#include "error.h"
+
+char *xgetcwd PARAMS ((void));
+
+/* Record the location of the current working directory in CWD so that
+ the program may change to other directories and later use restore_cwd
+ to return to the recorded location. This function may allocate
+ space using malloc (via xgetcwd) or leave a file descriptor open;
+ use free_cwd to perform the necessary free or close. Upon failure,
+ no memory is allocated, any locally opened file descriptors are
+ closed; return non-zero -- in that case, free_cwd need not be
+ called, but doing so is ok. Otherwise, return zero. */
+
+int
+save_cwd (struct saved_cwd *cwd)
+{
+ static int have_working_fchdir = 1;
+
+ cwd->desc = -1;
+ cwd->name = NULL;
+
+ if (have_working_fchdir)
+ {
+#if HAVE_FCHDIR
+ cwd->desc = open (".", O_RDONLY | O_DIRECTORY);
+ if (cwd->desc < 0)
+ {
+ error (0, errno, "cannot open current directory");
+ return 1;
+ }
+
+# if __sun__ || sun
+ /* On SunOS 4, fchdir returns EINVAL if accounting is enabled,
+ so we have to fall back to chdir. */
+ if (fchdir (cwd->desc))
+ {
+ if (errno == EINVAL)
+ {
+ close (cwd->desc);
+ cwd->desc = -1;
+ have_working_fchdir = 0;
+ }
+ else
+ {
+ error (0, errno, "current directory");
+ close (cwd->desc);
+ cwd->desc = -1;
+ return 1;
+ }
+ }
+# endif /* __sun__ || sun */
+#else
+# define fchdir(x) (abort (), 0)
+ have_working_fchdir = 0;
+#endif
+ }
+
+ if (!have_working_fchdir)
+ {
+ cwd->name = xgetcwd ();
+ if (cwd->name == NULL)
+ {
+ error (0, errno, "cannot get current directory");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Change to recorded location, CWD, in directory hierarchy.
+ If "saved working directory", NULL))
+ */
+
+int
+restore_cwd (const struct saved_cwd *cwd, const char *dest, const char *from)
+{
+ int fail = 0;
+ if (cwd->desc >= 0)
+ {
+ if (fchdir (cwd->desc))
+ {
+ error (0, errno, "cannot return to %s%s%s",
+ (dest ? dest : "saved working directory"),
+ (from ? " from " : ""),
+ (from ? from : ""));
+ fail = 1;
+ }
+ }
+ else if (chdir (cwd->name) < 0)
+ {
+ error (0, errno, "%s", cwd->name);
+ fail = 1;
+ }
+ return fail;
+}
+
+void
+free_cwd (struct saved_cwd *cwd)
+{
+ if (cwd->desc >= 0)
+ close (cwd->desc);
+ if (cwd->name)
+ free (cwd->name);
+}
diff --git a/contrib/tar/lib/save-cwd.h b/contrib/tar/lib/save-cwd.h
new file mode 100644
index 0000000..4801a4d
--- /dev/null
+++ b/contrib/tar/lib/save-cwd.h
@@ -0,0 +1,23 @@
+#ifndef SAVE_CWD_H
+# define SAVE_CWD_H 1
+
+struct saved_cwd
+ {
+ int desc;
+ char *name;
+ };
+
+# ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+# endif
+
+int save_cwd PARAMS ((struct saved_cwd *cwd));
+int restore_cwd PARAMS ((const struct saved_cwd *cwd, const char *dest,
+ const char *from));
+void free_cwd PARAMS ((struct saved_cwd *cwd));
+
+#endif /* SAVE_CWD_H */
diff --git a/contrib/tar/lib/savedir.c b/contrib/tar/lib/savedir.c
new file mode 100644
index 0000000..112f5c0
--- /dev/null
+++ b/contrib/tar/lib/savedir.c
@@ -0,0 +1,129 @@
+/* savedir.c -- save the list of files in a directory in a string
+
+ Copyright 1990, 1997, 1998, 1999, 2000, 2001 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+#ifdef CLOSEDIR_VOID
+/* Fake a return value. */
+# define CLOSEDIR(d) (closedir (d), 0)
+#else
+# define CLOSEDIR(d) closedir (d)
+#endif
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif
+#ifndef NULL
+# define NULL 0
+#endif
+
+#include "savedir.h"
+#include "xalloc.h"
+
+/* Return a freshly allocated string containing the filenames
+ in directory DIR, separated by '\0' characters;
+ the end is marked by two '\0' characters in a row.
+ Return NULL (setting errno) if DIR cannot be opened, read, or closed. */
+
+#ifndef NAME_SIZE_DEFAULT
+# define NAME_SIZE_DEFAULT 512
+#endif
+
+char *
+savedir (const char *dir)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ char *name_space;
+ size_t allocated = NAME_SIZE_DEFAULT;
+ size_t used = 0;
+ int save_errno;
+
+ dirp = opendir (dir);
+ if (dirp == NULL)
+ return NULL;
+
+ name_space = xmalloc (allocated);
+
+ errno = 0;
+ while ((dp = readdir (dirp)) != NULL)
+ {
+ /* Skip "", ".", and "..". "" is returned by at least one buggy
+ implementation: Solaris 2.4 readdir on NFS filesystems. */
+ char const *entry = dp->d_name;
+ if (entry[entry[0] != '.' ? 0 : entry[1] != '.' ? 1 : 2] != '\0')
+ {
+ size_t entry_size = strlen (entry) + 1;
+ if (used + entry_size < used)
+ xalloc_die ();
+ if (allocated <= used + entry_size)
+ {
+ do
+ {
+ if (2 * allocated < allocated)
+ xalloc_die ();
+ allocated *= 2;
+ }
+ while (allocated <= used + entry_size);
+
+ name_space = xrealloc (name_space, allocated);
+ }
+ memcpy (name_space + used, entry, entry_size);
+ used += entry_size;
+ }
+ }
+ name_space[used] = '\0';
+ save_errno = errno;
+ if (CLOSEDIR (dirp) != 0)
+ save_errno = errno;
+ if (save_errno != 0)
+ {
+ free (name_space);
+ errno = save_errno;
+ return NULL;
+ }
+ return name_space;
+}
diff --git a/contrib/tar/lib/savedir.h b/contrib/tar/lib/savedir.h
new file mode 100644
index 0000000..03b41f5
--- /dev/null
+++ b/contrib/tar/lib/savedir.h
@@ -0,0 +1,14 @@
+#if !defined SAVEDIR_H_
+# define SAVEDIR_H_
+
+# ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+# endif
+
+char *savedir PARAMS ((const char *dir));
+
+#endif
diff --git a/contrib/tar/lib/stpcpy.c b/contrib/tar/lib/stpcpy.c
new file mode 100644
index 0000000..a01636c
--- /dev/null
+++ b/contrib/tar/lib/stpcpy.c
@@ -0,0 +1,50 @@
+/* stpcpy.c -- copy a string and return pointer to end of new string
+ Copyright (C) 1992, 1995, 1997, 1998 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#undef __stpcpy
+#undef stpcpy
+
+#ifndef weak_alias
+# define __stpcpy stpcpy
+#endif
+
+/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */
+char *
+__stpcpy (char *dest, const char *src)
+{
+ register char *d = dest;
+ register const char *s = src;
+
+ do
+ *d++ = *s;
+ while (*s++ != '\0');
+
+ return d - 1;
+}
+#ifdef weak_alias
+weak_alias (__stpcpy, stpcpy)
+#endif
diff --git a/contrib/tar/lib/strcasecmp.c b/contrib/tar/lib/strcasecmp.c
new file mode 100644
index 0000000..ae7601d
--- /dev/null
+++ b/contrib/tar/lib/strcasecmp.c
@@ -0,0 +1,66 @@
+/* strcasecmp.c -- case insensitive string comparator
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef LENGTH_LIMIT
+# define STRXCASECMP_FUNCTION strncasecmp
+# define STRXCASECMP_DECLARE_N , size_t n
+# define LENGTH_LIMIT_EXPR(Expr) Expr
+#else
+# define STRXCASECMP_FUNCTION strcasecmp
+# define STRXCASECMP_DECLARE_N /* empty */
+# define LENGTH_LIMIT_EXPR(Expr) 0
+#endif
+
+#include <sys/types.h>
+#include <ctype.h>
+
+#define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
+
+/* Compare {{no more than N characters of }}strings S1 and S2,
+ ignoring case, returning less than, equal to or
+ greater than zero if S1 is lexicographically less
+ than, equal to or greater than S2. */
+
+int
+STRXCASECMP_FUNCTION (const char *s1, const char *s2 STRXCASECMP_DECLARE_N)
+{
+ register const unsigned char *p1 = (const unsigned char *) s1;
+ register const unsigned char *p2 = (const unsigned char *) s2;
+ unsigned char c1, c2;
+
+ if (p1 == p2 || LENGTH_LIMIT_EXPR (n == 0))
+ return 0;
+
+ do
+ {
+ c1 = TOLOWER (*p1);
+ c2 = TOLOWER (*p2);
+
+ if (LENGTH_LIMIT_EXPR (--n == 0) || c1 == '\0')
+ break;
+
+ ++p1;
+ ++p2;
+ }
+ while (c1 == c2);
+
+ return c1 - c2;
+}
diff --git a/contrib/tar/lib/strncasecmp.c b/contrib/tar/lib/strncasecmp.c
new file mode 100644
index 0000000..68d95aa
--- /dev/null
+++ b/contrib/tar/lib/strncasecmp.c
@@ -0,0 +1,2 @@
+#define LENGTH_LIMIT
+#include "strcasecmp.c"
diff --git a/contrib/tar/lib/strstr.c b/contrib/tar/lib/strstr.c
new file mode 100644
index 0000000..c41e903
--- /dev/null
+++ b/contrib/tar/lib/strstr.c
@@ -0,0 +1,122 @@
+/* Copyright (C) 1994, 1999 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/*
+ * My personal strstr() implementation that beats most other algorithms.
+ * Until someone tells me otherwise, I assume that this is the
+ * fastest implementation of strstr() in C.
+ * I deliberately chose not to comment it. You should have at least
+ * as much fun trying to understand it, as I had to write it :-).
+ *
+ * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined _LIBC || defined HAVE_STRING_H
+# include <string.h>
+#endif
+#include <sys/types.h>
+
+typedef unsigned chartype;
+
+#undef strstr
+
+char *
+strstr (const char *phaystack, const char *pneedle)
+{
+ register const unsigned char *haystack, *needle;
+ register chartype b, c;
+
+ haystack = (const unsigned char *) phaystack;
+ needle = (const unsigned char *) pneedle;
+
+ b = *needle;
+ if (b != '\0')
+ {
+ haystack--; /* possible ANSI violation */
+ do
+ {
+ c = *++haystack;
+ if (c == '\0')
+ goto ret0;
+ }
+ while (c != b);
+
+ c = *++needle;
+ if (c == '\0')
+ goto foundneedle;
+ ++needle;
+ goto jin;
+
+ for (;;)
+ {
+ register chartype a;
+ register const unsigned char *rhaystack, *rneedle;
+
+ do
+ {
+ a = *++haystack;
+ if (a == '\0')
+ goto ret0;
+ if (a == b)
+ break;
+ a = *++haystack;
+ if (a == '\0')
+ goto ret0;
+shloop:; }
+ while (a != b);
+
+jin: a = *++haystack;
+ if (a == '\0')
+ goto ret0;
+
+ if (a != c)
+ goto shloop;
+
+ rhaystack = haystack-- + 1;
+ rneedle = needle;
+ a = *rneedle;
+
+ if (*rhaystack == a)
+ do
+ {
+ if (a == '\0')
+ goto foundneedle;
+ ++rhaystack;
+ a = *++needle;
+ if (*rhaystack != a)
+ break;
+ if (a == '\0')
+ goto foundneedle;
+ ++rhaystack;
+ a = *++needle;
+ }
+ while (*rhaystack == a);
+
+ needle = rneedle; /* took the register-poor approach */
+
+ if (a == '\0')
+ break;
+ }
+ }
+foundneedle:
+ return (char*) haystack;
+ret0:
+ return 0;
+}
diff --git a/contrib/tar/lib/strtoimax.c b/contrib/tar/lib/strtoimax.c
new file mode 100644
index 0000000..0f03ca1
--- /dev/null
+++ b/contrib/tar/lib/strtoimax.c
@@ -0,0 +1,100 @@
+/* Convert string representation of a number into an intmax_t value.
+ Copyright 1999, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Paul Eggert. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifndef PARAMS
+# if defined PROTOTYPES || defined __STDC__
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+#endif
+
+/* Verify a requirement at compile-time (unlike assert, which is runtime). */
+#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
+
+#ifdef UNSIGNED
+# ifndef HAVE_DECL_STRTOUL
+"this configure-time declaration test was not run"
+# endif
+# if !HAVE_DECL_STRTOUL
+unsigned long strtoul PARAMS ((char const *, char **, int));
+# endif
+# ifndef HAVE_DECL_STRTOULL
+"this configure-time declaration test was not run"
+# endif
+# if !HAVE_DECL_STRTOULL && HAVE_UNSIGNED_LONG_LONG
+unsigned long long strtoull PARAMS ((char const *, char **, int));
+# endif
+
+#else
+
+# ifndef HAVE_DECL_STRTOL
+"this configure-time declaration test was not run"
+# endif
+# if !HAVE_DECL_STRTOL
+long strtol PARAMS ((char const *, char **, int));
+# endif
+# ifndef HAVE_DECL_STRTOLL
+"this configure-time declaration test was not run"
+# endif
+# if !HAVE_DECL_STRTOLL && HAVE_UNSIGNED_LONG_LONG
+long long strtoll PARAMS ((char const *, char **, int));
+# endif
+#endif
+
+#ifdef UNSIGNED
+# undef HAVE_LONG_LONG
+# define HAVE_LONG_LONG HAVE_UNSIGNED_LONG_LONG
+# define INT uintmax_t
+# define strtoimax strtoumax
+# define strtol strtoul
+# define strtoll strtoull
+#else
+# define INT intmax_t
+#endif
+
+INT
+strtoimax (char const *ptr, char **endptr, int base)
+{
+#if HAVE_LONG_LONG
+ verify (size_is_that_of_long_or_long_long,
+ (sizeof (INT) == sizeof (long)
+ || sizeof (INT) == sizeof (long long)));
+
+ if (sizeof (INT) != sizeof (long))
+ return strtoll (ptr, endptr, base);
+#else
+ verify (size_is_that_of_long,
+ sizeof (INT) == sizeof (long));
+#endif
+
+ return strtol (ptr, endptr, base);
+}
diff --git a/contrib/tar/lib/strtol.c b/contrib/tar/lib/strtol.c
new file mode 100644
index 0000000..0c9c2767
--- /dev/null
+++ b/contrib/tar/lib/strtol.c
@@ -0,0 +1,472 @@
+/* Convert string representation of a number into an integer value.
+ Copyright (C) 1991, 92, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@gnu.org.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# define USE_NUMBER_GROUPING
+# define STDC_HEADERS
+# define HAVE_LIMITS_H
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <stddef.h>
+# include <stdlib.h>
+# include <string.h>
+#else
+# ifndef NULL
+# define NULL 0
+# endif
+#endif
+
+#ifdef USE_NUMBER_GROUPING
+# include "../locale/localeinfo.h"
+#endif
+
+/* Nonzero if we are defining `strtoul' or `strtoull', operating on
+ unsigned integers. */
+#ifndef UNSIGNED
+# define UNSIGNED 0
+# define INT LONG int
+#else
+# define INT unsigned LONG int
+#endif
+
+/* Determine the name. */
+#ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# if UNSIGNED
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol __wcstoull_l
+# else
+# define strtol __wcstoul_l
+# endif
+# else
+# ifdef QUAD
+# define strtol __strtoull_l
+# else
+# define strtol __strtoul_l
+# endif
+# endif
+# else
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol __wcstoll_l
+# else
+# define strtol __wcstol_l
+# endif
+# else
+# ifdef QUAD
+# define strtol __strtoll_l
+# else
+# define strtol __strtol_l
+# endif
+# endif
+# endif
+#else
+# if UNSIGNED
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol wcstoull
+# else
+# define strtol wcstoul
+# endif
+# else
+# ifdef QUAD
+# define strtol strtoull
+# else
+# define strtol strtoul
+# endif
+# endif
+# else
+# ifdef USE_WIDE_CHAR
+# ifdef QUAD
+# define strtol wcstoll
+# else
+# define strtol wcstol
+# endif
+# else
+# ifdef QUAD
+# define strtol strtoll
+# endif
+# endif
+# endif
+#endif
+
+/* If QUAD is defined, we are defining `strtoll' or `strtoull',
+ operating on `long long int's. */
+#ifdef QUAD
+# define LONG long long
+# define STRTOL_LONG_MIN LONG_LONG_MIN
+# define STRTOL_LONG_MAX LONG_LONG_MAX
+# define STRTOL_ULONG_MAX ULONG_LONG_MAX
+
+/* The extra casts work around common compiler bugs,
+ e.g. Cray C 5.0.3.0 when t == time_t. */
+# ifndef TYPE_SIGNED
+# define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+# endif
+# ifndef TYPE_MINIMUM
+# define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
+ ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \
+ : (t) 0))
+# endif
+# ifndef TYPE_MAXIMUM
+# define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
+# endif
+
+# ifndef ULONG_LONG_MAX
+# define ULONG_LONG_MAX TYPE_MAXIMUM (unsigned long long)
+# endif
+# ifndef LONG_LONG_MAX
+# define LONG_LONG_MAX TYPE_MAXIMUM (long long int)
+# endif
+# ifndef LONG_LONG_MIN
+# define LONG_LONG_MIN TYPE_MINIMUM (long long int)
+# endif
+
+# if __GNUC__ == 2 && __GNUC_MINOR__ < 7
+ /* Work around gcc bug with using this constant. */
+ static const unsigned long long int maxquad = ULONG_LONG_MAX;
+# undef STRTOL_ULONG_MAX
+# define STRTOL_ULONG_MAX maxquad
+# endif
+#else
+# define LONG long
+
+# ifndef ULONG_MAX
+# define ULONG_MAX ((unsigned long) ~(unsigned long) 0)
+# endif
+# ifndef LONG_MAX
+# define LONG_MAX ((long int) (ULONG_MAX >> 1))
+# endif
+# define STRTOL_LONG_MIN LONG_MIN
+# define STRTOL_LONG_MAX LONG_MAX
+# define STRTOL_ULONG_MAX ULONG_MAX
+#endif
+
+
+/* We use this code also for the extended locale handling where the
+ function gets as an additional argument the locale which has to be
+ used. To access the values we have to redefine the _NL_CURRENT
+ macro. */
+#ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# undef _NL_CURRENT
+# define _NL_CURRENT(category, item) \
+ (current->values[_NL_ITEM_INDEX (item)].string)
+# define LOCALE_PARAM , loc
+# define LOCALE_PARAM_DECL __locale_t loc;
+#else
+# define LOCALE_PARAM
+# define LOCALE_PARAM_DECL
+#endif
+
+#if defined _LIBC || defined HAVE_WCHAR_H
+# include <wchar.h>
+#endif
+
+#ifdef USE_WIDE_CHAR
+# include <wctype.h>
+# define L_(Ch) L##Ch
+# define UCHAR_TYPE wint_t
+# define STRING_TYPE wchar_t
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define ISSPACE(Ch) __iswspace_l ((Ch), loc)
+# define ISALPHA(Ch) __iswalpha_l ((Ch), loc)
+# define TOUPPER(Ch) __towupper_l ((Ch), loc)
+# else
+# define ISSPACE(Ch) iswspace (Ch)
+# define ISALPHA(Ch) iswalpha (Ch)
+# define TOUPPER(Ch) towupper (Ch)
+# endif
+#else
+# if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII)
+# define IN_CTYPE_DOMAIN(c) 1
+# else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+# endif
+# define L_(Ch) Ch
+# define UCHAR_TYPE unsigned char
+# define STRING_TYPE char
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# define ISSPACE(Ch) __isspace_l ((Ch), loc)
+# define ISALPHA(Ch) __isalpha_l ((Ch), loc)
+# define TOUPPER(Ch) __toupper_l ((Ch), loc)
+# else
+# define ISSPACE(Ch) (IN_CTYPE_DOMAIN (Ch) && isspace (Ch))
+# define ISALPHA(Ch) (IN_CTYPE_DOMAIN (Ch) && isalpha (Ch))
+# define TOUPPER(Ch) (IN_CTYPE_DOMAIN (Ch) ? toupper (Ch) : (Ch))
+# endif
+#endif
+
+/* For compilers which are ansi but don't define __STDC__, like SGI
+ Irix-4.0.5 cc, also check whether PROTOTYPES is defined. */
+#if defined (__STDC__) || defined (PROTOTYPES)
+# define INTERNAL(X) INTERNAL1(X)
+# define INTERNAL1(X) __##X##_internal
+# define WEAKNAME(X) WEAKNAME1(X)
+#else
+# define INTERNAL(X) __/**/X/**/_internal
+#endif
+
+#ifdef USE_NUMBER_GROUPING
+/* This file defines a function to check for correct grouping. */
+# include "grouping.h"
+#endif
+
+
+
+/* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
+ If BASE is 0 the base is determined by the presence of a leading
+ zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal.
+ If BASE is < 2 or > 36, it is reset to 10.
+ If ENDPTR is not NULL, a pointer to the character after the last
+ one converted is stored in *ENDPTR. */
+
+INT
+INTERNAL (strtol) (nptr, endptr, base, group LOCALE_PARAM)
+ const STRING_TYPE *nptr;
+ STRING_TYPE **endptr;
+ int base;
+ int group;
+ LOCALE_PARAM_DECL
+{
+ int negative;
+ register unsigned LONG int cutoff;
+ register unsigned int cutlim;
+ register unsigned LONG int i;
+ register const STRING_TYPE *s;
+ register UCHAR_TYPE c;
+ const STRING_TYPE *save, *end;
+ int overflow;
+
+#ifdef USE_NUMBER_GROUPING
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+ struct locale_data *current = loc->__locales[LC_NUMERIC];
+# endif
+ /* The thousands character of the current locale. */
+ wchar_t thousands = L'\0';
+ /* The numeric grouping specification of the current locale,
+ in the format described in <locale.h>. */
+ const char *grouping;
+
+ if (group)
+ {
+ grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
+ if (*grouping <= 0 || *grouping == CHAR_MAX)
+ grouping = NULL;
+ else
+ {
+ /* Figure out the thousands separator character. */
+# if defined _LIBC || defined _HAVE_BTOWC
+ thousands = __btowc (*_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP));
+ if (thousands == WEOF)
+ thousands = L'\0';
+# endif
+ if (thousands == L'\0')
+ grouping = NULL;
+ }
+ }
+ else
+ grouping = NULL;
+#endif
+
+ if (base < 0 || base == 1 || base > 36)
+ {
+ __set_errno (EINVAL);
+ return 0;
+ }
+
+ save = s = nptr;
+
+ /* Skip white space. */
+ while (ISSPACE (*s))
+ ++s;
+ if (*s == L_('\0'))
+ goto noconv;
+
+ /* Check for a sign. */
+ if (*s == L_('-'))
+ {
+ negative = 1;
+ ++s;
+ }
+ else if (*s == L_('+'))
+ {
+ negative = 0;
+ ++s;
+ }
+ else
+ negative = 0;
+
+ /* Recognize number prefix and if BASE is zero, figure it out ourselves. */
+ if (*s == L_('0'))
+ {
+ if ((base == 0 || base == 16) && TOUPPER (s[1]) == L_('X'))
+ {
+ s += 2;
+ base = 16;
+ }
+ else if (base == 0)
+ base = 8;
+ }
+ else if (base == 0)
+ base = 10;
+
+ /* Save the pointer so we can check later if anything happened. */
+ save = s;
+
+#ifdef USE_NUMBER_GROUPING
+ if (group)
+ {
+ /* Find the end of the digit string and check its grouping. */
+ end = s;
+ for (c = *end; c != L_('\0'); c = *++end)
+ if ((wchar_t) c != thousands
+ && ((wchar_t) c < L_('0') || (wchar_t) c > L_('9'))
+ && (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base))
+ break;
+ if (*s == thousands)
+ end = s;
+ else
+ end = correctly_grouped_prefix (s, end, thousands, grouping);
+ }
+ else
+#endif
+ end = NULL;
+
+ cutoff = STRTOL_ULONG_MAX / (unsigned LONG int) base;
+ cutlim = STRTOL_ULONG_MAX % (unsigned LONG int) base;
+
+ overflow = 0;
+ i = 0;
+ for (c = *s; c != L_('\0'); c = *++s)
+ {
+ if (s == end)
+ break;
+ if (c >= L_('0') && c <= L_('9'))
+ c -= L_('0');
+ else if (ISALPHA (c))
+ c = TOUPPER (c) - L_('A') + 10;
+ else
+ break;
+ if ((int) c >= base)
+ break;
+ /* Check for overflow. */
+ if (i > cutoff || (i == cutoff && c > cutlim))
+ overflow = 1;
+ else
+ {
+ i *= (unsigned LONG int) base;
+ i += c;
+ }
+ }
+
+ /* Check if anything actually happened. */
+ if (s == save)
+ goto noconv;
+
+ /* Store in ENDPTR the address of one character
+ past the last character we converted. */
+ if (endptr != NULL)
+ *endptr = (STRING_TYPE *) s;
+
+#if !UNSIGNED
+ /* Check for a value that is within the range of
+ `unsigned LONG int', but outside the range of `LONG int'. */
+ if (overflow == 0
+ && i > (negative
+ ? -((unsigned LONG int) (STRTOL_LONG_MIN + 1)) + 1
+ : (unsigned LONG int) STRTOL_LONG_MAX))
+ overflow = 1;
+#endif
+
+ if (overflow)
+ {
+ __set_errno (ERANGE);
+#if UNSIGNED
+ return STRTOL_ULONG_MAX;
+#else
+ return negative ? STRTOL_LONG_MIN : STRTOL_LONG_MAX;
+#endif
+ }
+
+ /* Return the result of the appropriate sign. */
+ return negative ? -i : i;
+
+noconv:
+ /* We must handle a special case here: the base is 0 or 16 and the
+ first two characters are '0' and 'x', but the rest are no
+ hexadecimal digits. This is no error case. We return 0 and
+ ENDPTR points to the `x`. */
+ if (endptr != NULL)
+ {
+ if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X')
+ && save[-2] == L_('0'))
+ *endptr = (STRING_TYPE *) &save[-1];
+ else
+ /* There was no number to convert. */
+ *endptr = (STRING_TYPE *) nptr;
+ }
+
+ return 0L;
+}
+
+/* External user entry point. */
+
+#if _LIBC - 0 == 0
+# undef PARAMS
+# if defined (__STDC__) && __STDC__
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+
+/* Prototype. */
+INT strtol PARAMS ((const STRING_TYPE *nptr, STRING_TYPE **endptr, int base));
+#endif
+
+
+INT
+#ifdef weak_function
+weak_function
+#endif
+strtol (nptr, endptr, base LOCALE_PARAM)
+ const STRING_TYPE *nptr;
+ STRING_TYPE **endptr;
+ int base;
+ LOCALE_PARAM_DECL
+{
+ return INTERNAL (strtol) (nptr, endptr, base, 0 LOCALE_PARAM);
+}
diff --git a/contrib/tar/lib/strtoll.c b/contrib/tar/lib/strtoll.c
new file mode 100644
index 0000000..76234cb
--- /dev/null
+++ b/contrib/tar/lib/strtoll.c
@@ -0,0 +1,33 @@
+/* Function to parse a `long long int' from text.
+ Copyright (C) 1995, 1996, 1997, 1999, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#define QUAD 1
+
+#include "strtol.c"
+
+#ifdef _LIBC
+# ifdef SHARED
+# include <shlib-compat.h>
+
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
+compat_symbol (libc, __strtoll_internal, __strtoq_internal, GLIBC_2_0);
+# endif
+
+# endif
+weak_alias (strtoll, strtoq)
+#endif
diff --git a/contrib/tar/lib/strtoul.c b/contrib/tar/lib/strtoul.c
new file mode 100644
index 0000000..cfe239c
--- /dev/null
+++ b/contrib/tar/lib/strtoul.c
@@ -0,0 +1,22 @@
+/* Copyright (C) 1991, 1999, 2001 Free Software Foundation, Inc.
+
+NOTE: The canonical source of this file is maintained with the GNU C Library.
+Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#define UNSIGNED 1
+
+#include "strtol.c"
diff --git a/contrib/tar/lib/strtoull.c b/contrib/tar/lib/strtoull.c
new file mode 100644
index 0000000..d6aa1f8
--- /dev/null
+++ b/contrib/tar/lib/strtoull.c
@@ -0,0 +1,27 @@
+/* Function to parse an `unsigned long long int' from text.
+ Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@gnu.org.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#define QUAD 1
+
+#include "strtoul.c"
+
+#ifdef _LIBC
+strong_alias (__strtoull_internal, __strtouq_internal)
+weak_alias (strtoull, strtouq)
+#endif
diff --git a/contrib/tar/lib/strtoumax.c b/contrib/tar/lib/strtoumax.c
new file mode 100644
index 0000000..dc395d6
--- /dev/null
+++ b/contrib/tar/lib/strtoumax.c
@@ -0,0 +1,2 @@
+#define UNSIGNED 1
+#include "strtoimax.c"
diff --git a/contrib/tar/lib/unicodeio.c b/contrib/tar/lib/unicodeio.c
new file mode 100644
index 0000000..a1db6e2
--- /dev/null
+++ b/contrib/tar/lib/unicodeio.c
@@ -0,0 +1,259 @@
+/* Unicode character output to streams with locale dependent encoding.
+
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Bruno Haible <haible@clisp.cons.org>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+
+#include <stdio.h>
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#if HAVE_ICONV
+# include <iconv.h>
+#endif
+
+/* Some systems, like SunOS 4, don't have EILSEQ. On these systems,
+ define EILSEQ to some value other than EINVAL, because our invokers
+ may want to distinguish EINVAL from EILSEQ. */
+#ifndef EILSEQ
+# define EILSEQ ENOENT
+#endif
+#ifndef ENOTSUP
+# define ENOTSUP EINVAL
+#endif
+
+#if HAVE_LANGINFO_CODESET && ! USE_INCLUDED_LIBINTL
+# include <langinfo.h>
+#endif
+
+#include "unicodeio.h"
+
+/* When we pass a Unicode character to iconv(), we must pass it in a
+ suitable encoding. The standardized Unicode encodings are
+ UTF-8, UCS-2, UCS-4, UTF-16, UTF-16BE, UTF-16LE, UTF-7.
+ UCS-2 supports only characters up to \U0000FFFF.
+ UTF-16 and variants support only characters up to \U0010FFFF.
+ UTF-7 is way too complex and not supported by glibc-2.1.
+ UCS-4 specification leaves doubts about endianness and byte order
+ mark. glibc currently interprets it as big endian without byte order
+ mark, but this is not backed by an RFC.
+ So we use UTF-8. It supports characters up to \U7FFFFFFF and is
+ unambiguously defined. */
+
+/* Stores the UTF-8 representation of the Unicode character wc in r[0..5].
+ Returns the number of bytes stored, or -1 if wc is out of range. */
+static int
+utf8_wctomb (unsigned char *r, unsigned int wc)
+{
+ int count;
+
+ if (wc < 0x80)
+ count = 1;
+ else if (wc < 0x800)
+ count = 2;
+ else if (wc < 0x10000)
+ count = 3;
+ else if (wc < 0x200000)
+ count = 4;
+ else if (wc < 0x4000000)
+ count = 5;
+ else if (wc <= 0x7fffffff)
+ count = 6;
+ else
+ return -1;
+
+ switch (count)
+ {
+ /* Note: code falls through cases! */
+ case 6: r[5] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x4000000;
+ case 5: r[4] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x200000;
+ case 4: r[3] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x10000;
+ case 3: r[2] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x800;
+ case 2: r[1] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0xc0;
+ case 1: r[0] = wc;
+ }
+
+ return count;
+}
+
+/* Luckily, the encoding's name is platform independent. */
+#define UTF8_NAME "UTF-8"
+
+/* Converts the Unicode character CODE to its multibyte representation
+ in the current locale and calls SUCCESS on the resulting byte
+ sequence. If an error occurs, invoke FAILURE instead,
+ passing it CODE with errno set appropriately.
+ Assumes that the locale doesn't change between two calls.
+ Return whatever the SUCCESS or FAILURE returns. */
+int
+unicode_to_mb (unsigned int code,
+ int (*success) PARAMS((const char *buf, size_t buflen,
+ void *callback_arg)),
+ int (*failure) PARAMS((unsigned int code,
+ void *callback_arg)),
+ void *callback_arg)
+{
+ static int initialized;
+ static int is_utf8;
+#if HAVE_ICONV
+ static iconv_t utf8_to_local;
+#endif
+
+ char inbuf[6];
+ int count;
+
+ if (!initialized)
+ {
+ const char *charset;
+
+#if USE_INCLUDED_LIBINTL
+ extern const char *locale_charset PARAMS ((void));
+ charset = locale_charset ();
+#else
+# if HAVE_LANGINFO_CODESET
+ charset = nl_langinfo (CODESET);
+# else
+ charset = "";
+# endif
+#endif
+
+ is_utf8 = !strcmp (charset, UTF8_NAME);
+#if HAVE_ICONV
+ if (!is_utf8)
+ {
+ utf8_to_local = iconv_open (charset, UTF8_NAME);
+ if (utf8_to_local == (iconv_t)(-1))
+ {
+ /* For an unknown encoding, assume ASCII. */
+ utf8_to_local = iconv_open ("ASCII", UTF8_NAME);
+ if (utf8_to_local == (iconv_t)(-1))
+ return failure (code, callback_arg);
+ }
+ }
+#endif
+ initialized = 1;
+ }
+
+ /* Convert the character to UTF-8. */
+ count = utf8_wctomb ((unsigned char *) inbuf, code);
+ if (count < 0)
+ {
+ errno = EILSEQ;
+ return failure (code, callback_arg);
+ }
+
+ if (is_utf8)
+ {
+ return success (inbuf, count, callback_arg);
+ }
+ else
+ {
+#if HAVE_ICONV
+ char outbuf[25];
+ const char *inptr;
+ size_t inbytesleft;
+ char *outptr;
+ size_t outbytesleft;
+ size_t res;
+
+ inptr = inbuf;
+ inbytesleft = count;
+ outptr = outbuf;
+ outbytesleft = sizeof (outbuf);
+
+ /* Convert the character from UTF-8 to the locale's charset. */
+ res = iconv (utf8_to_local,
+ (ICONV_CONST char **)&inptr, &inbytesleft,
+ &outptr, &outbytesleft);
+ if (inbytesleft > 0 || res == (size_t)(-1)
+ /* Irix iconv() inserts a NUL byte if it cannot convert. */
+# if !defined _LIBICONV_VERSION && (defined sgi || defined __sgi)
+ || (res > 0 && code != 0 && outptr - outbuf == 1 && *outbuf == '\0')
+# endif
+ )
+ {
+ if (res != (size_t)(-1))
+ errno = EILSEQ;
+ return failure (code, callback_arg);
+ }
+
+ /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
+# if defined _LIBICONV_VERSION \
+ || !((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) || defined __sun)
+
+ /* Get back to the initial shift state. */
+ res = iconv (utf8_to_local, NULL, NULL, &outptr, &outbytesleft);
+ if (res == (size_t)(-1))
+ return failure (code, callback_arg);
+# endif
+
+ return success (outbuf, outptr - outbuf, callback_arg);
+#else
+ errno = ENOTSUP;
+ return failure (code, callback_arg);
+#endif
+ }
+}
+
+/* Simple success callback that outputs the converted string.
+ The STREAM is passed as callback_arg. */
+int
+print_unicode_success (const char *buf, size_t buflen, void *callback_arg)
+{
+ FILE *stream = (FILE *) callback_arg;
+
+ return fwrite (buf, 1, buflen, stream) == 0 ? -1 : 0;
+}
+
+/* Simple failure callback that prints an ASCII representation, using
+ the same notation as C99 strings. */
+int
+print_unicode_failure (unsigned int code, void *callback_arg)
+{
+ int e = errno;
+ FILE *stream = callback_arg;
+
+ fprintf (stream, code < 0x10000 ? "\\u%04X" : "\\U%08X", code);
+ errno = e;
+ return -1;
+}
+
+/* Outputs the Unicode character CODE to the output stream STREAM.
+ Returns zero if successful, -1 (setting errno) otherwise.
+ Assumes that the locale doesn't change between two calls. */
+int
+print_unicode_char (FILE *stream, unsigned int code)
+{
+ return unicode_to_mb (code, print_unicode_success, print_unicode_failure,
+ stream);
+}
diff --git a/contrib/tar/lib/unicodeio.h b/contrib/tar/lib/unicodeio.h
new file mode 100644
index 0000000..4a22bfb
--- /dev/null
+++ b/contrib/tar/lib/unicodeio.h
@@ -0,0 +1,57 @@
+/* Unicode character output to streams with locale dependent encoding.
+
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef UNICODEIO_H
+# define UNICODEIO_H
+
+# include <stdio.h>
+
+# ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+# endif
+
+/* Converts the Unicode character CODE to its multibyte representation
+ in the current locale and calls the CALLBACK on the resulting byte
+ sequence. If an error occurs, invokes ERROR_CALLBACK instead,
+ passing it CODE with errno set appropriately. Returns whatever the
+ callback returns. */
+extern int unicode_to_mb
+ PARAMS ((unsigned int code,
+ int (*callback) PARAMS ((const char *buf, size_t buflen,
+ void *callback_arg)),
+ int (*error_callback) PARAMS ((unsigned int code,
+ void * callback_arg)),
+ void *callback_arg));
+
+/* Success callback that outputs the conversion of the character. */
+extern int print_unicode_success PARAMS((const char *buf, size_t buflen,
+ void *callback_arg));
+
+/* Failure callback that outputs an ASCII representation. */
+extern int print_unicode_failure PARAMS((unsigned int code,
+ void *callback_arg));
+
+/* Outputs the Unicode character CODE to the output stream STREAM.
+ Returns -1 (setting errno) if unsuccessful. */
+extern int print_unicode_char PARAMS((FILE *stream, unsigned int code));
+
+#endif
diff --git a/contrib/tar/lib/utime.c b/contrib/tar/lib/utime.c
new file mode 100644
index 0000000..6ed14ef
--- /dev/null
+++ b/contrib/tar/lib/utime.c
@@ -0,0 +1,82 @@
+/* Copyright (C) 1998, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* derived from a function in touch.c */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#undef utime
+
+#include <sys/types.h>
+
+#ifdef HAVE_UTIME_H
+# include <utime.h>
+#endif
+
+#include "full-write.h"
+#include "safe-read.h"
+
+/* Some systems (even some that do have <utime.h>) don't declare this
+ structure anywhere. */
+#ifndef HAVE_STRUCT_UTIMBUF
+struct utimbuf
+{
+ long actime;
+ long modtime;
+};
+#endif
+
+/* Emulate utime (file, NULL) for systems (like 4.3BSD) that do not
+ interpret it to set the access and modification times of FILE to
+ the current time. Return 0 if successful, -1 if not. */
+
+static int
+utime_null (const char *file)
+{
+#if HAVE_UTIMES_NULL
+ return utimes (file, 0);
+#else
+ int fd;
+ char c;
+ int status = 0;
+ struct stat sb;
+
+ fd = open (file, O_RDWR);
+ if (fd < 0
+ || fstat (fd, &sb) < 0
+ || safe_read (fd, &c, sizeof c) < 0
+ || lseek (fd, (off_t) 0, SEEK_SET) < 0
+ || full_write (fd, &c, sizeof c) != sizeof c
+ /* Maybe do this -- it's necessary on SunOS4.1.3 with some combination
+ of patches, but that system doesn't use this code: it has utimes.
+ || fsync (fd) < 0
+ */
+ || ftruncate (fd, st.st_size) < 0
+ || close (fd) < 0)
+ status = -1;
+ return status;
+#endif
+}
+
+int
+rpl_utime (const char *file, const struct utimbuf *times)
+{
+ if (times)
+ return utime (file, times);
+
+ return utime_null (file);
+}
diff --git a/contrib/tar/lib/waitpid.c b/contrib/tar/lib/waitpid.c
new file mode 100644
index 0000000..f2b4235
--- /dev/null
+++ b/contrib/tar/lib/waitpid.c
@@ -0,0 +1,72 @@
+/* Emulate waitpid on systems that just have wait.
+ Copyright 1994, 1995, 1998, 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING.
+ If not, write to the Free Software Foundation,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#define WAITPID_CHILDREN 8
+static pid_t waited_pid[WAITPID_CHILDREN];
+static int waited_status[WAITPID_CHILDREN];
+
+pid_t
+waitpid (pid_t pid, int *stat_loc, int options)
+{
+ int i;
+ pid_t p;
+
+ if (!options && (pid == -1 || 0 < pid))
+ {
+ /* If we have already waited for this child, return it immediately. */
+ for (i = 0; i < WAITPID_CHILDREN; i++)
+ {
+ p = waited_pid[i];
+ if (p && (p == pid || pid == -1))
+ {
+ waited_pid[i] = 0;
+ goto success;
+ }
+ }
+
+ /* The child has not returned yet; wait for it, accumulating status. */
+ for (i = 0; i < WAITPID_CHILDREN; i++)
+ if (! waited_pid[i])
+ {
+ p = wait (&waited_status[i]);
+ if (p < 0)
+ return p;
+ if (p == pid || pid == -1)
+ goto success;
+ waited_pid[i] = p;
+ }
+ }
+
+ /* We cannot emulate this wait call, e.g. because of too many children. */
+ errno = EINVAL;
+ return -1;
+
+success:
+ if (stat_loc)
+ *stat_loc = waited_status[i];
+ return p;
+}
diff --git a/contrib/tar/lib/xalloc.h b/contrib/tar/lib/xalloc.h
new file mode 100644
index 0000000..098a6c2
--- /dev/null
+++ b/contrib/tar/lib/xalloc.h
@@ -0,0 +1,87 @@
+/* xalloc.h -- malloc with out-of-memory checking
+ Copyright (C) 1990-1998, 1999, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef XALLOC_H_
+# define XALLOC_H_
+
+# ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+# endif
+
+# ifndef __attribute__
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
+# define __attribute__(x)
+# endif
+# endif
+
+# ifndef ATTRIBUTE_NORETURN
+# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
+# endif
+
+/* Exit value when the requested amount of memory is not available.
+ It is initialized to EXIT_FAILURE, but the caller may set it to
+ some other value. */
+extern int xalloc_exit_failure;
+
+/* If this pointer is non-zero, run the specified function upon each
+ allocation failure. It is initialized to zero. */
+extern void (*xalloc_fail_func) PARAMS ((void));
+
+/* If XALLOC_FAIL_FUNC is undefined or a function that returns, this
+ message is output. It is translated via gettext.
+ Its value is "memory exhausted". */
+extern char const xalloc_msg_memory_exhausted[];
+
+/* This function is always triggered when memory is exhausted. It is
+ in charge of honoring the three previous items. This is the
+ function to call when one wants the program to die because of a
+ memory allocation failure. */
+extern void xalloc_die PARAMS ((void)) ATTRIBUTE_NORETURN;
+
+void *xmalloc PARAMS ((size_t n));
+void *xcalloc PARAMS ((size_t n, size_t s));
+void *xrealloc PARAMS ((void *p, size_t n));
+char *xstrdup PARAMS ((const char *str));
+
+# define XMALLOC(Type, N_items) ((Type *) xmalloc (sizeof (Type) * (N_items)))
+# define XCALLOC(Type, N_items) ((Type *) xcalloc (sizeof (Type), (N_items)))
+# define XREALLOC(Ptr, Type, N_items) \
+ ((Type *) xrealloc ((void *) (Ptr), sizeof (Type) * (N_items)))
+
+/* Declare and alloc memory for VAR of type TYPE. */
+# define NEW(Type, Var) Type *(Var) = XMALLOC (Type, 1)
+
+/* Free VAR only if non NULL. */
+# define XFREE(Var) \
+ do { \
+ if (Var) \
+ free (Var); \
+ } while (0)
+
+/* Return a pointer to a malloc'ed copy of the array SRC of NUM elements. */
+# define CCLONE(Src, Num) \
+ (memcpy (xmalloc (sizeof (*Src) * (Num)), (Src), sizeof (*Src) * (Num)))
+
+/* Return a malloc'ed copy of SRC. */
+# define CLONE(Src) CCLONE (Src, 1)
+
+
+#endif /* !XALLOC_H_ */
diff --git a/contrib/tar/lib/xgetcwd.c b/contrib/tar/lib/xgetcwd.c
new file mode 100644
index 0000000..1409bcf
--- /dev/null
+++ b/contrib/tar/lib/xgetcwd.c
@@ -0,0 +1,87 @@
+/* xgetcwd.c -- return current directory with unlimited length
+ Copyright (C) 1992, 1996, 2000, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#include <sys/types.h>
+
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_GETCWD
+char *getcwd ();
+#else
+# include "pathmax.h"
+# define INITIAL_BUFFER_SIZE (PATH_MAX + 1)
+char *getwd ();
+# define getcwd(Buf, Max) getwd (Buf)
+#endif
+
+#include "xalloc.h"
+
+/* Return the current directory, newly allocated, arbitrarily long.
+ Return NULL and set errno on error. */
+
+char *
+xgetcwd ()
+{
+#if HAVE_GETCWD_NULL
+ char *cwd = getcwd (NULL, 0);
+ if (! cwd && errno == ENOMEM)
+ xalloc_die ();
+ return cwd;
+#else
+
+ /* The initial buffer size for the working directory. A power of 2
+ detects arithmetic overflow earlier, but is not required. */
+# ifndef INITIAL_BUFFER_SIZE
+# define INITIAL_BUFFER_SIZE 128
+# endif
+
+ size_t buf_size = INITIAL_BUFFER_SIZE;
+
+ while (1)
+ {
+ char *buf = xmalloc (buf_size);
+ char *cwd = getcwd (buf, buf_size);
+ int saved_errno;
+ if (cwd)
+ return cwd;
+ saved_errno = errno;
+ free (buf);
+ if (saved_errno != ERANGE)
+ return NULL;
+ buf_size *= 2;
+ if (buf_size == 0)
+ xalloc_die ();
+ }
+#endif
+}
diff --git a/contrib/tar/lib/xmalloc.c b/contrib/tar/lib/xmalloc.c
new file mode 100644
index 0000000..2f103d6
--- /dev/null
+++ b/contrib/tar/lib/xmalloc.c
@@ -0,0 +1,116 @@
+/* xmalloc.c -- malloc with out of memory checking
+ Copyright (C) 1990-1999, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+void *calloc ();
+void *malloc ();
+void *realloc ();
+void free ();
+#endif
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# define textdomain(Domain)
+# define _(Text) Text
+#endif
+#define N_(Text) Text
+
+#include "error.h"
+#include "xalloc.h"
+
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+#ifndef HAVE_DONE_WORKING_MALLOC_CHECK
+"you must run the autoconf test for a properly working malloc -- see malloc.m4"
+#endif
+
+#ifndef HAVE_DONE_WORKING_REALLOC_CHECK
+"you must run the autoconf test for a properly working realloc --see realloc.m4"
+#endif
+
+/* Exit value when the requested amount of memory is not available.
+ The caller may set it to some other value. */
+int xalloc_exit_failure = EXIT_FAILURE;
+
+/* If non NULL, call this function when memory is exhausted. */
+void (*xalloc_fail_func) PARAMS ((void)) = 0;
+
+/* If XALLOC_FAIL_FUNC is NULL, or does return, display this message
+ before exiting when memory is exhausted. Goes through gettext. */
+char const xalloc_msg_memory_exhausted[] = N_("memory exhausted");
+
+void
+xalloc_die (void)
+{
+ if (xalloc_fail_func)
+ (*xalloc_fail_func) ();
+ error (xalloc_exit_failure, 0, "%s", _(xalloc_msg_memory_exhausted));
+ /* The `noreturn' cannot be given to error, since it may return if
+ its first argument is 0. To help compilers understand the
+ xalloc_die does terminate, call exit. */
+ exit (EXIT_FAILURE);
+}
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+
+void *
+xmalloc (size_t n)
+{
+ void *p;
+
+ p = malloc (n);
+ if (p == 0)
+ xalloc_die ();
+ return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking. */
+
+void *
+xrealloc (void *p, size_t n)
+{
+ p = realloc (p, n);
+ if (p == 0)
+ xalloc_die ();
+ return p;
+}
+
+/* Allocate memory for N elements of S bytes, with error checking. */
+
+void *
+xcalloc (size_t n, size_t s)
+{
+ void *p;
+
+ p = calloc (n, s);
+ if (p == 0)
+ xalloc_die ();
+ return p;
+}
diff --git a/contrib/tar/lib/xstrdup.c b/contrib/tar/lib/xstrdup.c
new file mode 100644
index 0000000..38674ca
--- /dev/null
+++ b/contrib/tar/lib/xstrdup.c
@@ -0,0 +1,46 @@
+/* xstrdup.c -- copy a string with out of memory checking
+ Copyright (C) 1990, 1996, 1998 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+#endif
+
+#if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#include <sys/types.h>
+
+char *xmalloc PARAMS ((size_t n));
+
+/* Return a newly allocated copy of STRING. */
+
+char *
+xstrdup (const char *string)
+{
+ return strcpy (xmalloc (strlen (string) + 1), string);
+}
diff --git a/contrib/tar/lib/xstrtoimax.c b/contrib/tar/lib/xstrtoimax.c
new file mode 100644
index 0000000..8937862
--- /dev/null
+++ b/contrib/tar/lib/xstrtoimax.c
@@ -0,0 +1,31 @@
+/* xstrtoimax.c -- A more useful interface to strtoimax.
+ Copyright 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Cloned by Jim Meyering. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#define __strtol strtoimax
+#define __strtol_t intmax_t
+#define __xstrtol xstrtoimax
+#include "xstrtol.c"
diff --git a/contrib/tar/lib/xstrtol.c b/contrib/tar/lib/xstrtol.c
new file mode 100644
index 0000000..d7ca6cf
--- /dev/null
+++ b/contrib/tar/lib/xstrtol.c
@@ -0,0 +1,288 @@
+/* A more useful interface to strtol.
+ Copyright (C) 1995, 1996, 1998-2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Jim Meyering. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef __strtol
+# define __strtol strtol
+# define __strtol_t long int
+# define __xstrtol xstrtol
+#endif
+
+/* Some pre-ANSI implementations (e.g. SunOS 4)
+ need stderr defined if assertion checking is enabled. */
+#include <stdio.h>
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#endif
+
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef strchr
+# define strchr index
+# endif
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#ifndef CHAR_BIT
+# define CHAR_BIT 8
+#endif
+
+/* The extra casts work around common compiler bugs. */
+#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
+ It is necessary at least when t == time_t. */
+#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
+ ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
+#define TYPE_MAXIMUM(t) (~ (t) 0 - TYPE_MINIMUM (t))
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+
+#include "xstrtol.h"
+
+#ifndef strtol
+long int strtol ();
+#endif
+
+#ifndef strtoul
+unsigned long int strtoul ();
+#endif
+
+#if !HAVE_DECL_STRTOIMAX
+intmax_t strtoimax ();
+#endif
+
+#if !HAVE_DECL_STRTOUMAX
+uintmax_t strtoumax ();
+#endif
+
+static int
+bkm_scale (__strtol_t *x, int scale_factor)
+{
+ __strtol_t product = *x * scale_factor;
+ if (*x != product / scale_factor)
+ return 1;
+ *x = product;
+ return 0;
+}
+
+static int
+bkm_scale_by_power (__strtol_t *x, int base, int power)
+{
+ while (power--)
+ if (bkm_scale (x, base))
+ return 1;
+
+ return 0;
+}
+
+/* FIXME: comment. */
+
+strtol_error
+__xstrtol (const char *s, char **ptr, int strtol_base,
+ __strtol_t *val, const char *valid_suffixes)
+{
+ char *t_ptr;
+ char **p;
+ __strtol_t tmp;
+
+ assert (0 <= strtol_base && strtol_base <= 36);
+
+ p = (ptr ? ptr : &t_ptr);
+
+ if (! TYPE_SIGNED (__strtol_t))
+ {
+ const char *q = s;
+ while (ISSPACE ((unsigned char) *q))
+ ++q;
+ if (*q == '-')
+ return LONGINT_INVALID;
+ }
+
+ errno = 0;
+ tmp = __strtol (s, p, strtol_base);
+ if (errno != 0)
+ return LONGINT_OVERFLOW;
+ if (*p == s)
+ return LONGINT_INVALID;
+
+ /* Let valid_suffixes == NULL mean `allow any suffix'. */
+ /* FIXME: update all callers except the ones that allow suffixes
+ after the number, changing last parameter NULL to `""'. */
+ if (!valid_suffixes)
+ {
+ *val = tmp;
+ return LONGINT_OK;
+ }
+
+ if (**p != '\0')
+ {
+ int base = 1024;
+ int suffixes = 1;
+ int overflow;
+
+ if (!strchr (valid_suffixes, **p))
+ {
+ *val = tmp;
+ return LONGINT_INVALID_SUFFIX_CHAR;
+ }
+
+ if (strchr (valid_suffixes, '0'))
+ {
+ /* The ``valid suffix'' '0' is a special flag meaning that
+ an optional second suffix is allowed, which can change
+ the base, e.g. "100MD" for 100 megabytes decimal. */
+
+ switch (p[0][1])
+ {
+ case 'B':
+ suffixes++;
+ break;
+
+ case 'D':
+ base = 1000;
+ suffixes++;
+ break;
+ }
+ }
+
+ switch (**p)
+ {
+ case 'b':
+ overflow = bkm_scale (&tmp, 512);
+ break;
+
+ case 'B':
+ overflow = bkm_scale (&tmp, 1024);
+ break;
+
+ case 'c':
+ overflow = 0;
+ break;
+
+ case 'E': /* Exa */
+ overflow = bkm_scale_by_power (&tmp, base, 6);
+ break;
+
+ case 'G': /* Giga */
+ case 'g': /* 'g' is undocumented; for compatibility only */
+ overflow = bkm_scale_by_power (&tmp, base, 3);
+ break;
+
+ case 'k': /* kilo */
+ overflow = bkm_scale_by_power (&tmp, base, 1);
+ break;
+
+ case 'M': /* Mega */
+ case 'm': /* 'm' is undocumented; for compatibility only */
+ overflow = bkm_scale_by_power (&tmp, base, 2);
+ break;
+
+ case 'P': /* Peta */
+ overflow = bkm_scale_by_power (&tmp, base, 5);
+ break;
+
+ case 'T': /* Tera */
+ case 't': /* 't' is undocumented; for compatibility only */
+ overflow = bkm_scale_by_power (&tmp, base, 4);
+ break;
+
+ case 'w':
+ overflow = bkm_scale (&tmp, 2);
+ break;
+
+ case 'Y': /* Yotta */
+ overflow = bkm_scale_by_power (&tmp, base, 8);
+ break;
+
+ case 'Z': /* Zetta */
+ overflow = bkm_scale_by_power (&tmp, base, 7);
+ break;
+
+ default:
+ *val = tmp;
+ return LONGINT_INVALID_SUFFIX_CHAR;
+ break;
+ }
+
+ if (overflow)
+ return LONGINT_OVERFLOW;
+
+ (*p) += suffixes;
+ }
+
+ *val = tmp;
+ return LONGINT_OK;
+}
+
+#ifdef TESTING_XSTRTO
+
+# include <stdio.h>
+# include "error.h"
+
+char *program_name;
+
+int
+main (int argc, char** argv)
+{
+ strtol_error s_err;
+ int i;
+
+ program_name = argv[0];
+ for (i=1; i<argc; i++)
+ {
+ char *p;
+ __strtol_t val;
+
+ s_err = __xstrtol (argv[i], &p, 0, &val, "bckmw");
+ if (s_err == LONGINT_OK)
+ {
+ printf ("%s->%lu (%s)\n", argv[i], val, p);
+ }
+ else
+ {
+ STRTOL_FATAL_ERROR (argv[i], "arg", s_err);
+ }
+ }
+ exit (0);
+}
+
+#endif /* TESTING_XSTRTO */
diff --git a/contrib/tar/lib/xstrtol.h b/contrib/tar/lib/xstrtol.h
new file mode 100644
index 0000000..513855f
--- /dev/null
+++ b/contrib/tar/lib/xstrtol.h
@@ -0,0 +1,82 @@
+/* A more useful interface to strtol.
+ Copyright 1995, 1996, 1998, 1999, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef XSTRTOL_H_
+# define XSTRTOL_H_ 1
+
+# if HAVE_INTTYPES_H
+# include <inttypes.h> /* for uintmax_t */
+# endif
+
+# ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+# endif
+
+# ifndef _STRTOL_ERROR
+enum strtol_error
+ {
+ LONGINT_OK, LONGINT_INVALID, LONGINT_INVALID_SUFFIX_CHAR, LONGINT_OVERFLOW
+ };
+typedef enum strtol_error strtol_error;
+# endif
+
+# define _DECLARE_XSTRTOL(name, type) \
+ strtol_error \
+ name PARAMS ((const char *s, char **ptr, int base, \
+ type *val, const char *valid_suffixes));
+_DECLARE_XSTRTOL (xstrtol, long int)
+_DECLARE_XSTRTOL (xstrtoul, unsigned long int)
+_DECLARE_XSTRTOL (xstrtoimax, intmax_t)
+_DECLARE_XSTRTOL (xstrtoumax, uintmax_t)
+
+# define _STRTOL_ERROR(Exit_code, Str, Argument_type_string, Err) \
+ do \
+ { \
+ switch ((Err)) \
+ { \
+ case LONGINT_OK: \
+ abort (); \
+ \
+ case LONGINT_INVALID: \
+ error ((Exit_code), 0, "invalid %s `%s'", \
+ (Argument_type_string), (Str)); \
+ break; \
+ \
+ case LONGINT_INVALID_SUFFIX_CHAR: \
+ error ((Exit_code), 0, "invalid character following %s in `%s'", \
+ (Argument_type_string), (Str)); \
+ break; \
+ \
+ case LONGINT_OVERFLOW: \
+ error ((Exit_code), 0, "%s `%s' too large", \
+ (Argument_type_string), (Str)); \
+ break; \
+ } \
+ } \
+ while (0)
+
+# define STRTOL_FATAL_ERROR(Str, Argument_type_string, Err) \
+ _STRTOL_ERROR (2, Str, Argument_type_string, Err)
+
+# define STRTOL_FAIL_WARN(Str, Argument_type_string, Err) \
+ _STRTOL_ERROR (0, Str, Argument_type_string, Err)
+
+#endif /* not XSTRTOL_H_ */
diff --git a/contrib/tar/lib/xstrtoul.c b/contrib/tar/lib/xstrtoul.c
new file mode 100644
index 0000000..6140bbe
--- /dev/null
+++ b/contrib/tar/lib/xstrtoul.c
@@ -0,0 +1,4 @@
+#define __strtol strtoul
+#define __strtol_t unsigned long int
+#define __xstrtol xstrtoul
+#include "xstrtol.c"
diff --git a/contrib/tar/lib/xstrtoumax.c b/contrib/tar/lib/xstrtoumax.c
new file mode 100644
index 0000000..04d7cf9
--- /dev/null
+++ b/contrib/tar/lib/xstrtoumax.c
@@ -0,0 +1,31 @@
+/* xstrtoumax.c -- A more useful interface to strtoumax.
+ Copyright 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Paul Eggert. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#define __strtol strtoumax
+#define __strtol_t uintmax_t
+#define __xstrtol xstrtoumax
+#include "xstrtol.c"
diff --git a/contrib/tar/src/arith.h b/contrib/tar/src/arith.h
new file mode 100644
index 0000000..a1e532f
--- /dev/null
+++ b/contrib/tar/src/arith.h
@@ -0,0 +1,27 @@
+/* Long integers, for GNU tar.
+ Copyright 1999 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Handle large integers for calculating big tape lengths and the
+ like. In practice, double precision does for now. On the vast
+ majority of machines, it counts up to 2**52 bytes without any loss
+ of information, and counts up to 2**62 bytes if data are always
+ blocked in 1 kB boundaries. We'll need arbitrary precision
+ arithmetic anyway once we get into the 2**64 range, so there's no
+ point doing anything fancy before then. */
+
+#define TARLONG_FORMAT "%.0f"
+typedef double tarlong;
diff --git a/contrib/tar/src/buffer.c b/contrib/tar/src/buffer.c
new file mode 100644
index 0000000..1d164b4
--- /dev/null
+++ b/contrib/tar/src/buffer.c
@@ -0,0 +1,1600 @@
+/* Buffer management for tar.
+
+ Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free
+ Software Foundation, Inc.
+
+ Written by John Gilmore, on 1985-08-25.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+
+#include <signal.h>
+
+#if MSDOS
+# include <process.h>
+#endif
+
+#if XENIX
+# include <sys/inode.h>
+#endif
+
+#include <fnmatch.h>
+#include <human.h>
+#include <quotearg.h>
+
+#include "common.h"
+#include "rmt.h"
+
+#define PREAD 0 /* read file descriptor from pipe() */
+#define PWRITE 1 /* write file descriptor from pipe() */
+
+/* Number of retries before giving up on read. */
+#define READ_ERROR_MAX 10
+
+/* Globbing pattern to append to volume label if initial match failed. */
+#define VOLUME_LABEL_APPEND " Volume [1-9]*"
+
+/* Variables. */
+
+static tarlong prev_written; /* bytes written on previous volumes */
+static tarlong bytes_written; /* bytes written on this volume */
+
+/* FIXME: The following variables should ideally be static to this
+ module. However, this cannot be done yet. The cleanup continues! */
+
+union block *record_start; /* start of record of archive */
+union block *record_end; /* last+1 block of archive record */
+union block *current_block; /* current block of archive */
+enum access_mode access_mode; /* how do we handle the archive */
+off_t records_read; /* number of records read from this archive */
+off_t records_written; /* likewise, for records written */
+
+static struct stat archive_stat; /* stat block for archive file */
+
+static off_t record_start_block; /* block ordinal at record_start */
+
+/* Where we write list messages (not errors, not interactions) to. Stdout
+ unless we're writing a pipe, in which case stderr. */
+FILE *stdlis;
+
+static void backspace_output PARAMS ((void));
+static int new_volume PARAMS ((enum access_mode));
+static void archive_write_error PARAMS ((ssize_t)) __attribute__ ((noreturn));
+static void archive_read_error PARAMS ((void));
+
+#if !MSDOS
+/* Obnoxious test to see if dimwit is trying to dump the archive. */
+dev_t ar_dev;
+ino_t ar_ino;
+#endif
+
+/* PID of child program, if compress_option or remote archive access. */
+static pid_t child_pid;
+
+/* Error recovery stuff */
+static int read_error_count;
+
+/* Have we hit EOF yet? */
+static int hit_eof;
+
+/* Checkpointing counter */
+static int checkpoint;
+
+/* We're reading, but we just read the last block and its time to update. */
+/* As least EXTERN like this one as possible. FIXME! */
+extern int time_to_start_writing;
+
+int file_to_switch_to = -1; /* if remote update, close archive, and use
+ this descriptor to write to */
+
+static int volno = 1; /* which volume of a multi-volume tape we're
+ on */
+static int global_volno = 1; /* volume number to print in external
+ messages */
+
+/* The pointer save_name, which is set in function dump_file() of module
+ create.c, points to the original long filename instead of the new,
+ shorter mangled name that is set in start_header() of module create.c.
+ The pointer save_name is only used in multi-volume mode when the file
+ being processed is non-sparse; if a file is split between volumes, the
+ save_name is used in generating the LF_MULTIVOL record on the second
+ volume. (From Pierce Cantrell, 1991-08-13.) */
+
+char *save_name; /* name of the file we are currently writing */
+off_t save_totsize; /* total size of file we are writing, only
+ valid if save_name is nonzero */
+off_t save_sizeleft; /* where we are in the file we are writing,
+ only valid if save_name is nonzero */
+
+bool write_archive_to_stdout;
+
+/* Used by flush_read and flush_write to store the real info about saved
+ names. */
+static char *real_s_name;
+static off_t real_s_totsize;
+static off_t real_s_sizeleft;
+
+/* Functions. */
+
+void
+print_total_written (void)
+{
+ tarlong written = prev_written + bytes_written;
+ char bytes[sizeof (tarlong) * CHAR_BIT];
+ char abbr[LONGEST_HUMAN_READABLE + 1];
+ char rate[LONGEST_HUMAN_READABLE + 1];
+ double seconds;
+
+#if HAVE_CLOCK_GETTIME
+ struct timespec now;
+ if (clock_gettime (CLOCK_REALTIME, &now) == 0)
+ seconds = ((now.tv_sec - start_timespec.tv_sec)
+ + (now.tv_nsec - start_timespec.tv_nsec) / 1e9);
+ else
+#endif
+ seconds = time (0) - start_time;
+
+ sprintf (bytes, TARLONG_FORMAT, written);
+
+ /* Amanda 2.4.1p1 looks for "Total bytes written: [0-9][0-9]*". */
+ fprintf (stderr, _("Total bytes written: %s (%sB, %sB/s)\n"), bytes,
+ human_readable ((uintmax_t) written, abbr, 1, -1024),
+ (0 < seconds && written / seconds < (uintmax_t) -1
+ ? human_readable ((uintmax_t) (written / seconds), rate, 1, -1024)
+ : "?"));
+}
+
+/* Compute and return the block ordinal at current_block. */
+off_t
+current_block_ordinal (void)
+{
+ return record_start_block + (current_block - record_start);
+}
+
+/* If the EOF flag is set, reset it, as well as current_block, etc. */
+void
+reset_eof (void)
+{
+ if (hit_eof)
+ {
+ hit_eof = 0;
+ current_block = record_start;
+ record_end = record_start + blocking_factor;
+ access_mode = ACCESS_WRITE;
+ }
+}
+
+/* Return the location of the next available input or output block.
+ Return zero for EOF. Once we have returned zero, we just keep returning
+ it, to avoid accidentally going on to the next file on the tape. */
+union block *
+find_next_block (void)
+{
+ if (current_block == record_end)
+ {
+ if (hit_eof)
+ return 0;
+ flush_archive ();
+ if (current_block == record_end)
+ {
+ hit_eof = 1;
+ return 0;
+ }
+ }
+ return current_block;
+}
+
+/* Indicate that we have used all blocks up thru BLOCK.
+ FIXME: should the arg have an off-by-1? */
+void
+set_next_block_after (union block *block)
+{
+ while (block >= current_block)
+ current_block++;
+
+ /* Do *not* flush the archive here. If we do, the same argument to
+ set_next_block_after could mean the next block (if the input record
+ is exactly one block long), which is not what is intended. */
+
+ if (current_block > record_end)
+ abort ();
+}
+
+/* Return the number of bytes comprising the space between POINTER
+ through the end of the current buffer of blocks. This space is
+ available for filling with data, or taking data from. POINTER is
+ usually (but not always) the result previous find_next_block call. */
+size_t
+available_space_after (union block *pointer)
+{
+ return record_end->buffer - pointer->buffer;
+}
+
+/* Close file having descriptor FD, and abort if close unsuccessful. */
+static void
+xclose (int fd)
+{
+ if (close (fd) != 0)
+ close_error (_("(pipe)"));
+}
+
+/* Duplicate file descriptor FROM into becoming INTO.
+ INTO is closed first and has to be the next available slot. */
+static void
+xdup2 (int from, int into)
+{
+ if (from != into)
+ {
+ int status = close (into);
+
+ if (status != 0 && errno != EBADF)
+ {
+ int e = errno;
+ FATAL_ERROR ((0, e, _("Cannot close")));
+ }
+ status = dup (from);
+ if (status != into)
+ {
+ if (status < 0)
+ {
+ int e = errno;
+ FATAL_ERROR ((0, e, _("Cannot dup")));
+ }
+ abort ();
+ }
+ xclose (from);
+ }
+}
+
+#if MSDOS
+
+/* Set ARCHIVE for writing, then compressing an archive. */
+static void
+child_open_for_compress (void)
+{
+ FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
+}
+
+/* Set ARCHIVE for uncompressing, then reading an archive. */
+static void
+child_open_for_uncompress (void)
+{
+ FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
+}
+
+#else /* not MSDOS */
+
+/* Return nonzero if NAME is the name of a regular file, or if the file
+ does not exist (so it would be created as a regular file). */
+static int
+is_regular_file (const char *name)
+{
+ struct stat stbuf;
+
+ if (stat (name, &stbuf) == 0)
+ return S_ISREG (stbuf.st_mode);
+ else
+ return errno == ENOENT;
+}
+
+static ssize_t
+write_archive_buffer (void)
+{
+ ssize_t status;
+ ssize_t written = 0;
+
+ while (0 <= (status = rmtwrite (archive, record_start->buffer + written,
+ record_size - written)))
+ {
+ written += status;
+ if (written == record_size
+ || _isrmt (archive)
+ || ! (S_ISFIFO (archive_stat.st_mode)
+ || S_ISSOCK (archive_stat.st_mode)))
+ break;
+ }
+
+ return written ? written : status;
+}
+
+/* Set ARCHIVE for writing, then compressing an archive. */
+static void
+child_open_for_compress (void)
+{
+ int parent_pipe[2];
+ int child_pipe[2];
+ pid_t grandchild_pid;
+ int wait_status;
+
+ xpipe (parent_pipe);
+ child_pid = xfork ();
+
+ if (child_pid > 0)
+ {
+ /* The parent tar is still here! Just clean up. */
+
+ archive = parent_pipe[PWRITE];
+ xclose (parent_pipe[PREAD]);
+ return;
+ }
+
+ /* The new born child tar is here! */
+
+ program_name = _("tar (child)");
+
+ xdup2 (parent_pipe[PREAD], STDIN_FILENO);
+ xclose (parent_pipe[PWRITE]);
+
+ /* Check if we need a grandchild tar. This happens only if either:
+ a) we are writing stdout: to force reblocking;
+ b) the file is to be accessed by rmt: compressor doesn't know how;
+ c) the file is not a plain file. */
+
+ if (strcmp (archive_name_array[0], "-") != 0
+ && !_remdev (archive_name_array[0])
+ && is_regular_file (archive_name_array[0]))
+ {
+ if (backup_option)
+ maybe_backup_file (archive_name_array[0], 1);
+
+ /* We don't need a grandchild tar. Open the archive and launch the
+ compressor. */
+
+ archive = creat (archive_name_array[0], MODE_RW);
+ if (archive < 0)
+ {
+ int saved_errno = errno;
+
+ if (backup_option)
+ undo_last_backup ();
+ errno = saved_errno;
+ open_fatal (archive_name_array[0]);
+ }
+ xdup2 (archive, STDOUT_FILENO);
+ execlp (use_compress_program_option, use_compress_program_option,
+ (char *) 0);
+ exec_fatal (use_compress_program_option);
+ }
+
+ /* We do need a grandchild tar. */
+
+ xpipe (child_pipe);
+ grandchild_pid = xfork ();
+
+ if (grandchild_pid == 0)
+ {
+ /* The newborn grandchild tar is here! Launch the compressor. */
+
+ program_name = _("tar (grandchild)");
+
+ xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
+ xclose (child_pipe[PREAD]);
+ execlp (use_compress_program_option, use_compress_program_option,
+ (char *) 0);
+ exec_fatal (use_compress_program_option);
+ }
+
+ /* The child tar is still here! */
+
+ /* Prepare for reblocking the data from the compressor into the archive. */
+
+ xdup2 (child_pipe[PREAD], STDIN_FILENO);
+ xclose (child_pipe[PWRITE]);
+
+ if (strcmp (archive_name_array[0], "-") == 0)
+ archive = STDOUT_FILENO;
+ else
+ {
+ archive = rmtcreat (archive_name_array[0], MODE_RW, rsh_command_option);
+ if (archive < 0)
+ open_fatal (archive_name_array[0]);
+ }
+
+ /* Let's read out of the stdin pipe and write an archive. */
+
+ while (1)
+ {
+ ssize_t status = 0;
+ char *cursor;
+ size_t length;
+
+ /* Assemble a record. */
+
+ for (length = 0, cursor = record_start->buffer;
+ length < record_size;
+ length += status, cursor += status)
+ {
+ size_t size = record_size - length;
+
+ if (size < BLOCKSIZE)
+ size = BLOCKSIZE;
+ status = safe_read (STDIN_FILENO, cursor, size);
+ if (status <= 0)
+ break;
+ }
+
+ if (status < 0)
+ read_fatal (use_compress_program_option);
+
+ /* Copy the record. */
+
+ if (status == 0)
+ {
+ /* We hit the end of the file. Write last record at
+ full length, as the only role of the grandchild is
+ doing proper reblocking. */
+
+ if (length > 0)
+ {
+ memset (record_start->buffer + length, 0, record_size - length);
+ status = write_archive_buffer ();
+ if (status != record_size)
+ archive_write_error (status);
+ }
+
+ /* There is nothing else to read, break out. */
+ break;
+ }
+
+ status = write_archive_buffer ();
+ if (status != record_size)
+ archive_write_error (status);
+ }
+
+#if 0
+ close_archive ();
+#endif
+
+ /* Propagate any failure of the grandchild back to the parent. */
+
+ while (waitpid (grandchild_pid, &wait_status, 0) == -1)
+ if (errno != EINTR)
+ {
+ waitpid_error (use_compress_program_option);
+ break;
+ }
+
+ if (WIFSIGNALED (wait_status))
+ {
+ kill (child_pid, WTERMSIG (wait_status));
+ exit_status = TAREXIT_FAILURE;
+ }
+ else if (WEXITSTATUS (wait_status) != 0)
+ exit_status = WEXITSTATUS (wait_status);
+
+ exit (exit_status);
+}
+
+/* Set ARCHIVE for uncompressing, then reading an archive. */
+static void
+child_open_for_uncompress (void)
+{
+ int parent_pipe[2];
+ int child_pipe[2];
+ pid_t grandchild_pid;
+ int wait_status;
+
+ xpipe (parent_pipe);
+ child_pid = xfork ();
+
+ if (child_pid > 0)
+ {
+ /* The parent tar is still here! Just clean up. */
+
+ read_full_records_option = 1;
+ archive = parent_pipe[PREAD];
+ xclose (parent_pipe[PWRITE]);
+ return;
+ }
+
+ /* The newborn child tar is here! */
+
+ program_name = _("tar (child)");
+
+ xdup2 (parent_pipe[PWRITE], STDOUT_FILENO);
+ xclose (parent_pipe[PREAD]);
+
+ /* Check if we need a grandchild tar. This happens only if either:
+ a) we're reading stdin: to force unblocking;
+ b) the file is to be accessed by rmt: compressor doesn't know how;
+ c) the file is not a plain file. */
+
+ if (strcmp (archive_name_array[0], "-") != 0
+ && !_remdev (archive_name_array[0])
+ && is_regular_file (archive_name_array[0]))
+ {
+ /* We don't need a grandchild tar. Open the archive and lauch the
+ uncompressor. */
+
+ archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW);
+ if (archive < 0)
+ open_fatal (archive_name_array[0]);
+ xdup2 (archive, STDIN_FILENO);
+ execlp (use_compress_program_option, use_compress_program_option,
+ "-d", (char *) 0);
+ exec_fatal (use_compress_program_option);
+ }
+
+ /* We do need a grandchild tar. */
+
+ xpipe (child_pipe);
+ grandchild_pid = xfork ();
+
+ if (grandchild_pid == 0)
+ {
+ /* The newborn grandchild tar is here! Launch the uncompressor. */
+
+ program_name = _("tar (grandchild)");
+
+ xdup2 (child_pipe[PREAD], STDIN_FILENO);
+ xclose (child_pipe[PWRITE]);
+ execlp (use_compress_program_option, use_compress_program_option,
+ "-d", (char *) 0);
+ exec_fatal (use_compress_program_option);
+ }
+
+ /* The child tar is still here! */
+
+ /* Prepare for unblocking the data from the archive into the
+ uncompressor. */
+
+ xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
+ xclose (child_pipe[PREAD]);
+
+ if (strcmp (archive_name_array[0], "-") == 0)
+ archive = STDIN_FILENO;
+ else
+ archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
+ MODE_RW, rsh_command_option);
+ if (archive < 0)
+ open_fatal (archive_name_array[0]);
+
+ /* Let's read the archive and pipe it into stdout. */
+
+ while (1)
+ {
+ char *cursor;
+ size_t maximum;
+ size_t count;
+ ssize_t status;
+
+ read_error_count = 0;
+
+ error_loop:
+ status = rmtread (archive, record_start->buffer, record_size);
+ if (status < 0)
+ {
+ archive_read_error ();
+ goto error_loop;
+ }
+ if (status == 0)
+ break;
+ cursor = record_start->buffer;
+ maximum = status;
+ while (maximum)
+ {
+ count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE;
+ if (full_write (STDOUT_FILENO, cursor, count) != count)
+ write_error (use_compress_program_option);
+ cursor += count;
+ maximum -= count;
+ }
+ }
+
+ xclose (STDOUT_FILENO);
+#if 0
+ close_archive ();
+#endif
+
+ /* Propagate any failure of the grandchild back to the parent. */
+
+ while (waitpid (grandchild_pid, &wait_status, 0) == -1)
+ if (errno != EINTR)
+ {
+ waitpid_error (use_compress_program_option);
+ break;
+ }
+
+ if (WIFSIGNALED (wait_status))
+ {
+ kill (child_pid, WTERMSIG (wait_status));
+ exit_status = TAREXIT_FAILURE;
+ }
+ else if (WEXITSTATUS (wait_status) != 0)
+ exit_status = WEXITSTATUS (wait_status);
+
+ exit (exit_status);
+}
+
+#endif /* not MSDOS */
+
+/* Check the LABEL block against the volume label, seen as a globbing
+ pattern. Return true if the pattern matches. In case of failure,
+ retry matching a volume sequence number before giving up in
+ multi-volume mode. */
+static int
+check_label_pattern (union block *label)
+{
+ char *string;
+ int result;
+
+ if (! memchr (label->header.name, '\0', sizeof label->header.name))
+ return 0;
+
+ if (fnmatch (volume_label_option, label->header.name, 0) == 0)
+ return 1;
+
+ if (!multi_volume_option)
+ return 0;
+
+ string = xmalloc (strlen (volume_label_option)
+ + sizeof VOLUME_LABEL_APPEND + 1);
+ strcpy (string, volume_label_option);
+ strcat (string, VOLUME_LABEL_APPEND);
+ result = fnmatch (string, label->header.name, 0) == 0;
+ free (string);
+ return result;
+}
+
+/* Open an archive file. The argument specifies whether we are
+ reading or writing, or both. */
+void
+open_archive (enum access_mode wanted_access)
+{
+ int backed_up_flag = 0;
+
+ stdlis = to_stdout_option ? stderr : stdout;
+
+ if (record_size == 0)
+ FATAL_ERROR ((0, 0, _("Invalid value for record_size")));
+
+ if (archive_names == 0)
+ FATAL_ERROR ((0, 0, _("No archive name given")));
+
+ current_file_name = 0;
+ current_link_name = 0;
+ save_name = 0;
+ real_s_name = 0;
+
+ if (multi_volume_option)
+ {
+ if (verify_option)
+ FATAL_ERROR ((0, 0, _("Cannot verify multi-volume archives")));
+ record_start = valloc (record_size + (2 * BLOCKSIZE));
+ if (record_start)
+ record_start += 2;
+ }
+ else
+ record_start = valloc (record_size);
+ if (!record_start)
+ FATAL_ERROR ((0, 0, _("Cannot allocate memory for blocking factor %d"),
+ blocking_factor));
+
+ current_block = record_start;
+ record_end = record_start + blocking_factor;
+ /* When updating the archive, we start with reading. */
+ access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access;
+
+ if (use_compress_program_option)
+ {
+ if (multi_volume_option)
+ FATAL_ERROR ((0, 0, _("Cannot use multi-volume compressed archives")));
+ if (verify_option)
+ FATAL_ERROR ((0, 0, _("Cannot verify compressed archives")));
+
+ switch (wanted_access)
+ {
+ case ACCESS_READ:
+ child_open_for_uncompress ();
+ break;
+
+ case ACCESS_WRITE:
+ child_open_for_compress ();
+ break;
+
+ case ACCESS_UPDATE:
+ FATAL_ERROR ((0, 0, _("Cannot update compressed archives")));
+ break;
+ }
+
+ if (wanted_access == ACCESS_WRITE
+ && strcmp (archive_name_array[0], "-") == 0)
+ stdlis = stderr;
+ }
+ else if (strcmp (archive_name_array[0], "-") == 0)
+ {
+ read_full_records_option = 1; /* could be a pipe, be safe */
+ if (verify_option)
+ FATAL_ERROR ((0, 0, _("Cannot verify stdin/stdout archive")));
+
+ switch (wanted_access)
+ {
+ case ACCESS_READ:
+ archive = STDIN_FILENO;
+ break;
+
+ case ACCESS_WRITE:
+ archive = STDOUT_FILENO;
+ stdlis = stderr;
+ break;
+
+ case ACCESS_UPDATE:
+ archive = STDIN_FILENO;
+ stdlis = stderr;
+ write_archive_to_stdout = 1;
+ break;
+ }
+ }
+ else if (verify_option)
+ archive = rmtopen (archive_name_array[0], O_RDWR | O_CREAT | O_BINARY,
+ MODE_RW, rsh_command_option);
+ else
+ switch (wanted_access)
+ {
+ case ACCESS_READ:
+ archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
+ MODE_RW, rsh_command_option);
+ break;
+
+ case ACCESS_WRITE:
+ if (backup_option)
+ {
+ maybe_backup_file (archive_name_array[0], 1);
+ backed_up_flag = 1;
+ }
+ archive = rmtcreat (archive_name_array[0], MODE_RW,
+ rsh_command_option);
+ break;
+
+ case ACCESS_UPDATE:
+ archive = rmtopen (archive_name_array[0], O_RDWR | O_CREAT | O_BINARY,
+ MODE_RW, rsh_command_option);
+ break;
+ }
+
+ if (archive < 0
+ || (! _isrmt (archive) && fstat (archive, &archive_stat) < 0))
+ {
+ int saved_errno = errno;
+
+ if (backed_up_flag)
+ undo_last_backup ();
+ errno = saved_errno;
+ open_fatal (archive_name_array[0]);
+ }
+
+#if !MSDOS
+
+ /* Detect if outputting to "/dev/null". */
+ {
+ static char const dev_null[] = "/dev/null";
+ struct stat dev_null_stat;
+
+ dev_null_output =
+ (strcmp (archive_name_array[0], dev_null) == 0
+ || (! _isrmt (archive)
+ && S_ISCHR (archive_stat.st_mode)
+ && stat (dev_null, &dev_null_stat) == 0
+ && archive_stat.st_dev == dev_null_stat.st_dev
+ && archive_stat.st_ino == dev_null_stat.st_ino));
+ }
+
+ if (!_isrmt (archive) && S_ISREG (archive_stat.st_mode))
+ {
+ ar_dev = archive_stat.st_dev;
+ ar_ino = archive_stat.st_ino;
+ }
+ else
+ ar_dev = 0;
+
+#endif /* not MSDOS */
+
+#if MSDOS
+ setmode (archive, O_BINARY);
+#endif
+
+ switch (wanted_access)
+ {
+ case ACCESS_UPDATE:
+ records_written = 0;
+ case ACCESS_READ:
+ records_read = 0;
+ record_end = record_start; /* set up for 1st record = # 0 */
+ find_next_block (); /* read it in, check for EOF */
+
+ if (volume_label_option)
+ {
+ union block *label = find_next_block ();
+
+ if (!label)
+ FATAL_ERROR ((0, 0, _("Archive not labeled to match %s"),
+ quote (volume_label_option)));
+ if (!check_label_pattern (label))
+ FATAL_ERROR ((0, 0, _("Volume %s does not match %s"),
+ quote_n (0, label->header.name),
+ quote_n (1, volume_label_option)));
+ }
+ break;
+
+ case ACCESS_WRITE:
+ records_written = 0;
+ if (volume_label_option)
+ {
+ memset (record_start, 0, BLOCKSIZE);
+ if (multi_volume_option)
+ sprintf (record_start->header.name, "%s Volume 1",
+ volume_label_option);
+ else
+ strcpy (record_start->header.name, volume_label_option);
+
+ assign_string (&current_file_name, record_start->header.name);
+
+ record_start->header.typeflag = GNUTYPE_VOLHDR;
+ TIME_TO_CHARS (start_time, record_start->header.mtime);
+ finish_header (record_start);
+#if 0
+ current_block++;
+#endif
+ }
+ break;
+ }
+}
+
+/* Perform a write to flush the buffer. */
+void
+flush_write (void)
+{
+ int copy_back;
+ ssize_t status;
+
+ if (checkpoint_option && !(++checkpoint % 10))
+ WARN ((0, 0, _("Write checkpoint %d"), checkpoint));
+
+ if (tape_length_option && tape_length_option <= bytes_written)
+ {
+ errno = ENOSPC;
+ status = 0;
+ }
+ else if (dev_null_output)
+ status = record_size;
+ else
+ status = write_archive_buffer ();
+ if (status != record_size && !multi_volume_option)
+ archive_write_error (status);
+
+ if (status > 0)
+ {
+ records_written++;
+ bytes_written += status;
+ }
+
+ if (status == record_size)
+ {
+ if (multi_volume_option)
+ {
+ char *cursor;
+
+ if (!save_name)
+ {
+ assign_string (&real_s_name, 0);
+ real_s_totsize = 0;
+ real_s_sizeleft = 0;
+ return;
+ }
+
+ cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name);
+ while (ISSLASH (*cursor))
+ cursor++;
+
+ assign_string (&real_s_name, cursor);
+ real_s_totsize = save_totsize;
+ real_s_sizeleft = save_sizeleft;
+ }
+ return;
+ }
+
+ /* We're multivol. Panic if we didn't get the right kind of response. */
+
+ /* ENXIO is for the UNIX PC. */
+ if (status < 0 && errno != ENOSPC && errno != EIO && errno != ENXIO)
+ archive_write_error (status);
+
+ /* If error indicates a short write, we just move to the next tape. */
+
+ if (!new_volume (ACCESS_WRITE))
+ return;
+
+ if (totals_option)
+ prev_written += bytes_written;
+ bytes_written = 0;
+
+ if (volume_label_option && real_s_name)
+ {
+ copy_back = 2;
+ record_start -= 2;
+ }
+ else if (volume_label_option || real_s_name)
+ {
+ copy_back = 1;
+ record_start--;
+ }
+ else
+ copy_back = 0;
+
+ if (volume_label_option)
+ {
+ memset (record_start, 0, BLOCKSIZE);
+ sprintf (record_start->header.name, "%s Volume %d",
+ volume_label_option, volno);
+ TIME_TO_CHARS (start_time, record_start->header.mtime);
+ record_start->header.typeflag = GNUTYPE_VOLHDR;
+ finish_header (record_start);
+ }
+
+ if (real_s_name)
+ {
+ int tmp;
+
+ if (volume_label_option)
+ record_start++;
+
+ memset (record_start, 0, BLOCKSIZE);
+
+ /* FIXME: Michael P Urban writes: [a long name file] is being written
+ when a new volume rolls around [...] Looks like the wrong value is
+ being preserved in real_s_name, though. */
+
+ strcpy (record_start->header.name, real_s_name);
+ record_start->header.typeflag = GNUTYPE_MULTIVOL;
+ OFF_TO_CHARS (real_s_sizeleft, record_start->header.size);
+ OFF_TO_CHARS (real_s_totsize - real_s_sizeleft,
+ record_start->oldgnu_header.offset);
+ tmp = verbose_option;
+ verbose_option = 0;
+ finish_header (record_start);
+ verbose_option = tmp;
+
+ if (volume_label_option)
+ record_start--;
+ }
+
+ status = write_archive_buffer ();
+ if (status != record_size)
+ archive_write_error (status);
+
+ bytes_written += status;
+
+ if (copy_back)
+ {
+ record_start += copy_back;
+ memcpy (current_block,
+ record_start + blocking_factor - copy_back,
+ copy_back * BLOCKSIZE);
+ current_block += copy_back;
+
+ if (real_s_sizeleft >= copy_back * BLOCKSIZE)
+ real_s_sizeleft -= copy_back * BLOCKSIZE;
+ else if ((real_s_sizeleft + BLOCKSIZE - 1) / BLOCKSIZE <= copy_back)
+ assign_string (&real_s_name, 0);
+ else
+ {
+ char *cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name);
+
+ while (ISSLASH (*cursor))
+ cursor++;
+
+ assign_string (&real_s_name, cursor);
+ real_s_sizeleft = save_sizeleft;
+ real_s_totsize = save_totsize;
+ }
+ copy_back = 0;
+ }
+}
+
+/* Handle write errors on the archive. Write errors are always fatal.
+ Hitting the end of a volume does not cause a write error unless the
+ write was the first record of the volume. */
+static void
+archive_write_error (ssize_t status)
+{
+ /* It might be useful to know how much was written before the error
+ occurred. */
+ if (totals_option)
+ {
+ int e = errno;
+ print_total_written ();
+ errno = e;
+ }
+
+ write_fatal_details (*archive_name_cursor, status, record_size);
+}
+
+/* Handle read errors on the archive. If the read should be retried,
+ return to the caller. */
+static void
+archive_read_error (void)
+{
+ read_error (*archive_name_cursor);
+
+ if (record_start_block == 0)
+ FATAL_ERROR ((0, 0, _("At beginning of tape, quitting now")));
+
+ /* Read error in mid archive. We retry up to READ_ERROR_MAX times and
+ then give up on reading the archive. */
+
+ if (read_error_count++ > READ_ERROR_MAX)
+ FATAL_ERROR ((0, 0, _("Too many errors, quitting")));
+ return;
+}
+
+/* Perform a read to flush the buffer. */
+void
+flush_read (void)
+{
+ ssize_t status; /* result from system call */
+ size_t left; /* bytes left */
+ char *more; /* pointer to next byte to read */
+
+ if (checkpoint_option && !(++checkpoint % 10))
+ WARN ((0, 0, _("Read checkpoint %d"), checkpoint));
+
+ /* Clear the count of errors. This only applies to a single call to
+ flush_read. */
+
+ read_error_count = 0; /* clear error count */
+
+ if (write_archive_to_stdout && record_start_block != 0)
+ {
+ archive = STDOUT_FILENO;
+ status = write_archive_buffer ();
+ archive = STDIN_FILENO;
+ if (status != record_size)
+ archive_write_error (status);
+ }
+ if (multi_volume_option)
+ {
+ if (save_name)
+ {
+ char *cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name);
+
+ while (ISSLASH (*cursor))
+ cursor++;
+
+ assign_string (&real_s_name, cursor);
+ real_s_sizeleft = save_sizeleft;
+ real_s_totsize = save_totsize;
+ }
+ else
+ {
+ assign_string (&real_s_name, 0);
+ real_s_totsize = 0;
+ real_s_sizeleft = 0;
+ }
+ }
+
+ error_loop:
+ status = rmtread (archive, record_start->buffer, record_size);
+ if (status == record_size)
+ {
+ records_read++;
+ return;
+ }
+
+ if ((status == 0
+ || (status < 0 && errno == ENOSPC)
+ || (status > 0 && !read_full_records_option))
+ && multi_volume_option)
+ {
+ union block *cursor;
+
+ try_volume:
+ switch (subcommand_option)
+ {
+ case APPEND_SUBCOMMAND:
+ case CAT_SUBCOMMAND:
+ case UPDATE_SUBCOMMAND:
+ if (!new_volume (ACCESS_UPDATE))
+ return;
+ break;
+
+ default:
+ if (!new_volume (ACCESS_READ))
+ return;
+ break;
+ }
+
+ vol_error:
+ status = rmtread (archive, record_start->buffer, record_size);
+ if (status < 0)
+ {
+ archive_read_error ();
+ goto vol_error;
+ }
+ if (status != record_size)
+ goto short_read;
+
+ cursor = record_start;
+
+ if (cursor->header.typeflag == GNUTYPE_VOLHDR)
+ {
+ if (volume_label_option)
+ {
+ if (!check_label_pattern (cursor))
+ {
+ WARN ((0, 0, _("Volume %s does not match %s"),
+ quote_n (0, cursor->header.name),
+ quote_n (1, volume_label_option)));
+ volno--;
+ global_volno--;
+ goto try_volume;
+ }
+ }
+ if (verbose_option)
+ fprintf (stdlis, _("Reading %s\n"), quote (cursor->header.name));
+ cursor++;
+ }
+ else if (volume_label_option)
+ WARN ((0, 0, _("WARNING: No volume header")));
+
+ if (real_s_name)
+ {
+ uintmax_t s1, s2;
+ if (cursor->header.typeflag != GNUTYPE_MULTIVOL
+ || strcmp (cursor->header.name, real_s_name))
+ {
+ WARN ((0, 0, _("%s is not continued on this volume"),
+ quote (real_s_name)));
+ volno--;
+ global_volno--;
+ goto try_volume;
+ }
+ s1 = UINTMAX_FROM_HEADER (cursor->header.size);
+ s2 = UINTMAX_FROM_HEADER (cursor->oldgnu_header.offset);
+ if (real_s_totsize != s1 + s2 || s1 + s2 < s2)
+ {
+ char totsizebuf[UINTMAX_STRSIZE_BOUND];
+ char s1buf[UINTMAX_STRSIZE_BOUND];
+ char s2buf[UINTMAX_STRSIZE_BOUND];
+
+ WARN ((0, 0, _("%s is the wrong size (%s != %s + %s)"),
+ quote (cursor->header.name),
+ STRINGIFY_BIGINT (save_totsize, totsizebuf),
+ STRINGIFY_BIGINT (s1, s1buf),
+ STRINGIFY_BIGINT (s2, s2buf)));
+ volno--;
+ global_volno--;
+ goto try_volume;
+ }
+ if (real_s_totsize - real_s_sizeleft
+ != OFF_FROM_HEADER (cursor->oldgnu_header.offset))
+ {
+ WARN ((0, 0, _("This volume is out of sequence")));
+ volno--;
+ global_volno--;
+ goto try_volume;
+ }
+ cursor++;
+ }
+ current_block = cursor;
+ records_read++;
+ return;
+ }
+ else if (status < 0)
+ {
+ archive_read_error ();
+ goto error_loop; /* try again */
+ }
+
+ short_read:
+ more = record_start->buffer + status;
+ left = record_size - status;
+
+ while (left % BLOCKSIZE != 0
+ || (left && status && read_full_records_option))
+ {
+ if (status)
+ while ((status = rmtread (archive, more, left)) < 0)
+ archive_read_error ();
+
+ if (status == 0)
+ break;
+
+ if (! read_full_records_option)
+ FATAL_ERROR ((0, 0, _("Unaligned block (%lu bytes) in archive"),
+ (unsigned long) (record_size - left)));
+
+ /* User warned us about this. Fix up. */
+
+ left -= status;
+ more += status;
+ }
+
+ /* FIXME: for size=0, multi-volume support. On the first record, warn
+ about the problem. */
+
+ if (!read_full_records_option && verbose_option
+ && record_start_block == 0 && status > 0)
+ WARN ((0, 0, _("Record size = %lu blocks"),
+ (unsigned long) ((record_size - left) / BLOCKSIZE)));
+
+ record_end = record_start + (record_size - left) / BLOCKSIZE;
+ records_read++;
+}
+
+/* Flush the current buffer to/from the archive. */
+void
+flush_archive (void)
+{
+ record_start_block += record_end - record_start;
+ current_block = record_start;
+ record_end = record_start + blocking_factor;
+
+ if (access_mode == ACCESS_READ && time_to_start_writing)
+ {
+ access_mode = ACCESS_WRITE;
+ time_to_start_writing = 0;
+
+ if (file_to_switch_to >= 0)
+ {
+ if (rmtclose (archive) != 0)
+ close_warn (*archive_name_cursor);
+
+ archive = file_to_switch_to;
+ }
+ else
+ backspace_output ();
+ }
+
+ switch (access_mode)
+ {
+ case ACCESS_READ:
+ flush_read ();
+ break;
+
+ case ACCESS_WRITE:
+ flush_write ();
+ break;
+
+ case ACCESS_UPDATE:
+ abort ();
+ }
+}
+
+/* Backspace the archive descriptor by one record worth. If it's a
+ tape, MTIOCTOP will work. If it's something else, try to seek on
+ it. If we can't seek, we lose! */
+static void
+backspace_output (void)
+{
+#ifdef MTIOCTOP
+ {
+ struct mtop operation;
+
+ operation.mt_op = MTBSR;
+ operation.mt_count = 1;
+ if (rmtioctl (archive, MTIOCTOP, (char *) &operation) >= 0)
+ return;
+ if (errno == EIO && rmtioctl (archive, MTIOCTOP, (char *) &operation) >= 0)
+ return;
+ }
+#endif
+
+ {
+ off_t position = rmtlseek (archive, (off_t) 0, SEEK_CUR);
+
+ /* Seek back to the beginning of this record and start writing there. */
+
+ position -= record_size;
+ if (position < 0)
+ position = 0;
+ if (rmtlseek (archive, position, SEEK_SET) != position)
+ {
+ /* Lseek failed. Try a different method. */
+
+ WARN ((0, 0,
+ _("Cannot backspace archive file; it may be unreadable without -i")));
+
+ /* Replace the first part of the record with NULs. */
+
+ if (record_start->buffer != output_start)
+ memset (record_start->buffer, 0,
+ output_start - record_start->buffer);
+ }
+ }
+}
+
+/* Close the archive file. */
+void
+close_archive (void)
+{
+ if (time_to_start_writing || access_mode == ACCESS_WRITE)
+ flush_archive ();
+
+#if !MSDOS
+
+ /* Manage to fully drain a pipe we might be reading, so to not break it on
+ the producer after the EOF block. FIXME: one of these days, GNU tar
+ might become clever enough to just stop working, once there is no more
+ work to do, we might have to revise this area in such time. */
+
+ if (access_mode == ACCESS_READ
+ && ! _isrmt (archive)
+ && (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode)))
+ while (rmtread (archive, record_start->buffer, record_size) > 0)
+ continue;
+#endif
+
+ if (verify_option)
+ verify_volume ();
+
+ if (rmtclose (archive) != 0)
+ close_warn (*archive_name_cursor);
+
+#if !MSDOS
+
+ if (child_pid)
+ {
+ int wait_status;
+
+ while (waitpid (child_pid, &wait_status, 0) == -1)
+ if (errno != EINTR)
+ {
+ waitpid_error (use_compress_program_option);
+ break;
+ }
+
+ if (WIFSIGNALED (wait_status))
+ ERROR ((0, 0, _("Child died with signal %d"),
+ WTERMSIG (wait_status)));
+ else if (WEXITSTATUS (wait_status) != 0)
+ ERROR ((0, 0, _("Child returned status %d"),
+ WEXITSTATUS (wait_status)));
+ }
+#endif /* !MSDOS */
+
+ if (current_file_name)
+ free (current_file_name);
+ if (current_link_name)
+ free (current_link_name);
+ if (save_name)
+ free (save_name);
+ if (real_s_name)
+ free (real_s_name);
+ free (multi_volume_option ? record_start - 2 : record_start);
+}
+
+/* Called to initialize the global volume number. */
+void
+init_volume_number (void)
+{
+ FILE *file = fopen (volno_file_option, "r");
+
+ if (file)
+ {
+ if (fscanf (file, "%d", &global_volno) != 1
+ || global_volno < 0)
+ FATAL_ERROR ((0, 0, _("%s: contains invalid volume number"),
+ quotearg_colon (volno_file_option)));
+ if (ferror (file))
+ read_error (volno_file_option);
+ if (fclose (file) != 0)
+ close_error (volno_file_option);
+ }
+ else if (errno != ENOENT)
+ open_error (volno_file_option);
+}
+
+/* Called to write out the closing global volume number. */
+void
+closeout_volume_number (void)
+{
+ FILE *file = fopen (volno_file_option, "w");
+
+ if (file)
+ {
+ fprintf (file, "%d\n", global_volno);
+ if (ferror (file))
+ write_error (volno_file_option);
+ if (fclose (file) != 0)
+ close_error (volno_file_option);
+ }
+ else
+ open_error (volno_file_option);
+}
+
+/* We've hit the end of the old volume. Close it and open the next one.
+ Return nonzero on success. */
+static int
+new_volume (enum access_mode access)
+{
+ static FILE *read_file;
+ static int looped;
+
+ if (!read_file && !info_script_option)
+ /* FIXME: if fopen is used, it will never be closed. */
+ read_file = archive == STDIN_FILENO ? fopen (TTY_NAME, "r") : stdin;
+
+ if (now_verifying)
+ return 0;
+ if (verify_option)
+ verify_volume ();
+
+ if (rmtclose (archive) != 0)
+ close_warn (*archive_name_cursor);
+
+ global_volno++;
+ if (global_volno < 0)
+ FATAL_ERROR ((0, 0, _("Volume number overflow")));
+ volno++;
+ archive_name_cursor++;
+ if (archive_name_cursor == archive_name_array + archive_names)
+ {
+ archive_name_cursor = archive_name_array;
+ looped = 1;
+ }
+
+ tryagain:
+ if (looped)
+ {
+ /* We have to prompt from now on. */
+
+ if (info_script_option)
+ {
+ if (volno_file_option)
+ closeout_volume_number ();
+ if (system (info_script_option) != 0)
+ FATAL_ERROR ((0, 0, _("`%s' command failed"), info_script_option));
+ }
+ else
+ while (1)
+ {
+ char input_buffer[80];
+
+ fputc ('\007', stderr);
+ fprintf (stderr,
+ _("Prepare volume #%d for %s and hit return: "),
+ global_volno, quote (*archive_name_cursor));
+ fflush (stderr);
+
+ if (fgets (input_buffer, sizeof input_buffer, read_file) == 0)
+ {
+ WARN ((0, 0, _("EOF where user reply was expected")));
+
+ if (subcommand_option != EXTRACT_SUBCOMMAND
+ && subcommand_option != LIST_SUBCOMMAND
+ && subcommand_option != DIFF_SUBCOMMAND)
+ WARN ((0, 0, _("WARNING: Archive is incomplete")));
+
+ fatal_exit ();
+ }
+ if (input_buffer[0] == '\n'
+ || input_buffer[0] == 'y'
+ || input_buffer[0] == 'Y')
+ break;
+
+ switch (input_buffer[0])
+ {
+ case '?':
+ {
+ fprintf (stderr, _("\
+ n [name] Give a new file name for the next (and subsequent) volume(s)\n\
+ q Abort tar\n\
+ ! Spawn a subshell\n\
+ ? Print this list\n"));
+ }
+ break;
+
+ case 'q':
+ /* Quit. */
+
+ WARN ((0, 0, _("No new volume; exiting.\n")));
+
+ if (subcommand_option != EXTRACT_SUBCOMMAND
+ && subcommand_option != LIST_SUBCOMMAND
+ && subcommand_option != DIFF_SUBCOMMAND)
+ WARN ((0, 0, _("WARNING: Archive is incomplete")));
+
+ fatal_exit ();
+
+ case 'n':
+ /* Get new file name. */
+
+ {
+ char *name = &input_buffer[1];
+ char *cursor;
+
+ while (*name == ' ' || *name == '\t')
+ name++;
+ cursor = name;
+ while (*cursor && *cursor != '\n')
+ cursor++;
+ *cursor = '\0';
+
+ /* FIXME: the following allocation is never reclaimed. */
+ *archive_name_cursor = xstrdup (name);
+ }
+ break;
+
+ case '!':
+#if MSDOS
+ spawnl (P_WAIT, getenv ("COMSPEC"), "-", 0);
+#else /* not MSDOS */
+ {
+ pid_t child;
+ const char *shell = getenv ("SHELL");
+ if (! shell)
+ shell = "/bin/sh";
+ child = xfork ();
+ if (child == 0)
+ {
+ execlp (shell, "-sh", "-i", 0);
+ exec_fatal (shell);
+ }
+ else
+ {
+ int wait_status;
+ while (waitpid (child, &wait_status, 0) == -1)
+ if (errno != EINTR)
+ {
+ waitpid_error (shell);
+ break;
+ }
+ }
+ }
+#endif /* not MSDOS */
+ break;
+ }
+ }
+ }
+
+ if (verify_option)
+ archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW,
+ rsh_command_option);
+ else
+ switch (access)
+ {
+ case ACCESS_READ:
+ archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW,
+ rsh_command_option);
+ break;
+
+ case ACCESS_WRITE:
+ if (backup_option)
+ maybe_backup_file (*archive_name_cursor, 1);
+ archive = rmtcreat (*archive_name_cursor, MODE_RW,
+ rsh_command_option);
+ break;
+
+ case ACCESS_UPDATE:
+ archive = rmtopen (*archive_name_cursor, O_RDWR | O_CREAT, MODE_RW,
+ rsh_command_option);
+ break;
+ }
+
+ if (archive < 0)
+ {
+ open_warn (*archive_name_cursor);
+ if (!verify_option && access == ACCESS_WRITE && backup_option)
+ undo_last_backup ();
+ goto tryagain;
+ }
+
+#if MSDOS
+ setmode (archive, O_BINARY);
+#endif
+
+ return 1;
+}
diff --git a/contrib/tar/src/common.h b/contrib/tar/src/common.h
new file mode 100644
index 0000000..4ea6a52
--- /dev/null
+++ b/contrib/tar/src/common.h
@@ -0,0 +1,578 @@
+/* Common declarations for the tar program.
+
+ Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free
+ Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Declare the GNU tar archive format. */
+#include "tar.h"
+
+/* The checksum field is filled with this while the checksum is computed. */
+#define CHKBLANKS " " /* 8 blanks, no null */
+
+/* Some constants from POSIX are given names. */
+#define NAME_FIELD_SIZE 100
+#define PREFIX_FIELD_SIZE 155
+#define UNAME_FIELD_SIZE 32
+#define GNAME_FIELD_SIZE 32
+
+/* Some various global definitions. */
+
+/* Name of file to use for interacting with user. */
+#if MSDOS
+# define TTY_NAME "con"
+#else
+# define TTY_NAME "/dev/tty"
+#endif
+
+/* GLOBAL is defined to empty in tar.c only, and left alone in other *.c
+ modules. Here, we merely set it to "extern" if it is not already set.
+ GNU tar does depend on the system loader to preset all GLOBAL variables to
+ neutral (or zero) values, explicit initialization is usually not done. */
+#ifndef GLOBAL
+# define GLOBAL extern
+#endif
+
+/* Exit status for GNU tar. Let's try to keep this list as simple as
+ possible. -d option strongly invites a status different for unequal
+ comparison and other errors. */
+GLOBAL int exit_status;
+
+#define TAREXIT_SUCCESS 0
+#define TAREXIT_DIFFERS 1
+#define TAREXIT_FAILURE 2
+
+/* Both WARN and ERROR write a message on stderr and continue processing,
+ however ERROR manages so tar will exit unsuccessfully. FATAL_ERROR
+ writes a message on stderr and aborts immediately, with another message
+ line telling so. USAGE_ERROR works like FATAL_ERROR except that the
+ other message line suggests trying --help. All four macros accept a
+ single argument of the form ((0, errno, _("FORMAT"), Args...)). errno
+ is zero when the error is not being detected by the system. */
+
+#define WARN(Args) \
+ error Args
+#define ERROR(Args) \
+ (error Args, exit_status = TAREXIT_FAILURE)
+#define FATAL_ERROR(Args) \
+ (error Args, fatal_exit ())
+#define USAGE_ERROR(Args) \
+ (error Args, usage (TAREXIT_FAILURE))
+
+/* Information gleaned from the command line. */
+
+#include "arith.h"
+#include <backupfile.h>
+#include <exclude.h>
+#include <modechange.h>
+#include <safe-read.h>
+#include <full-write.h>
+
+/* Log base 2 of common values. */
+#define LG_8 3
+#define LG_64 6
+#define LG_256 8
+
+/* Name of this program. */
+GLOBAL const char *program_name;
+
+/* Main command option. */
+
+enum subcommand
+{
+ UNKNOWN_SUBCOMMAND, /* none of the following */
+ APPEND_SUBCOMMAND, /* -r */
+ CAT_SUBCOMMAND, /* -A */
+ CREATE_SUBCOMMAND, /* -c */
+ DELETE_SUBCOMMAND, /* -D */
+ DIFF_SUBCOMMAND, /* -d */
+ EXTRACT_SUBCOMMAND, /* -x */
+ LIST_SUBCOMMAND, /* -t */
+ UPDATE_SUBCOMMAND /* -u */
+};
+
+GLOBAL enum subcommand subcommand_option;
+
+/* Selected format for output archive. */
+GLOBAL enum archive_format archive_format;
+
+/* Either NL or NUL, as decided by the --null option. */
+GLOBAL char filename_terminator;
+
+/* Size of each record, once in blocks, once in bytes. Those two variables
+ are always related, the second being BLOCKSIZE times the first. They do
+ not have _option in their name, even if their values is derived from
+ option decoding, as these are especially important in tar. */
+GLOBAL int blocking_factor;
+GLOBAL size_t record_size;
+
+/* Boolean value. */
+GLOBAL int absolute_names_option;
+
+/* This variable tells how to interpret newer_mtime_option, below. If zero,
+ files get archived if their mtime is not less than newer_mtime_option.
+ If nonzero, files get archived if *either* their ctime or mtime is not less
+ than newer_mtime_option. */
+GLOBAL int after_date_option;
+
+/* Boolean value. */
+GLOBAL int atime_preserve_option;
+
+/* Boolean value. */
+GLOBAL int backup_option;
+
+/* Type of backups being made. */
+GLOBAL enum backup_type backup_type;
+
+/* Boolean value. */
+GLOBAL int block_number_option;
+
+/* Boolean value. */
+GLOBAL int checkpoint_option;
+
+/* Specified name of compression program, or "gzip" as implied by -z. */
+GLOBAL const char *use_compress_program_option;
+
+/* Boolean value. */
+GLOBAL int dereference_option;
+
+/* Patterns that match file names to be excluded. */
+GLOBAL struct exclude *excluded;
+
+/* Specified file containing names to work on. */
+GLOBAL const char *files_from_option;
+
+/* Boolean value. */
+GLOBAL int force_local_option;
+
+/* Specified value to be put into tar file in place of stat () results, or
+ just -1 if such an override should not take place. */
+GLOBAL gid_t group_option;
+
+/* Boolean value. */
+GLOBAL int ignore_failed_read_option;
+
+/* Boolean value. */
+GLOBAL int ignore_zeros_option;
+
+/* Boolean value. */
+GLOBAL int incremental_option;
+
+/* Specified name of script to run at end of each tape change. */
+GLOBAL const char *info_script_option;
+
+/* Boolean value. */
+GLOBAL int interactive_option;
+
+enum old_files
+{
+ DEFAULT_OLD_FILES, /* default */
+ UNLINK_FIRST_OLD_FILES, /* --unlink-first */
+ KEEP_OLD_FILES, /* --keep-old-files */
+ OVERWRITE_OLD_DIRS, /* --overwrite-dir */
+ OVERWRITE_OLD_FILES /* --overwrite */
+};
+GLOBAL enum old_files old_files_option;
+
+/* Specified file name for incremental list. */
+GLOBAL const char *listed_incremental_option;
+
+/* Specified mode change string. */
+GLOBAL struct mode_change *mode_option;
+
+/* Boolean value. */
+GLOBAL int multi_volume_option;
+
+/* The same variable hold the time, whether mtime or ctime. Just fake a
+ non-existing option, for making the code clearer, elsewhere. */
+#define newer_ctime_option newer_mtime_option
+
+/* Specified threshold date and time. Files having an older time stamp
+ do not get archived (also see after_date_option above). */
+GLOBAL time_t newer_mtime_option;
+
+/* Zero if there is no recursion, otherwise FNM_LEADING_DIR. */
+GLOBAL int recursion_option;
+
+/* Boolean value. */
+GLOBAL int numeric_owner_option;
+
+/* Boolean value. */
+GLOBAL int one_file_system_option;
+
+/* Specified value to be put into tar file in place of stat () results, or
+ just -1 if such an override should not take place. */
+GLOBAL uid_t owner_option;
+
+/* Boolean value. */
+GLOBAL int recursive_unlink_option;
+
+/* Boolean value. */
+GLOBAL int read_full_records_option;
+
+/* Boolean value. */
+GLOBAL int remove_files_option;
+
+/* Specified remote shell command. */
+GLOBAL const char *rsh_command_option;
+
+/* Boolean value. */
+GLOBAL int same_order_option;
+
+/* If positive, preserve ownership when extracting. */
+GLOBAL int same_owner_option;
+
+/* If positive, preserve permissions when extracting. */
+GLOBAL int same_permissions_option;
+
+/* Boolean value. */
+GLOBAL int show_omitted_dirs_option;
+
+/* Boolean value. */
+GLOBAL int sparse_option;
+
+/* Boolean value. */
+GLOBAL int starting_file_option;
+
+/* Specified maximum byte length of each tape volume (multiple of 1024). */
+GLOBAL tarlong tape_length_option;
+
+/* Boolean value. */
+GLOBAL int to_stdout_option;
+
+/* Boolean value. */
+GLOBAL int totals_option;
+
+/* Boolean value. */
+GLOBAL int touch_option;
+
+/* Count how many times the option has been set, multiple setting yields
+ more verbose behavior. Value 0 means no verbosity, 1 means file name
+ only, 2 means file name and all attributes. More than 2 is just like 2. */
+GLOBAL int verbose_option;
+
+/* Boolean value. */
+GLOBAL int verify_option;
+
+/* Specified name of file containing the volume number. */
+GLOBAL const char *volno_file_option;
+
+/* Specified value or pattern. */
+GLOBAL const char *volume_label_option;
+
+/* Other global variables. */
+
+/* File descriptor for archive file. */
+GLOBAL int archive;
+
+/* Nonzero when outputting to /dev/null. */
+GLOBAL int dev_null_output;
+
+/* Timestamp for when we started execution. */
+#if HAVE_CLOCK_GETTIME
+ GLOBAL struct timespec start_timespec;
+# define start_time (start_timespec.tv_sec)
+#else
+ GLOBAL time_t start_time;
+#endif
+
+/* Name of file for the current archive entry. */
+GLOBAL char *current_file_name;
+
+/* Name of link for the current archive entry. */
+GLOBAL char *current_link_name;
+
+/* List of tape drive names, number of such tape drives, allocated number,
+ and current cursor in list. */
+GLOBAL const char **archive_name_array;
+GLOBAL int archive_names;
+GLOBAL int allocated_archive_names;
+GLOBAL const char **archive_name_cursor;
+
+/* Structure for keeping track of filenames and lists thereof. */
+struct name
+ {
+ struct name *next;
+ size_t length; /* cached strlen(name) */
+ char found; /* a matching file has been found */
+ char firstch; /* first char is literally matched */
+ char regexp; /* this name is a regexp, not literal */
+ int change_dir; /* set with the -C option */
+ char const *dir_contents; /* for incremental_option */
+ char fake; /* dummy entry */
+ char name[1];
+ };
+
+/* Information about a sparse file. */
+struct sp_array
+ {
+ off_t offset;
+ size_t numbytes;
+ };
+GLOBAL struct sp_array *sparsearray;
+
+/* Number of elements in sparsearray. */
+GLOBAL int sp_array_size;
+
+/* Declarations for each module. */
+
+/* FIXME: compare.c should not directly handle the following variable,
+ instead, this should be done in buffer.c only. */
+
+enum access_mode
+{
+ ACCESS_READ,
+ ACCESS_WRITE,
+ ACCESS_UPDATE
+};
+extern enum access_mode access_mode;
+
+/* Module buffer.c. */
+
+extern FILE *stdlis;
+extern char *save_name;
+extern off_t save_sizeleft;
+extern off_t save_totsize;
+extern bool write_archive_to_stdout;
+
+size_t available_space_after PARAMS ((union block *));
+off_t current_block_ordinal PARAMS ((void));
+void close_archive PARAMS ((void));
+void closeout_volume_number PARAMS ((void));
+union block *find_next_block PARAMS ((void));
+void flush_read PARAMS ((void));
+void flush_write PARAMS ((void));
+void flush_archive PARAMS ((void));
+void init_volume_number PARAMS ((void));
+void open_archive PARAMS ((enum access_mode));
+void print_total_written PARAMS ((void));
+void reset_eof PARAMS ((void));
+void set_next_block_after PARAMS ((union block *));
+
+/* Module create.c. */
+
+void create_archive PARAMS ((void));
+void dump_file PARAMS ((char *, int, dev_t));
+void finish_header PARAMS ((union block *));
+void write_eot PARAMS ((void));
+
+#define GID_TO_CHARS(val, where) gid_to_chars (val, where, sizeof (where))
+#define MAJOR_TO_CHARS(val, where) major_to_chars (val, where, sizeof (where))
+#define MINOR_TO_CHARS(val, where) minor_to_chars (val, where, sizeof (where))
+#define MODE_TO_CHARS(val, where) mode_to_chars (val, where, sizeof (where))
+#define OFF_TO_CHARS(val, where) off_to_chars (val, where, sizeof (where))
+#define SIZE_TO_CHARS(val, where) size_to_chars (val, where, sizeof (where))
+#define TIME_TO_CHARS(val, where) time_to_chars (val, where, sizeof (where))
+#define UID_TO_CHARS(val, where) uid_to_chars (val, where, sizeof (where))
+#define UINTMAX_TO_CHARS(val, where) uintmax_to_chars (val, where, sizeof (where))
+
+void gid_to_chars PARAMS ((gid_t, char *, size_t));
+void major_to_chars PARAMS ((major_t, char *, size_t));
+void minor_to_chars PARAMS ((minor_t, char *, size_t));
+void mode_to_chars PARAMS ((mode_t, char *, size_t));
+void off_to_chars PARAMS ((off_t, char *, size_t));
+void size_to_chars PARAMS ((size_t, char *, size_t));
+void time_to_chars PARAMS ((time_t, char *, size_t));
+void uid_to_chars PARAMS ((uid_t, char *, size_t));
+void uintmax_to_chars PARAMS ((uintmax_t, char *, size_t));
+
+/* Module diffarch.c. */
+
+extern int now_verifying;
+
+void diff_archive PARAMS ((void));
+void diff_init PARAMS ((void));
+void verify_volume PARAMS ((void));
+
+/* Module extract.c. */
+
+extern int we_are_root;
+void extr_init PARAMS ((void));
+void extract_archive PARAMS ((void));
+void extract_finish PARAMS ((void));
+void fatal_exit PARAMS ((void)) __attribute__ ((noreturn));
+
+/* Module delete.c. */
+
+void delete_archive_members PARAMS ((void));
+
+/* Module incremen.c. */
+
+char *get_directory_contents PARAMS ((char *, dev_t));
+void read_directory_file PARAMS ((void));
+void write_directory_file PARAMS ((void));
+void gnu_restore PARAMS ((size_t));
+
+/* Module list.c. */
+
+enum read_header
+{
+ HEADER_STILL_UNREAD, /* for when read_header has not been called */
+ HEADER_SUCCESS, /* header successfully read and checksummed */
+ HEADER_SUCCESS_EXTENDED, /* likewise, but we got an extended header */
+ HEADER_ZERO_BLOCK, /* zero block where header expected */
+ HEADER_END_OF_FILE, /* true end of file while header expected */
+ HEADER_FAILURE /* ill-formed header, or bad checksum */
+};
+
+extern union block *current_header;
+extern struct stat current_stat;
+extern enum archive_format current_format;
+
+void decode_header PARAMS ((union block *, struct stat *,
+ enum archive_format *, int));
+#define STRINGIFY_BIGINT(i, b) \
+ stringify_uintmax_t_backwards ((uintmax_t) (i), (b) + UINTMAX_STRSIZE_BOUND)
+char *stringify_uintmax_t_backwards PARAMS ((uintmax_t, char *));
+char const *tartime PARAMS ((time_t));
+
+#define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where))
+#define MAJOR_FROM_HEADER(where) major_from_header (where, sizeof (where))
+#define MINOR_FROM_HEADER(where) minor_from_header (where, sizeof (where))
+#define MODE_FROM_HEADER(where) mode_from_header (where, sizeof (where))
+#define OFF_FROM_HEADER(where) off_from_header (where, sizeof (where))
+#define SIZE_FROM_HEADER(where) size_from_header (where, sizeof (where))
+#define TIME_FROM_HEADER(where) time_from_header (where, sizeof (where))
+#define UID_FROM_HEADER(where) uid_from_header (where, sizeof (where))
+#define UINTMAX_FROM_HEADER(where) uintmax_from_header (where, sizeof (where))
+
+gid_t gid_from_header PARAMS ((const char *, size_t));
+major_t major_from_header PARAMS ((const char *, size_t));
+minor_t minor_from_header PARAMS ((const char *, size_t));
+mode_t mode_from_header PARAMS ((const char *, size_t));
+off_t off_from_header PARAMS ((const char *, size_t));
+size_t size_from_header PARAMS ((const char *, size_t));
+time_t time_from_header PARAMS ((const char *, size_t));
+uid_t uid_from_header PARAMS ((const char *, size_t));
+uintmax_t uintmax_from_header PARAMS ((const char *, size_t));
+
+void list_archive PARAMS ((void));
+void print_for_mkdir PARAMS ((char *, int, mode_t));
+void print_header PARAMS ((void));
+void read_and PARAMS ((void (*do_) ()));
+enum read_header read_header PARAMS ((bool));
+void skip_file PARAMS ((off_t));
+void skip_member PARAMS ((void));
+
+/* Module mangle.c. */
+
+void extract_mangle PARAMS ((void));
+
+/* Module misc.c. */
+
+void assign_string PARAMS ((char **, const char *));
+char *quote_copy_string PARAMS ((const char *));
+int unquote_string PARAMS ((char *));
+
+int contains_dot_dot PARAMS ((char const *));
+
+int remove_any_file PARAMS ((const char *, int));
+int maybe_backup_file PARAMS ((const char *, int));
+void undo_last_backup PARAMS ((void));
+
+int deref_stat PARAMS ((int, char const *, struct stat *));
+
+int chdir_arg PARAMS ((char const *));
+void chdir_do PARAMS ((int));
+
+void decode_mode PARAMS ((mode_t, char *));
+
+void chdir_fatal PARAMS ((char const *)) __attribute__ ((noreturn));
+void chmod_error_details PARAMS ((char const *, mode_t));
+void chown_error_details PARAMS ((char const *, uid_t, gid_t));
+void close_error PARAMS ((char const *));
+void close_warn PARAMS ((char const *));
+void exec_fatal PARAMS ((char const *)) __attribute__ ((noreturn));
+void link_error PARAMS ((char const *, char const *));
+void mkdir_error PARAMS ((char const *));
+void mkfifo_error PARAMS ((char const *));
+void mknod_error PARAMS ((char const *));
+void open_error PARAMS ((char const *));
+void open_fatal PARAMS ((char const *)) __attribute__ ((noreturn));
+void open_warn PARAMS ((char const *));
+void read_error PARAMS ((char const *));
+void read_error_details PARAMS ((char const *, off_t, size_t));
+void read_fatal PARAMS ((char const *)) __attribute__ ((noreturn));
+void read_fatal_details PARAMS ((char const *, off_t, size_t));
+void read_warn_details PARAMS ((char const *, off_t, size_t));
+void readlink_error PARAMS ((char const *));
+void readlink_warn PARAMS ((char const *));
+void savedir_error PARAMS ((char const *));
+void savedir_warn PARAMS ((char const *));
+void seek_error PARAMS ((char const *));
+void seek_error_details PARAMS ((char const *, off_t));
+void seek_warn PARAMS ((char const *));
+void seek_warn_details PARAMS ((char const *, off_t));
+void stat_error PARAMS ((char const *));
+void stat_warn PARAMS ((char const *));
+void symlink_error PARAMS ((char const *, char const *));
+void truncate_error PARAMS ((char const *));
+void truncate_warn PARAMS ((char const *));
+void unlink_error PARAMS ((char const *));
+void utime_error PARAMS ((char const *));
+void waitpid_error PARAMS ((char const *));
+void write_error PARAMS ((char const *));
+void write_error_details PARAMS ((char const *, ssize_t, size_t));
+void write_fatal PARAMS ((char const *)) __attribute__ ((noreturn));
+void write_fatal_details PARAMS ((char const *, ssize_t, size_t))
+ __attribute__ ((noreturn));
+
+pid_t xfork PARAMS ((void));
+void xpipe PARAMS ((int[2]));
+
+char const *quote PARAMS ((char const *));
+char const *quote_n PARAMS ((int, char const *));
+
+/* Module names.c. */
+
+extern struct name *gnu_list_name;
+
+void gid_to_gname PARAMS ((gid_t, char gname[GNAME_FIELD_SIZE]));
+int gname_to_gid PARAMS ((char gname[GNAME_FIELD_SIZE], gid_t *));
+void uid_to_uname PARAMS ((uid_t, char uname[UNAME_FIELD_SIZE]));
+int uname_to_uid PARAMS ((char uname[UNAME_FIELD_SIZE], uid_t *));
+
+void init_names PARAMS ((void));
+void name_add PARAMS ((const char *));
+void name_init PARAMS ((int, char *const *));
+void name_term PARAMS ((void));
+char *name_next PARAMS ((int));
+void name_close PARAMS ((void));
+void name_gather PARAMS ((void));
+struct name *addname PARAMS ((char const *, int));
+int name_match PARAMS ((const char *));
+void names_notfound PARAMS ((void));
+void collect_and_sort_names PARAMS ((void));
+struct name *name_scan PARAMS ((const char *));
+char *name_from_list PARAMS ((void));
+void blank_name_list PARAMS ((void));
+char *new_name PARAMS ((const char *, const char *));
+
+bool excluded_name PARAMS ((char const *));
+
+void add_avoided_name PARAMS ((char const *));
+int is_avoided_name PARAMS ((char const *));
+
+/* Module tar.c. */
+
+int confirm PARAMS ((const char *, const char *));
+void request_stdin PARAMS ((const char *));
+
+/* Module update.c. */
+
+extern char *output_start;
+
+void update_archive PARAMS ((void));
diff --git a/contrib/tar/src/compare.c b/contrib/tar/src/compare.c
new file mode 100644
index 0000000..c3b9bb9
--- /dev/null
+++ b/contrib/tar/src/compare.c
@@ -0,0 +1,817 @@
+/* Diff files from a tar archive.
+
+ Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free
+ Software Foundation, Inc.
+
+ Written by John Gilmore, on 1987-04-30.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+
+#if HAVE_UTIME_H
+# include <utime.h>
+#else
+struct utimbuf
+ {
+ long actime;
+ long modtime;
+ };
+#endif
+
+#if HAVE_LINUX_FD_H
+# include <linux/fd.h>
+#endif
+
+#include <quotearg.h>
+
+#include "common.h"
+#include "rmt.h"
+
+/* Spare space for messages, hopefully safe even after gettext. */
+#define MESSAGE_BUFFER_SIZE 100
+
+/* Nonzero if we are verifying at the moment. */
+int now_verifying;
+
+/* File descriptor for the file we are diffing. */
+static int diff_handle;
+
+/* Area for reading file contents into. */
+static char *diff_buffer;
+
+/* Initialize for a diff operation. */
+void
+diff_init (void)
+{
+ diff_buffer = valloc (record_size);
+ if (!diff_buffer)
+ xalloc_die ();
+}
+
+/* Sigh about something that differs by writing a MESSAGE to stdlis,
+ given MESSAGE is nonzero. Also set the exit status if not already. */
+static void
+report_difference (const char *message)
+{
+ if (message)
+ fprintf (stdlis, "%s: %s\n", quotearg_colon (current_file_name), message);
+
+ if (exit_status == TAREXIT_SUCCESS)
+ exit_status = TAREXIT_DIFFERS;
+}
+
+/* Take a buffer returned by read_and_process and do nothing with it. */
+static int
+process_noop (size_t size, char *data)
+{
+ /* Yes, I know. SIZE and DATA are unused in this function. Some
+ compilers may even report it. That's OK, just relax! */
+ return 1;
+}
+
+static int
+process_rawdata (size_t bytes, char *buffer)
+{
+ ssize_t status = safe_read (diff_handle, diff_buffer, bytes);
+ char message[MESSAGE_BUFFER_SIZE];
+
+ if (status != bytes)
+ {
+ if (status < 0)
+ {
+ read_error (current_file_name);
+ report_difference (0);
+ }
+ else
+ {
+ sprintf (message, _("Could only read %lu of %lu bytes"),
+ (unsigned long) status, (unsigned long) bytes);
+ report_difference (message);
+ }
+ return 0;
+ }
+
+ if (memcmp (buffer, diff_buffer, bytes))
+ {
+ report_difference (_("Contents differ"));
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Directory contents, only for GNUTYPE_DUMPDIR. */
+
+static char *dumpdir_cursor;
+
+static int
+process_dumpdir (size_t bytes, char *buffer)
+{
+ if (memcmp (buffer, dumpdir_cursor, bytes))
+ {
+ report_difference (_("Contents differ"));
+ return 0;
+ }
+
+ dumpdir_cursor += bytes;
+ return 1;
+}
+
+/* Some other routine wants SIZE bytes in the archive. For each chunk
+ of the archive, call PROCESSOR with the size of the chunk, and the
+ address of the chunk it can work with. The PROCESSOR should return
+ nonzero for success. It it return error once, continue skipping
+ without calling PROCESSOR anymore. */
+static void
+read_and_process (off_t size, int (*processor) (size_t, char *))
+{
+ union block *data_block;
+ size_t data_size;
+
+ if (multi_volume_option)
+ save_sizeleft = size;
+ while (size)
+ {
+ data_block = find_next_block ();
+ if (! data_block)
+ {
+ ERROR ((0, 0, _("Unexpected EOF in archive")));
+ return;
+ }
+
+ data_size = available_space_after (data_block);
+ if (data_size > size)
+ data_size = size;
+ if (!(*processor) (data_size, data_block->buffer))
+ processor = process_noop;
+ set_next_block_after ((union block *)
+ (data_block->buffer + data_size - 1));
+ size -= data_size;
+ if (multi_volume_option)
+ save_sizeleft -= data_size;
+ }
+}
+
+/* JK This routine should be used more often than it is ... look into
+ that. Anyhow, what it does is translate the sparse information on the
+ header, and in any subsequent extended headers, into an array of
+ structures with true numbers, as opposed to character strings. It
+ simply makes our life much easier, doing so many comparisons and such.
+ */
+static void
+fill_in_sparse_array (void)
+{
+ int counter;
+
+ /* Allocate space for our scratch space; it's initially 10 elements
+ long, but can change in this routine if necessary. */
+
+ sp_array_size = 10;
+ sparsearray = xmalloc (sp_array_size * sizeof (struct sp_array));
+
+ /* There are at most five of these structures in the header itself;
+ read these in first. */
+
+ for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++)
+ {
+ /* Compare to 0, or use !(int)..., for Pyramid's dumb compiler. */
+ if (current_header->oldgnu_header.sp[counter].numbytes == 0)
+ break;
+
+ sparsearray[counter].offset =
+ OFF_FROM_HEADER (current_header->oldgnu_header.sp[counter].offset);
+ sparsearray[counter].numbytes =
+ SIZE_FROM_HEADER (current_header->oldgnu_header.sp[counter].numbytes);
+ }
+
+ /* If the header's extended, we gotta read in exhdr's till we're done. */
+
+ if (current_header->oldgnu_header.isextended)
+ {
+ /* How far into the sparsearray we are `so far'. */
+ static int so_far_ind = SPARSES_IN_OLDGNU_HEADER;
+ union block *exhdr;
+
+ while (1)
+ {
+ exhdr = find_next_block ();
+ if (!exhdr)
+ FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
+
+ for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++)
+ {
+ if (counter + so_far_ind > sp_array_size - 1)
+ {
+ /* We just ran out of room in our scratch area -
+ realloc it. */
+
+ sp_array_size *= 2;
+ sparsearray =
+ xrealloc (sparsearray,
+ sp_array_size * sizeof (struct sp_array));
+ }
+
+ /* Convert the character strings into offsets and sizes. */
+
+ sparsearray[counter + so_far_ind].offset =
+ OFF_FROM_HEADER (exhdr->sparse_header.sp[counter].offset);
+ sparsearray[counter + so_far_ind].numbytes =
+ SIZE_FROM_HEADER (exhdr->sparse_header.sp[counter].numbytes);
+ }
+
+ /* If this is the last extended header for this file, we can
+ stop. */
+
+ if (!exhdr->sparse_header.isextended)
+ break;
+
+ so_far_ind += SPARSES_IN_SPARSE_HEADER;
+ set_next_block_after (exhdr);
+ }
+
+ /* Be sure to skip past the last one. */
+
+ set_next_block_after (exhdr);
+ }
+}
+
+/* JK Diff'ing a sparse file with its counterpart on the tar file is a
+ bit of a different story than a normal file. First, we must know what
+ areas of the file to skip through, i.e., we need to construct a
+ sparsearray, which will hold all the information we need. We must
+ compare small amounts of data at a time as we find it. */
+
+/* FIXME: This does not look very solid to me, at first glance. Zero areas
+ are not checked, spurious sparse entries seemingly goes undetected, and
+ I'm not sure overall identical sparsity is verified. */
+
+static void
+diff_sparse_files (off_t size_of_file)
+{
+ off_t remaining_size = size_of_file;
+ char *buffer = xmalloc (BLOCKSIZE * sizeof (char));
+ size_t buffer_size = BLOCKSIZE;
+ union block *data_block = 0;
+ int counter = 0;
+ int different = 0;
+
+ fill_in_sparse_array ();
+
+ while (remaining_size > 0)
+ {
+ ssize_t status;
+ size_t chunk_size;
+ off_t offset;
+
+#if 0
+ off_t amount_read = 0;
+#endif
+
+ data_block = find_next_block ();
+ if (!data_block)
+ FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
+ chunk_size = sparsearray[counter].numbytes;
+ if (!chunk_size)
+ break;
+
+ offset = sparsearray[counter].offset;
+ if (lseek (diff_handle, offset, SEEK_SET) < 0)
+ {
+ seek_error_details (current_file_name, offset);
+ report_difference (0);
+ }
+
+ /* Take care to not run out of room in our buffer. */
+
+ while (buffer_size < chunk_size)
+ {
+ if (buffer_size * 2 < buffer_size)
+ xalloc_die ();
+ buffer_size *= 2;
+ buffer = xrealloc (buffer, buffer_size * sizeof (char));
+ }
+
+ while (chunk_size > BLOCKSIZE)
+ {
+ if (status = safe_read (diff_handle, buffer, BLOCKSIZE),
+ status != BLOCKSIZE)
+ {
+ if (status < 0)
+ {
+ read_error (current_file_name);
+ report_difference (0);
+ }
+ else
+ {
+ char message[MESSAGE_BUFFER_SIZE];
+
+ sprintf (message, _("Could only read %lu of %lu bytes"),
+ (unsigned long) status, (unsigned long) chunk_size);
+ report_difference (message);
+ }
+ break;
+ }
+
+ if (memcmp (buffer, data_block->buffer, BLOCKSIZE))
+ {
+ different = 1;
+ break;
+ }
+
+ chunk_size -= status;
+ remaining_size -= status;
+ set_next_block_after (data_block);
+ data_block = find_next_block ();
+ if (!data_block)
+ FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
+ }
+ if (status = safe_read (diff_handle, buffer, chunk_size),
+ status != chunk_size)
+ {
+ if (status < 0)
+ {
+ read_error (current_file_name);
+ report_difference (0);
+ }
+ else
+ {
+ char message[MESSAGE_BUFFER_SIZE];
+
+ sprintf (message, _("Could only read %lu of %lu bytes"),
+ (unsigned long) status, (unsigned long) chunk_size);
+ report_difference (message);
+ }
+ break;
+ }
+
+ if (memcmp (buffer, data_block->buffer, chunk_size))
+ {
+ different = 1;
+ break;
+ }
+#if 0
+ amount_read += chunk_size;
+ if (amount_read >= BLOCKSIZE)
+ {
+ amount_read = 0;
+ set_next_block_after (data_block);
+ data_block = find_next_block ();
+ if (!data_block)
+ FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
+ }
+#endif
+ set_next_block_after (data_block);
+ counter++;
+ remaining_size -= chunk_size;
+ }
+
+#if 0
+ /* If the number of bytes read isn't the number of bytes supposedly in
+ the file, they're different. */
+
+ if (amount_read != size_of_file)
+ different = 1;
+#endif
+
+ set_next_block_after (data_block);
+ free (sparsearray);
+
+ if (different)
+ report_difference (_("Contents differ"));
+}
+
+/* Call either stat or lstat over STAT_DATA, depending on
+ --dereference (-h), for a file which should exist. Diagnose any
+ problem. Return nonzero for success, zero otherwise. */
+static int
+get_stat_data (char const *file_name, struct stat *stat_data)
+{
+ int status = deref_stat (dereference_option, file_name, stat_data);
+
+ if (status != 0)
+ {
+ if (errno == ENOENT)
+ stat_warn (file_name);
+ else
+ stat_error (file_name);
+ report_difference (0);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Diff a file against the archive. */
+void
+diff_archive (void)
+{
+ struct stat stat_data;
+ size_t name_length;
+ int status;
+ struct utimbuf restore_times;
+
+ set_next_block_after (current_header);
+ decode_header (current_header, &current_stat, &current_format, 1);
+
+ /* Print the block from current_header and current_stat. */
+
+ if (verbose_option)
+ {
+ if (now_verifying)
+ fprintf (stdlis, _("Verify "));
+ print_header ();
+ }
+
+ switch (current_header->header.typeflag)
+ {
+ default:
+ ERROR ((0, 0, _("%s: Unknown file type '%c', diffed as normal file"),
+ quotearg_colon (current_file_name),
+ current_header->header.typeflag));
+ /* Fall through. */
+
+ case AREGTYPE:
+ case REGTYPE:
+ case GNUTYPE_SPARSE:
+ case CONTTYPE:
+
+ /* Appears to be a file. See if it's really a directory. */
+
+ name_length = strlen (current_file_name) - 1;
+ if (ISSLASH (current_file_name[name_length]))
+ goto really_dir;
+
+ if (!get_stat_data (current_file_name, &stat_data))
+ {
+ skip_member ();
+ goto quit;
+ }
+
+ if (!S_ISREG (stat_data.st_mode))
+ {
+ report_difference (_("File type differs"));
+ skip_member ();
+ goto quit;
+ }
+
+ if ((current_stat.st_mode & MODE_ALL) != (stat_data.st_mode & MODE_ALL))
+ report_difference (_("Mode differs"));
+
+#if !MSDOS
+ /* stat() in djgpp's C library gives a constant number of 42 as the
+ uid and gid of a file. So, comparing an FTP'ed archive just after
+ unpack would fail on MSDOS. */
+ if (stat_data.st_uid != current_stat.st_uid)
+ report_difference (_("Uid differs"));
+ if (stat_data.st_gid != current_stat.st_gid)
+ report_difference (_("Gid differs"));
+#endif
+
+ if (stat_data.st_mtime != current_stat.st_mtime)
+ report_difference (_("Mod time differs"));
+ if (current_header->header.typeflag != GNUTYPE_SPARSE &&
+ stat_data.st_size != current_stat.st_size)
+ {
+ report_difference (_("Size differs"));
+ skip_member ();
+ goto quit;
+ }
+
+ diff_handle = open (current_file_name, O_RDONLY | O_BINARY);
+
+ if (diff_handle < 0)
+ {
+ open_error (current_file_name);
+ skip_member ();
+ report_difference (0);
+ goto quit;
+ }
+
+ restore_times.actime = stat_data.st_atime;
+ restore_times.modtime = stat_data.st_mtime;
+
+ /* Need to treat sparse files completely differently here. */
+
+ if (current_header->header.typeflag == GNUTYPE_SPARSE)
+ diff_sparse_files (current_stat.st_size);
+ else
+ {
+ if (multi_volume_option)
+ {
+ assign_string (&save_name, current_file_name);
+ save_totsize = current_stat.st_size;
+ /* save_sizeleft is set in read_and_process. */
+ }
+
+ read_and_process (current_stat.st_size, process_rawdata);
+
+ if (multi_volume_option)
+ assign_string (&save_name, 0);
+ }
+
+ status = close (diff_handle);
+ if (status != 0)
+ close_error (current_file_name);
+
+ if (atime_preserve_option)
+ utime (current_file_name, &restore_times);
+
+ quit:
+ break;
+
+#if !MSDOS
+ case LNKTYPE:
+ {
+ struct stat link_data;
+
+ if (!get_stat_data (current_file_name, &stat_data))
+ break;
+ if (!get_stat_data (current_link_name, &link_data))
+ break;
+
+ if (stat_data.st_dev != link_data.st_dev
+ || stat_data.st_ino != link_data.st_ino)
+ {
+ char *message =
+ xmalloc (MESSAGE_BUFFER_SIZE + 4 * strlen (current_link_name));
+
+ sprintf (message, _("Not linked to %s"),
+ quote (current_link_name));
+ report_difference (message);
+ free (message);
+ break;
+ }
+
+ break;
+ }
+#endif /* not MSDOS */
+
+#ifdef HAVE_READLINK
+ case SYMTYPE:
+ {
+ size_t len = strlen (current_link_name);
+ char *linkbuf = alloca (len + 1);
+
+ status = readlink (current_file_name, linkbuf, len + 1);
+
+ if (status < 0)
+ {
+ if (errno == ENOENT)
+ readlink_warn (current_file_name);
+ else
+ readlink_error (current_file_name);
+ report_difference (0);
+ }
+ else if (status != len
+ || strncmp (current_link_name, linkbuf, len) != 0)
+ report_difference (_("Symlink differs"));
+
+ break;
+ }
+#endif
+
+ case CHRTYPE:
+ case BLKTYPE:
+ case FIFOTYPE:
+
+ /* FIXME: deal with umask. */
+
+ if (!get_stat_data (current_file_name, &stat_data))
+ break;
+
+ if (current_header->header.typeflag == CHRTYPE
+ ? !S_ISCHR (stat_data.st_mode)
+ : current_header->header.typeflag == BLKTYPE
+ ? !S_ISBLK (stat_data.st_mode)
+ : /* current_header->header.typeflag == FIFOTYPE */
+ !S_ISFIFO (stat_data.st_mode))
+ {
+ report_difference (_("File type differs"));
+ break;
+ }
+
+ if ((current_header->header.typeflag == CHRTYPE
+ || current_header->header.typeflag == BLKTYPE)
+ && current_stat.st_rdev != stat_data.st_rdev)
+ {
+ report_difference (_("Device number differs"));
+ break;
+ }
+
+ if ((current_stat.st_mode & MODE_ALL) != (stat_data.st_mode & MODE_ALL))
+ {
+ report_difference (_("Mode differs"));
+ break;
+ }
+
+ break;
+
+ case GNUTYPE_DUMPDIR:
+ {
+ char *dumpdir_buffer = get_directory_contents (current_file_name, 0);
+
+ if (multi_volume_option)
+ {
+ assign_string (&save_name, current_file_name);
+ save_totsize = current_stat.st_size;
+ /* save_sizeleft is set in read_and_process. */
+ }
+
+ if (dumpdir_buffer)
+ {
+ dumpdir_cursor = dumpdir_buffer;
+ read_and_process (current_stat.st_size, process_dumpdir);
+ free (dumpdir_buffer);
+ }
+ else
+ read_and_process (current_stat.st_size, process_noop);
+
+ if (multi_volume_option)
+ assign_string (&save_name, 0);
+ /* Fall through. */
+ }
+
+ case DIRTYPE:
+ /* Check for trailing /. */
+
+ name_length = strlen (current_file_name) - 1;
+
+ really_dir:
+ while (name_length && ISSLASH (current_file_name[name_length]))
+ current_file_name[name_length--] = '\0'; /* zap / */
+
+ if (!get_stat_data (current_file_name, &stat_data))
+ break;
+
+ if (!S_ISDIR (stat_data.st_mode))
+ {
+ report_difference (_("File type differs"));
+ break;
+ }
+
+ if ((current_stat.st_mode & MODE_ALL) != (stat_data.st_mode & MODE_ALL))
+ {
+ report_difference (_("Mode differs"));
+ break;
+ }
+
+ break;
+
+ case GNUTYPE_VOLHDR:
+ break;
+
+ case GNUTYPE_MULTIVOL:
+ {
+ off_t offset;
+
+ name_length = strlen (current_file_name) - 1;
+ if (ISSLASH (current_file_name[name_length]))
+ goto really_dir;
+
+ if (!get_stat_data (current_file_name, &stat_data))
+ break;
+
+ if (!S_ISREG (stat_data.st_mode))
+ {
+ report_difference (_("File type differs"));
+ skip_member ();
+ break;
+ }
+
+ offset = OFF_FROM_HEADER (current_header->oldgnu_header.offset);
+ if (stat_data.st_size != current_stat.st_size + offset)
+ {
+ report_difference (_("Size differs"));
+ skip_member ();
+ break;
+ }
+
+ diff_handle = open (current_file_name, O_RDONLY | O_BINARY);
+
+ if (diff_handle < 0)
+ {
+ open_error (current_file_name);
+ report_difference (0);
+ skip_member ();
+ break;
+ }
+
+ if (lseek (diff_handle, offset, SEEK_SET) < 0)
+ {
+ seek_error_details (current_file_name, offset);
+ report_difference (0);
+ break;
+ }
+
+ if (multi_volume_option)
+ {
+ assign_string (&save_name, current_file_name);
+ save_totsize = stat_data.st_size;
+ /* save_sizeleft is set in read_and_process. */
+ }
+
+ read_and_process (current_stat.st_size, process_rawdata);
+
+ if (multi_volume_option)
+ assign_string (&save_name, 0);
+
+ status = close (diff_handle);
+ if (status != 0)
+ close_error (current_file_name);
+
+ break;
+ }
+ }
+}
+
+void
+verify_volume (void)
+{
+ if (!diff_buffer)
+ diff_init ();
+
+ /* Verifying an archive is meant to check if the physical media got it
+ correctly, so try to defeat clever in-memory buffering pertaining to
+ this particular media. On Linux, for example, the floppy drive would
+ not even be accessed for the whole verification.
+
+ The code was using fsync only when the ioctl is unavailable, but
+ Marty Leisner says that the ioctl does not work when not preceded by
+ fsync. So, until we know better, or maybe to please Marty, let's do it
+ the unbelievable way :-). */
+
+#if HAVE_FSYNC
+ fsync (archive);
+#endif
+#ifdef FDFLUSH
+ ioctl (archive, FDFLUSH);
+#endif
+
+#ifdef MTIOCTOP
+ {
+ struct mtop operation;
+ int status;
+
+ operation.mt_op = MTBSF;
+ operation.mt_count = 1;
+ if (status = rmtioctl (archive, MTIOCTOP, (char *) &operation), status < 0)
+ {
+ if (errno != EIO
+ || (status = rmtioctl (archive, MTIOCTOP, (char *) &operation),
+ status < 0))
+ {
+#endif
+ if (rmtlseek (archive, (off_t) 0, SEEK_SET) != 0)
+ {
+ /* Lseek failed. Try a different method. */
+ seek_warn (archive_name_array[0]);
+ return;
+ }
+#ifdef MTIOCTOP
+ }
+ }
+ }
+#endif
+
+ access_mode = ACCESS_READ;
+ now_verifying = 1;
+
+ flush_read ();
+ while (1)
+ {
+ enum read_header status = read_header (0);
+
+ if (status == HEADER_FAILURE)
+ {
+ int counter = 0;
+
+ while (status == HEADER_FAILURE);
+ {
+ counter++;
+ status = read_header (0);
+ }
+ ERROR ((0, 0,
+ _("VERIFY FAILURE: %d invalid header(s) detected"), counter));
+ }
+ if (status == HEADER_ZERO_BLOCK || status == HEADER_END_OF_FILE)
+ break;
+
+ diff_archive ();
+ }
+
+ access_mode = ACCESS_WRITE;
+ now_verifying = 0;
+}
diff --git a/contrib/tar/src/create.c b/contrib/tar/src/create.c
new file mode 100644
index 0000000..b3de6a8
--- /dev/null
+++ b/contrib/tar/src/create.c
@@ -0,0 +1,1550 @@
+/* Create a tar archive.
+ Copyright 1985,92,93,94,96,97,99,2000, 2001 Free Software Foundation, Inc.
+ Written by John Gilmore, on 1985-08-25.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+
+#if !MSDOS
+# include <pwd.h>
+# include <grp.h>
+#endif
+
+#if HAVE_UTIME_H
+# include <utime.h>
+#else
+struct utimbuf
+ {
+ long actime;
+ long modtime;
+ };
+#endif
+
+#include <quotearg.h>
+
+#include "common.h"
+#include <hash.h>
+
+#ifndef MSDOS
+extern dev_t ar_dev;
+extern ino_t ar_ino;
+#endif
+
+struct link
+ {
+ dev_t dev;
+ ino_t ino;
+ char name[1];
+ };
+
+/* The maximum uintmax_t value that can be represented with DIGITS digits,
+ assuming that each digit is BITS_PER_DIGIT wide. */
+#define MAX_VAL_WITH_DIGITS(digits, bits_per_digit) \
+ ((digits) * (bits_per_digit) < sizeof (uintmax_t) * CHAR_BIT \
+ ? ((uintmax_t) 1 << ((digits) * (bits_per_digit))) - 1 \
+ : (uintmax_t) -1)
+
+/* Convert VALUE to an octal representation suitable for tar headers.
+ Output to buffer WHERE with size SIZE.
+ The result is undefined if SIZE is 0 or if VALUE is too large to fit. */
+
+static void
+to_octal (uintmax_t value, char *where, size_t size)
+{
+ uintmax_t v = value;
+ size_t i = size;
+
+ do
+ {
+ where[--i] = '0' + (v & ((1 << LG_8) - 1));
+ v >>= LG_8;
+ }
+ while (i);
+}
+
+/* Convert NEGATIVE VALUE to a base-256 representation suitable for
+ tar headers. NEGATIVE is 1 if VALUE was negative before being cast
+ to uintmax_t, 0 otherwise. Output to buffer WHERE with size SIZE.
+ The result is undefined if SIZE is 0 or if VALUE is too large to
+ fit. */
+
+static void
+to_base256 (int negative, uintmax_t value, char *where, size_t size)
+{
+ uintmax_t v = value;
+ uintmax_t propagated_sign_bits =
+ ((uintmax_t) - negative << (CHAR_BIT * sizeof v - LG_256));
+ size_t i = size;
+
+ do
+ {
+ where[--i] = v & ((1 << LG_256) - 1);
+ v = propagated_sign_bits | (v >> LG_256);
+ }
+ while (i);
+}
+
+/* Convert NEGATIVE VALUE (which was originally of size VALSIZE) to
+ external form, using SUBSTITUTE (...) if VALUE won't fit. Output
+ to buffer WHERE with size SIZE. NEGATIVE is 1 iff VALUE was
+ negative before being cast to uintmax_t; its original bitpattern
+ can be deduced from VALSIZE, its original size before casting.
+ TYPE is the kind of value being output (useful for diagnostics).
+ Prefer the POSIX format of SIZE - 1 octal digits (with leading zero
+ digits), followed by '\0'. If this won't work, and if GNU or
+ OLDGNU format is allowed, use '\200' followed by base-256, or (if
+ NEGATIVE is nonzero) '\377' followed by two's complement base-256.
+ If neither format works, use SUBSTITUTE (...) instead. Pass to
+ SUBSTITUTE the address of an 0-or-1 flag recording whether the
+ substitute value is negative. */
+
+static void
+to_chars (int negative, uintmax_t value, size_t valsize,
+ uintmax_t (*substitute) PARAMS ((int *)),
+ char *where, size_t size, const char *type)
+{
+ int base256_allowed = (archive_format == GNU_FORMAT
+ || archive_format == OLDGNU_FORMAT);
+
+ /* Generate the POSIX octal representation if the number fits. */
+ if (! negative && value <= MAX_VAL_WITH_DIGITS (size - 1, LG_8))
+ {
+ where[size - 1] = '\0';
+ to_octal (value, where, size - 1);
+ }
+
+ /* Otherwise, generate the base-256 representation if we are
+ generating an old or new GNU format and if the number fits. */
+ else if (((negative ? -1 - value : value)
+ <= MAX_VAL_WITH_DIGITS (size - 1, LG_256))
+ && base256_allowed)
+ {
+ where[0] = negative ? -1 : 1 << (LG_256 - 1);
+ to_base256 (negative, value, where + 1, size - 1);
+ }
+
+ /* Otherwise, if the number is negative, and if it would not cause
+ ambiguity on this host by confusing positive with negative
+ values, then generate the POSIX octal representation of the value
+ modulo 2**(field bits). The resulting tar file is
+ machine-dependent, since it depends on the host word size. Yuck!
+ But this is the traditional behavior. */
+ else if (negative && valsize * CHAR_BIT <= (size - 1) * LG_8)
+ {
+ static int warned_once;
+ if (! warned_once)
+ {
+ warned_once = 1;
+ WARN ((0, 0, _("Generating negative octal headers")));
+ }
+ where[size - 1] = '\0';
+ to_octal (value & MAX_VAL_WITH_DIGITS (valsize * CHAR_BIT, 1),
+ where, size - 1);
+ }
+
+ /* Otherwise, output a substitute value if possible (with a
+ warning), and an error message if not. */
+ else
+ {
+ uintmax_t maxval = (base256_allowed
+ ? MAX_VAL_WITH_DIGITS (size - 1, LG_256)
+ : MAX_VAL_WITH_DIGITS (size - 1, LG_8));
+ char valbuf[UINTMAX_STRSIZE_BOUND + 1];
+ char maxbuf[UINTMAX_STRSIZE_BOUND];
+ char minbuf[UINTMAX_STRSIZE_BOUND + 1];
+ char const *minval_string;
+ char const *maxval_string = STRINGIFY_BIGINT (maxval, maxbuf);
+ char const *value_string;
+
+ if (base256_allowed)
+ {
+ uintmax_t m = maxval + 1 ? maxval + 1 : maxval / 2 + 1;
+ char *p = STRINGIFY_BIGINT (m, minbuf + 1);
+ *--p = '-';
+ minval_string = p;
+ }
+ else
+ minval_string = "0";
+
+ if (negative)
+ {
+ char *p = STRINGIFY_BIGINT (- value, valbuf + 1);
+ *--p = '-';
+ value_string = p;
+ }
+ else
+ value_string = STRINGIFY_BIGINT (value, valbuf);
+
+ if (substitute)
+ {
+ int negsub;
+ uintmax_t sub = substitute (&negsub) & maxval;
+ uintmax_t s = (negsub &= archive_format == GNU_FORMAT) ? - sub : sub;
+ char subbuf[UINTMAX_STRSIZE_BOUND + 1];
+ char *sub_string = STRINGIFY_BIGINT (s, subbuf + 1);
+ if (negsub)
+ *--sub_string = '-';
+ WARN ((0, 0, _("value %s out of %s range %s..%s; substituting %s"),
+ value_string, type, minval_string, maxval_string,
+ sub_string));
+ to_chars (negsub, s, valsize, 0, where, size, type);
+ }
+ else
+ ERROR ((0, 0, _("value %s out of %s range %s..%s"),
+ value_string, type, minval_string, maxval_string));
+ }
+}
+
+static uintmax_t
+gid_substitute (int *negative)
+{
+ gid_t r;
+#ifdef GID_NOBODY
+ r = GID_NOBODY;
+#else
+ static gid_t gid_nobody;
+ if (!gid_nobody && !gname_to_gid ("nobody", &gid_nobody))
+ gid_nobody = -2;
+ r = gid_nobody;
+#endif
+ *negative = r < 0;
+ return r;
+}
+
+void
+gid_to_chars (gid_t v, char *p, size_t s)
+{
+ to_chars (v < 0, (uintmax_t) v, sizeof v, gid_substitute, p, s, "gid_t");
+}
+
+void
+major_to_chars (major_t v, char *p, size_t s)
+{
+ to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "major_t");
+}
+
+void
+minor_to_chars (minor_t v, char *p, size_t s)
+{
+ to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "minor_t");
+}
+
+void
+mode_to_chars (mode_t v, char *p, size_t s)
+{
+ /* In the common case where the internal and external mode bits are the same,
+ and we are not using POSIX or GNU format,
+ propagate all unknown bits to the external mode.
+ This matches historical practice.
+ Otherwise, just copy the bits we know about. */
+ int negative;
+ uintmax_t u;
+ if (S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX
+ && S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC
+ && S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC
+ && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
+ && archive_format != POSIX_FORMAT
+ && archive_format != GNU_FORMAT)
+ {
+ negative = v < 0;
+ u = v;
+ }
+ else
+ {
+ negative = 0;
+ u = ((v & S_ISUID ? TSUID : 0)
+ | (v & S_ISGID ? TSGID : 0)
+ | (v & S_ISVTX ? TSVTX : 0)
+ | (v & S_IRUSR ? TUREAD : 0)
+ | (v & S_IWUSR ? TUWRITE : 0)
+ | (v & S_IXUSR ? TUEXEC : 0)
+ | (v & S_IRGRP ? TGREAD : 0)
+ | (v & S_IWGRP ? TGWRITE : 0)
+ | (v & S_IXGRP ? TGEXEC : 0)
+ | (v & S_IROTH ? TOREAD : 0)
+ | (v & S_IWOTH ? TOWRITE : 0)
+ | (v & S_IXOTH ? TOEXEC : 0));
+ }
+ to_chars (negative, u, sizeof v, 0, p, s, "mode_t");
+}
+
+void
+off_to_chars (off_t v, char *p, size_t s)
+{
+ to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "off_t");
+}
+
+void
+size_to_chars (size_t v, char *p, size_t s)
+{
+ to_chars (0, (uintmax_t) v, sizeof v, 0, p, s, "size_t");
+}
+
+void
+time_to_chars (time_t v, char *p, size_t s)
+{
+ to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "time_t");
+}
+
+static uintmax_t
+uid_substitute (int *negative)
+{
+ uid_t r;
+#ifdef UID_NOBODY
+ r = UID_NOBODY;
+#else
+ static uid_t uid_nobody;
+ if (!uid_nobody && !uname_to_uid ("nobody", &uid_nobody))
+ uid_nobody = -2;
+ r = uid_nobody;
+#endif
+ *negative = r < 0;
+ return r;
+}
+
+void
+uid_to_chars (uid_t v, char *p, size_t s)
+{
+ to_chars (v < 0, (uintmax_t) v, sizeof v, uid_substitute, p, s, "uid_t");
+}
+
+void
+uintmax_to_chars (uintmax_t v, char *p, size_t s)
+{
+ to_chars (0, v, sizeof v, 0, p, s, "uintmax_t");
+}
+
+/* Writing routines. */
+
+/* Zero out the buffer so we don't confuse ourselves with leftover
+ data. */
+static void
+clear_buffer (char *buffer)
+{
+ memset (buffer, 0, BLOCKSIZE);
+}
+
+/* Write the EOT block(s). Zero at least two blocks, through the end
+ of the record. Old tar, as previous versions of GNU tar, writes
+ garbage after two zeroed blocks. */
+void
+write_eot (void)
+{
+ union block *pointer = find_next_block ();
+ memset (pointer->buffer, 0, BLOCKSIZE);
+ set_next_block_after (pointer);
+ pointer = find_next_block ();
+ memset (pointer->buffer, 0, available_space_after (pointer));
+ set_next_block_after (pointer);
+}
+
+/* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block. */
+
+/* FIXME: Cross recursion between start_header and write_long! */
+
+static union block *start_header PARAMS ((const char *, struct stat *));
+
+static void
+write_long (const char *p, char type)
+{
+ size_t size = strlen (p) + 1;
+ size_t bufsize;
+ union block *header;
+ struct stat foo;
+
+ memset (&foo, 0, sizeof foo);
+ foo.st_size = size;
+
+ header = start_header ("././@LongLink", &foo);
+ header->header.typeflag = type;
+ finish_header (header);
+
+ header = find_next_block ();
+
+ bufsize = available_space_after (header);
+
+ while (bufsize < size)
+ {
+ memcpy (header->buffer, p, bufsize);
+ p += bufsize;
+ size -= bufsize;
+ set_next_block_after (header + (bufsize - 1) / BLOCKSIZE);
+ header = find_next_block ();
+ bufsize = available_space_after (header);
+ }
+ memcpy (header->buffer, p, size);
+ memset (header->buffer + size, 0, bufsize - size);
+ set_next_block_after (header + (size - 1) / BLOCKSIZE);
+}
+
+/* Return a suffix of the file NAME that is a relative file name.
+ Warn about `..' in file names. But return NAME if the user wants
+ absolute file names. */
+static char const *
+relativize (char const *name)
+{
+ if (! absolute_names_option)
+ {
+ {
+ static int warned_once;
+ if (! warned_once && contains_dot_dot (name))
+ {
+ warned_once = 1;
+ WARN ((0, 0, _("Member names contain `..'")));
+ }
+ }
+
+ {
+ size_t prefix_len = FILESYSTEM_PREFIX_LEN (name);
+
+ while (ISSLASH (name[prefix_len]))
+ prefix_len++;
+
+ if (prefix_len)
+ {
+ static int warned_once;
+ if (!warned_once)
+ {
+ warned_once = 1;
+ WARN ((0, 0, _("Removing leading `%.*s' from member names"),
+ (int) prefix_len, name));
+ }
+ name += prefix_len;
+ }
+ }
+ }
+
+ return name;
+}
+
+/* Header handling. */
+
+/* Make a header block for the file whose stat info is st,
+ and return its address. */
+
+static union block *
+start_header (const char *name, struct stat *st)
+{
+ union block *header;
+
+ name = relativize (name);
+
+ if (sizeof header->header.name <= strlen (name))
+ write_long (name, GNUTYPE_LONGNAME);
+ header = find_next_block ();
+ memset (header->buffer, 0, sizeof (union block));
+
+ assign_string (&current_file_name, name);
+
+ strncpy (header->header.name, name, NAME_FIELD_SIZE);
+ header->header.name[NAME_FIELD_SIZE - 1] = '\0';
+
+ /* Override some stat fields, if requested to do so. */
+
+ if (owner_option != (uid_t) -1)
+ st->st_uid = owner_option;
+ if (group_option != (gid_t) -1)
+ st->st_gid = group_option;
+ if (mode_option)
+ st->st_mode = ((st->st_mode & ~MODE_ALL)
+ | mode_adjust (st->st_mode, mode_option));
+
+ /* Paul Eggert tried the trivial test ($WRITER cf a b; $READER tvf a)
+ for a few tars and came up with the following interoperability
+ matrix:
+
+ WRITER
+ 1 2 3 4 5 6 7 8 9 READER
+ . . . . . . . . . 1 = SunOS 4.2 tar
+ # . . # # . . # # 2 = NEC SVR4.0.2 tar
+ . . . # # . . # . 3 = Solaris 2.1 tar
+ . . . . . . . . . 4 = GNU tar 1.11.1
+ . . . . . . . . . 5 = HP-UX 8.07 tar
+ . . . . . . . . . 6 = Ultrix 4.1
+ . . . . . . . . . 7 = AIX 3.2
+ . . . . . . . . . 8 = Hitachi HI-UX 1.03
+ . . . . . . . . . 9 = Omron UNIOS-B 4.3BSD 1.60Beta
+
+ . = works
+ # = ``impossible file type''
+
+ The following mask for old archive removes the `#'s in column 4
+ above, thus making GNU tar both a universal donor and a universal
+ acceptor for Paul's test. */
+
+ if (archive_format == V7_FORMAT)
+ MODE_TO_CHARS (st->st_mode & MODE_ALL, header->header.mode);
+ else
+ MODE_TO_CHARS (st->st_mode, header->header.mode);
+
+ UID_TO_CHARS (st->st_uid, header->header.uid);
+ GID_TO_CHARS (st->st_gid, header->header.gid);
+ OFF_TO_CHARS (st->st_size, header->header.size);
+ TIME_TO_CHARS (st->st_mtime, header->header.mtime);
+
+ if (incremental_option)
+ if (archive_format == OLDGNU_FORMAT)
+ {
+ TIME_TO_CHARS (st->st_atime, header->oldgnu_header.atime);
+ TIME_TO_CHARS (st->st_ctime, header->oldgnu_header.ctime);
+ }
+
+ header->header.typeflag = archive_format == V7_FORMAT ? AREGTYPE : REGTYPE;
+
+ switch (archive_format)
+ {
+ case V7_FORMAT:
+ break;
+
+ case OLDGNU_FORMAT:
+ /* Overwrite header->header.magic and header.version in one blow. */
+ strcpy (header->header.magic, OLDGNU_MAGIC);
+ break;
+
+ case POSIX_FORMAT:
+ case GNU_FORMAT:
+ strncpy (header->header.magic, TMAGIC, TMAGLEN);
+ strncpy (header->header.version, TVERSION, TVERSLEN);
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (archive_format == V7_FORMAT || numeric_owner_option)
+ {
+ /* header->header.[ug]name are left as the empty string. */
+ }
+ else
+ {
+ uid_to_uname (st->st_uid, header->header.uname);
+ gid_to_gname (st->st_gid, header->header.gname);
+ }
+
+ return header;
+}
+
+/* Finish off a filled-in header block and write it out. We also
+ print the file name and/or full info if verbose is on. */
+void
+finish_header (union block *header)
+{
+ size_t i;
+ int sum;
+ char *p;
+
+ memcpy (header->header.chksum, CHKBLANKS, sizeof header->header.chksum);
+
+ sum = 0;
+ p = header->buffer;
+ for (i = sizeof *header; i-- != 0; )
+ /* We can't use unsigned char here because of old compilers, e.g. V7. */
+ sum += 0xFF & *p++;
+
+ /* Fill in the checksum field. It's formatted differently from the
+ other fields: it has [6] digits, a null, then a space -- rather than
+ digits, then a null. We use to_chars.
+ The final space is already there, from
+ checksumming, and to_chars doesn't modify it.
+
+ This is a fast way to do:
+
+ sprintf(header->header.chksum, "%6o", sum); */
+
+ uintmax_to_chars ((uintmax_t) sum, header->header.chksum, 7);
+
+ if (verbose_option
+ && header->header.typeflag != GNUTYPE_LONGLINK
+ && header->header.typeflag != GNUTYPE_LONGNAME)
+ {
+ /* These globals are parameters to print_header, sigh. */
+
+ current_header = header;
+ /* current_stat is already set up. */
+ current_format = archive_format;
+ print_header ();
+ }
+
+ set_next_block_after (header);
+}
+
+/* Sparse file processing. */
+
+/* Takes a blockful of data and basically cruises through it to see if
+ it's made *entirely* of zeros, returning a 0 the instant it finds
+ something that is a nonzero, i.e., useful data. */
+static int
+zero_block_p (char *buffer)
+{
+ int counter;
+
+ for (counter = 0; counter < BLOCKSIZE; counter++)
+ if (buffer[counter] != '\0')
+ return 0;
+ return 1;
+}
+
+static void
+init_sparsearray (void)
+{
+ sp_array_size = 10;
+
+ /* Make room for our scratch space -- initially is 10 elts long. */
+
+ sparsearray = xmalloc (sp_array_size * sizeof (struct sp_array));
+}
+
+static off_t
+find_new_file_size (int sparses)
+{
+ int i;
+ off_t s = 0;
+ for (i = 0; i < sparses; i++)
+ s += sparsearray[i].numbytes;
+ return s;
+}
+
+/* Make one pass over the file NAME, studying where any non-zero data
+ is, that is, how far into the file each instance of data is, and
+ how many bytes are there. Save this information in the
+ sparsearray, which will later be translated into header
+ information. */
+
+/* There is little point in trimming small amounts of null data at the head
+ and tail of blocks, only avoid dumping full null blocks. */
+
+/* FIXME: this routine might accept bits of algorithmic cleanup, it is
+ too kludgey for my taste... */
+
+static int
+deal_with_sparse (char *name, union block *header)
+{
+ size_t numbytes = 0;
+ off_t offset = 0;
+ int file;
+ int sparses = 0;
+ ssize_t count;
+ char buffer[BLOCKSIZE];
+
+ if (archive_format == OLDGNU_FORMAT)
+ header->oldgnu_header.isextended = 0;
+
+ if (file = open (name, O_RDONLY), file < 0)
+ /* This problem will be caught later on, so just return. */
+ return 0;
+
+ init_sparsearray ();
+ clear_buffer (buffer);
+
+ for (;;)
+ {
+ /* Realloc the scratch area as necessary. FIXME: should reallocate
+ only at beginning of a new instance of non-zero data. */
+
+ if (sp_array_size <= sparses)
+ {
+ sparsearray =
+ xrealloc (sparsearray,
+ 2 * sp_array_size * sizeof (struct sp_array));
+ sp_array_size *= 2;
+ }
+
+ count = safe_read (file, buffer, sizeof buffer);
+ if (count <= 0)
+ break;
+
+ /* Process one block. */
+
+ if (count == sizeof buffer)
+
+ if (zero_block_p (buffer))
+ {
+ if (numbytes)
+ {
+ sparsearray[sparses++].numbytes = numbytes;
+ numbytes = 0;
+ }
+ }
+ else
+ {
+ if (!numbytes)
+ sparsearray[sparses].offset = offset;
+ numbytes += count;
+ }
+
+ else
+
+ /* Since count < sizeof buffer, we have the last bit of the file. */
+
+ if (!zero_block_p (buffer))
+ {
+ if (!numbytes)
+ sparsearray[sparses].offset = offset;
+ numbytes += count;
+ }
+ else
+ /* The next two lines are suggested by Andreas Degert, who says
+ they are required for trailing full blocks to be written to the
+ archive, when all zeroed. Yet, it seems to me that the case
+ does not apply. Further, at restore time, the file is not as
+ sparse as it should. So, some serious cleanup is *also* needed
+ in this area. Just one more... :-(. FIXME. */
+ if (numbytes)
+ numbytes += count;
+
+ /* Prepare for next block. */
+
+ offset += count;
+ /* FIXME: do not clear unless necessary. */
+ clear_buffer (buffer);
+ }
+
+ if (numbytes)
+ sparsearray[sparses++].numbytes = numbytes;
+ else
+ {
+ sparsearray[sparses].offset = offset - 1;
+ sparsearray[sparses++].numbytes = 1;
+ }
+
+ return close (file) == 0 && 0 <= count ? sparses : 0;
+}
+
+static int
+finish_sparse_file (int file, off_t *sizeleft, off_t fullsize, char *name)
+{
+ union block *start;
+ size_t bufsize;
+ int sparses = 0;
+ ssize_t count;
+
+ while (*sizeleft > 0)
+ {
+ start = find_next_block ();
+ memset (start->buffer, 0, BLOCKSIZE);
+ bufsize = sparsearray[sparses].numbytes;
+ if (! bufsize)
+ abort ();
+
+ if (lseek (file, sparsearray[sparses++].offset, SEEK_SET) < 0)
+ {
+ (ignore_failed_read_option ? seek_warn_details : seek_error_details)
+ (name, sparsearray[sparses - 1].offset);
+ break;
+ }
+
+ /* If the number of bytes to be written here exceeds the size of
+ the temporary buffer, do it in steps. */
+
+ while (bufsize > BLOCKSIZE)
+ {
+ count = safe_read (file, start->buffer, BLOCKSIZE);
+ if (count < 0)
+ {
+ (ignore_failed_read_option
+ ? read_warn_details
+ : read_error_details)
+ (name, fullsize - *sizeleft, bufsize);
+ return 1;
+ }
+ bufsize -= count;
+ *sizeleft -= count;
+ set_next_block_after (start);
+ start = find_next_block ();
+ memset (start->buffer, 0, BLOCKSIZE);
+ }
+
+ {
+ char buffer[BLOCKSIZE];
+
+ clear_buffer (buffer);
+ count = safe_read (file, buffer, bufsize);
+ memcpy (start->buffer, buffer, BLOCKSIZE);
+ }
+
+ if (count < 0)
+ {
+ (ignore_failed_read_option
+ ? read_warn_details
+ : read_error_details)
+ (name, fullsize - *sizeleft, bufsize);
+ return 1;
+ }
+
+ *sizeleft -= count;
+ set_next_block_after (start);
+ }
+ free (sparsearray);
+#if 0
+ set_next_block_after (start + (count - 1) / BLOCKSIZE);
+#endif
+ return 0;
+}
+
+/* Main functions of this module. */
+
+void
+create_archive (void)
+{
+ char *p;
+
+ open_archive (ACCESS_WRITE);
+
+ if (incremental_option)
+ {
+ size_t buffer_size = 1000;
+ char *buffer = xmalloc (buffer_size);
+ const char *q;
+
+ collect_and_sort_names ();
+
+ while (p = name_from_list (), p)
+ if (!excluded_name (p))
+ dump_file (p, -1, (dev_t) 0);
+
+ blank_name_list ();
+ while (p = name_from_list (), p)
+ if (!excluded_name (p))
+ {
+ size_t plen = strlen (p);
+ if (buffer_size <= plen)
+ {
+ while ((buffer_size *= 2) <= plen)
+ continue;
+ buffer = xrealloc (buffer, buffer_size);
+ }
+ memcpy (buffer, p, plen);
+ if (! ISSLASH (buffer[plen - 1]))
+ buffer[plen++] = '/';
+ q = gnu_list_name->dir_contents;
+ if (q)
+ while (*q)
+ {
+ size_t qlen = strlen (q);
+ if (*q == 'Y')
+ {
+ if (buffer_size < plen + qlen)
+ {
+ while ((buffer_size *=2 ) < plen + qlen)
+ continue;
+ buffer = xrealloc (buffer, buffer_size);
+ }
+ strcpy (buffer + plen, q + 1);
+ dump_file (buffer, -1, (dev_t) 0);
+ }
+ q += qlen + 1;
+ }
+ }
+ free (buffer);
+ }
+ else
+ {
+ while (p = name_next (1), p)
+ if (!excluded_name (p))
+ dump_file (p, 1, (dev_t) 0);
+ }
+
+ write_eot ();
+ close_archive ();
+
+ if (listed_incremental_option)
+ write_directory_file ();
+}
+
+
+/* Calculate the hash of a link. */
+static unsigned
+hash_link (void const *entry, unsigned n_buckets)
+{
+ struct link const *link = entry;
+ return (uintmax_t) (link->dev ^ link->ino) % n_buckets;
+}
+
+/* Compare two links for equality. */
+static bool
+compare_links (void const *entry1, void const *entry2)
+{
+ struct link const *link1 = entry1;
+ struct link const *link2 = entry2;
+ return ((link1->dev ^ link2->dev) | (link1->ino ^ link2->ino)) == 0;
+}
+
+/* Dump a single file, recursing on directories. P is the file name
+ to dump. TOP_LEVEL tells whether this is a top-level call; zero
+ means no, positive means yes, and negative means an incremental
+ dump. PARENT_DEVICE is the device of P's
+ parent directory; it is examined only if TOP_LEVEL is zero.
+
+ Set global CURRENT_STAT to stat output for this file. */
+
+/* FIXME: One should make sure that for *every* path leading to setting
+ exit_status to failure, a clear diagnostic has been issued. */
+
+void
+dump_file (char *p, int top_level, dev_t parent_device)
+{
+ union block *header;
+ char type;
+ union block *exhdr;
+ char save_typeflag;
+ time_t original_ctime;
+ struct utimbuf restore_times;
+
+ /* FIXME: `header' might be used uninitialized in this
+ function. Reported by Bruno Haible. */
+
+ if (interactive_option && !confirm ("add", p))
+ return;
+
+ if (deref_stat (dereference_option, p, &current_stat) != 0)
+ {
+ if (ignore_failed_read_option)
+ stat_warn (p);
+ else
+ stat_error (p);
+ return;
+ }
+
+ original_ctime = current_stat.st_ctime;
+ restore_times.actime = current_stat.st_atime;
+ restore_times.modtime = current_stat.st_mtime;
+
+#ifdef S_ISHIDDEN
+ if (S_ISHIDDEN (current_stat.st_mode))
+ {
+ char *new = (char *) alloca (strlen (p) + 2);
+ if (new)
+ {
+ strcpy (new, p);
+ strcat (new, "@");
+ p = new;
+ }
+ }
+#endif
+
+ /* See if we want only new files, and check if this one is too old to
+ put in the archive. */
+
+ if ((0 < top_level || !incremental_option)
+ && !S_ISDIR (current_stat.st_mode)
+ && current_stat.st_mtime < newer_mtime_option
+ && (!after_date_option || current_stat.st_ctime < newer_ctime_option))
+ {
+ if (0 < top_level)
+ WARN ((0, 0, _("%s: file is unchanged; not dumped"),
+ quotearg_colon (p)));
+ /* FIXME: recheck this return. */
+ return;
+ }
+
+#if !MSDOS
+ /* See if we are trying to dump the archive. */
+
+ if (ar_dev && current_stat.st_dev == ar_dev && current_stat.st_ino == ar_ino)
+ {
+ WARN ((0, 0, _("%s: file is the archive; not dumped"),
+ quotearg_colon (p)));
+ return;
+ }
+#endif
+
+ if (S_ISDIR (current_stat.st_mode))
+ {
+ char *directory;
+ char const *entry;
+ size_t entrylen;
+ char *namebuf;
+ size_t buflen;
+ size_t len;
+ dev_t our_device = current_stat.st_dev;
+
+ errno = 0;
+
+ directory = savedir (p);
+ if (! directory)
+ {
+ if (ignore_failed_read_option)
+ savedir_warn (p);
+ else
+ savedir_error (p);
+ return;
+ }
+
+ /* Build new prototype name. Ensure exactly one trailing slash. */
+
+ len = strlen (p);
+ buflen = len + NAME_FIELD_SIZE;
+ namebuf = xmalloc (buflen + 1);
+ memcpy (namebuf, p, len);
+ while (len >= 1 && ISSLASH (namebuf[len - 1]))
+ len--;
+ namebuf[len++] = '/';
+ namebuf[len] = '\0';
+
+ if (! is_avoided_name (namebuf))
+ {
+ /* The condition above used to be "archive_format != V7_FORMAT".
+ GNU tar was not writing directory blocks at all. Daniel Trinkle
+ writes: ``All old versions of tar I have ever seen have
+ correctly archived an empty directory. The really old ones I
+ checked included HP-UX 7 and Mt. Xinu More/BSD. There may be
+ some subtle reason for the exclusion that I don't know, but the
+ current behavior is broken.'' I do not know those subtle
+ reasons either, so until these are reported (anew?), just allow
+ directory blocks to be written even with old archives. */
+
+ current_stat.st_size = 0; /* force 0 size on dir */
+
+ /* FIXME: If people could really read standard archives, this
+ should be:
+
+ header
+ = start_header (standard_option ? p : namebuf, &current_stat);
+
+ but since they'd interpret DIRTYPE blocks as regular
+ files, we'd better put the / on the name. */
+
+ header = start_header (namebuf, &current_stat);
+
+ if (incremental_option)
+ header->header.typeflag = GNUTYPE_DUMPDIR;
+ else /* if (standard_option) */
+ header->header.typeflag = DIRTYPE;
+
+ /* If we're gnudumping, we aren't done yet so don't close it. */
+
+ if (!incremental_option)
+ finish_header (header); /* done with directory header */
+ }
+
+ if (incremental_option && gnu_list_name->dir_contents)
+ {
+ off_t sizeleft;
+ off_t totsize;
+ size_t bufsize;
+ union block *start;
+ ssize_t count;
+ const char *buffer, *p_buffer;
+
+ buffer = gnu_list_name->dir_contents; /* FOO */
+ totsize = 0;
+ for (p_buffer = buffer; p_buffer && *p_buffer;)
+ {
+ size_t tmp;
+
+ tmp = strlen (p_buffer) + 1;
+ totsize += tmp;
+ p_buffer += tmp;
+ }
+ totsize++;
+ OFF_TO_CHARS (totsize, header->header.size);
+ finish_header (header);
+ p_buffer = buffer;
+ sizeleft = totsize;
+ while (sizeleft > 0)
+ {
+ if (multi_volume_option)
+ {
+ assign_string (&save_name, p);
+ save_sizeleft = sizeleft;
+ save_totsize = totsize;
+ }
+ start = find_next_block ();
+ bufsize = available_space_after (start);
+ if (sizeleft < bufsize)
+ {
+ bufsize = sizeleft;
+ count = bufsize % BLOCKSIZE;
+ if (count)
+ memset (start->buffer + sizeleft, 0, BLOCKSIZE - count);
+ }
+ memcpy (start->buffer, p_buffer, bufsize);
+ sizeleft -= bufsize;
+ p_buffer += bufsize;
+ set_next_block_after (start + (bufsize - 1) / BLOCKSIZE);
+ }
+ if (multi_volume_option)
+ assign_string (&save_name, 0);
+ goto finish_dir;
+ }
+
+ /* See if we are about to recurse into a directory, and avoid doing
+ so if the user wants that we do not descend into directories. */
+
+ if (! recursion_option)
+ goto finish_dir;
+
+ /* See if we are crossing from one file system to another, and
+ avoid doing so if the user only wants to dump one file system. */
+
+ if (one_file_system_option && !top_level
+ && parent_device != current_stat.st_dev)
+ {
+ if (verbose_option)
+ WARN ((0, 0,
+ _("%s: file is on a different filesystem; not dumped"),
+ quotearg_colon (p)));
+ goto finish_dir;
+ }
+
+ /* Now output all the files in the directory. */
+
+ /* FIXME: Should speed this up by cd-ing into the dir. */
+
+ for (entry = directory;
+ (entrylen = strlen (entry)) != 0;
+ entry += entrylen + 1)
+ {
+ if (buflen <= len + entrylen)
+ {
+ buflen = len + entrylen;
+ namebuf = xrealloc (namebuf, buflen + 1);
+ }
+ strcpy (namebuf + len, entry);
+ if (!excluded_name (namebuf))
+ dump_file (namebuf, 0, our_device);
+ }
+
+ finish_dir:
+
+ free (directory);
+ free (namebuf);
+ if (atime_preserve_option)
+ utime (p, &restore_times);
+ return;
+ }
+ else if (is_avoided_name (p))
+ return;
+ else
+ {
+ /* Check for multiple links.
+
+ We maintain a table of all such files that we've written so
+ far. Any time we see another, we check the table and avoid
+ dumping the data again if we've done it once already. */
+
+ if (1 < current_stat.st_nlink)
+ {
+ static Hash_table *link_table;
+ struct link *lp = xmalloc (offsetof (struct link, name)
+ + strlen (p) + 1);
+ struct link *dup;
+ lp->ino = current_stat.st_ino;
+ lp->dev = current_stat.st_dev;
+ strcpy (lp->name, p);
+
+ if (! ((link_table
+ || (link_table = hash_initialize (0, 0, hash_link,
+ compare_links, 0)))
+ && (dup = hash_insert (link_table, lp))))
+ xalloc_die ();
+
+ if (dup != lp)
+ {
+ /* We found a link. */
+ char const *link_name = relativize (dup->name);
+
+ free (lp);
+
+ if (NAME_FIELD_SIZE <= strlen (link_name))
+ write_long (link_name, GNUTYPE_LONGLINK);
+ assign_string (&current_link_name, link_name);
+
+ current_stat.st_size = 0;
+ header = start_header (p, &current_stat);
+ strncpy (header->header.linkname, link_name, NAME_FIELD_SIZE);
+
+ /* Force null termination. */
+ header->header.linkname[NAME_FIELD_SIZE - 1] = 0;
+
+ header->header.typeflag = LNKTYPE;
+ finish_header (header);
+
+ /* FIXME: Maybe remove from table after all links found? */
+
+ if (remove_files_option && unlink (p) != 0)
+ unlink_error (p);
+
+ /* We dumped it. */
+ return;
+ }
+ }
+
+ /* This is not a link to a previously dumped file, so dump it. */
+
+ if (S_ISREG (current_stat.st_mode)
+ || S_ISCTG (current_stat.st_mode))
+ {
+ int f; /* file descriptor */
+ size_t bufsize;
+ ssize_t count;
+ off_t sizeleft;
+ union block *start;
+ int header_moved;
+ char isextended = 0;
+ int sparses = 0;
+
+ header_moved = 0;
+
+ if (sparse_option)
+ {
+ /* Check the size of the file against the number of blocks
+ allocated for it, counting both data and indirect blocks.
+ If there is a smaller number of blocks that would be
+ necessary to accommodate a file of this size, this is safe
+ to say that we have a sparse file: at least one of those
+ blocks in the file is just a useless hole. For sparse
+ files not having more hole blocks than indirect blocks, the
+ sparseness will go undetected. */
+
+ /* Bruno Haible sent me these statistics for Linux. It seems
+ that some filesystems count indirect blocks in st_blocks,
+ while others do not seem to:
+
+ minix-fs tar: size=7205, st_blocks=18 and ST_NBLOCKS=18
+ extfs tar: size=7205, st_blocks=18 and ST_NBLOCKS=18
+ ext2fs tar: size=7205, st_blocks=16 and ST_NBLOCKS=16
+ msdos-fs tar: size=7205, st_blocks=16 and ST_NBLOCKS=16
+
+ Dick Streefland reports the previous numbers as misleading,
+ because ext2fs use 12 direct blocks, while minix-fs uses only
+ 6 direct blocks. Dick gets:
+
+ ext2 size=20480 ls listed blocks=21
+ minix size=20480 ls listed blocks=21
+ msdos size=20480 ls listed blocks=20
+
+ It seems that indirect blocks *are* included in st_blocks.
+ The minix filesystem does not account for phantom blocks in
+ st_blocks, so `du' and `ls -s' give wrong results. So, the
+ --sparse option would not work on a minix filesystem. */
+
+ if (ST_NBLOCKS (current_stat)
+ < (current_stat.st_size / ST_NBLOCKSIZE
+ + (current_stat.st_size % ST_NBLOCKSIZE != 0)))
+ {
+ int counter;
+
+ header = start_header (p, &current_stat);
+ header->header.typeflag = GNUTYPE_SPARSE;
+ header_moved = 1;
+
+ /* Call the routine that figures out the layout of the
+ sparse file in question. SPARSES is the index of the
+ first unused element of the "sparsearray," i.e.,
+ the number of elements it needed to describe the file. */
+
+ sparses = deal_with_sparse (p, header);
+
+ /* See if we'll need an extended header later. */
+
+ if (SPARSES_IN_OLDGNU_HEADER < sparses)
+ header->oldgnu_header.isextended = 1;
+
+ /* We store the "real" file size so we can show that in
+ case someone wants to list the archive, i.e., tar tvf
+ <file>. It might be kind of disconcerting if the
+ shrunken file size was the one that showed up. */
+
+ OFF_TO_CHARS (current_stat.st_size,
+ header->oldgnu_header.realsize);
+
+ /* This will be the new "size" of the file, i.e., the size
+ of the file minus the blocks of holes that we're
+ skipping over. */
+
+ current_stat.st_size = find_new_file_size (sparses);
+ OFF_TO_CHARS (current_stat.st_size, header->header.size);
+
+ for (counter = 0;
+ counter < sparses && counter < SPARSES_IN_OLDGNU_HEADER;
+ counter++)
+ {
+ OFF_TO_CHARS (sparsearray[counter].offset,
+ header->oldgnu_header.sp[counter].offset);
+ SIZE_TO_CHARS (sparsearray[counter].numbytes,
+ header->oldgnu_header.sp[counter].numbytes);
+ }
+ }
+ }
+
+ sizeleft = current_stat.st_size;
+
+ /* Don't bother opening empty, world readable files. Also do not open
+ files when archive is meant for /dev/null. */
+
+ if (dev_null_output
+ || (sizeleft == 0
+ && MODE_R == (MODE_R & current_stat.st_mode)))
+ f = -1;
+ else
+ {
+ f = open (p, O_RDONLY | O_BINARY);
+ if (f < 0)
+ {
+ if (! top_level && errno == ENOENT)
+ WARN ((0, 0, _("%s: File removed before we read it"),
+ quotearg_colon (p)));
+ else
+ (ignore_failed_read_option ? open_warn : open_error) (p);
+ return;
+ }
+ }
+
+ /* If the file is sparse, we've already taken care of this. */
+
+ if (!header_moved)
+ header = start_header (p, &current_stat);
+
+ /* Mark contiguous files, if we support them. */
+
+ if (archive_format != V7_FORMAT && S_ISCTG (current_stat.st_mode))
+ header->header.typeflag = CONTTYPE;
+
+ isextended = header->oldgnu_header.isextended;
+ save_typeflag = header->header.typeflag;
+ finish_header (header);
+ if (isextended)
+ {
+ int sparses_emitted = SPARSES_IN_OLDGNU_HEADER;
+
+ for (;;)
+ {
+ int i;
+ exhdr = find_next_block ();
+ memset (exhdr->buffer, 0, BLOCKSIZE);
+ for (i = 0;
+ (i < SPARSES_IN_SPARSE_HEADER
+ && sparses_emitted + i < sparses);
+ i++)
+ {
+ SIZE_TO_CHARS (sparsearray[sparses_emitted + i].numbytes,
+ exhdr->sparse_header.sp[i].numbytes);
+ OFF_TO_CHARS (sparsearray[sparses_emitted + i].offset,
+ exhdr->sparse_header.sp[i].offset);
+ }
+ set_next_block_after (exhdr);
+ sparses_emitted += i;
+ if (sparses == sparses_emitted)
+ break;
+ exhdr->sparse_header.isextended = 1;
+ }
+ }
+ if (save_typeflag == GNUTYPE_SPARSE)
+ {
+ if (f < 0
+ || finish_sparse_file (f, &sizeleft,
+ current_stat.st_size, p))
+ goto padit;
+ }
+ else
+ while (sizeleft > 0)
+ {
+ if (multi_volume_option)
+ {
+ assign_string (&save_name, p);
+ save_sizeleft = sizeleft;
+ save_totsize = current_stat.st_size;
+ }
+ start = find_next_block ();
+
+ bufsize = available_space_after (start);
+
+ if (sizeleft < bufsize)
+ {
+ /* Last read -- zero out area beyond. */
+
+ bufsize = sizeleft;
+ count = bufsize % BLOCKSIZE;
+ if (count)
+ memset (start->buffer + sizeleft, 0, BLOCKSIZE - count);
+ }
+ if (f < 0)
+ count = bufsize;
+ else
+ count = safe_read (f, start->buffer, bufsize);
+ if (count < 0)
+ {
+ (ignore_failed_read_option
+ ? read_warn_details
+ : read_error_details)
+ (p, current_stat.st_size - sizeleft, bufsize);
+ goto padit;
+ }
+ sizeleft -= bufsize;
+
+ /* This is nonportable (the type of set_next_block_after's arg). */
+
+ set_next_block_after (start + (bufsize - 1) / BLOCKSIZE);
+
+
+ if (count != bufsize)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+ memset (start->buffer + count, 0, bufsize - count);
+ WARN ((0, 0,
+ _("%s: File shrank by %s bytes; padding with zeros"),
+ quotearg_colon (p),
+ STRINGIFY_BIGINT (sizeleft, buf)));
+ if (! ignore_failed_read_option)
+ exit_status = TAREXIT_FAILURE;
+ goto padit; /* short read */
+ }
+ }
+
+ if (multi_volume_option)
+ assign_string (&save_name, 0);
+
+ if (f >= 0)
+ {
+ struct stat final_stat;
+ if (fstat (f, &final_stat) != 0)
+ {
+ if (ignore_failed_read_option)
+ stat_warn (p);
+ else
+ stat_error (p);
+ }
+ else if (final_stat.st_ctime != original_ctime)
+ {
+ char const *qp = quotearg_colon (p);
+ WARN ((0, 0, _("%s: file changed as we read it"), qp));
+ if (! ignore_failed_read_option)
+ exit_status = TAREXIT_FAILURE;
+ }
+ if (close (f) != 0)
+ {
+ if (ignore_failed_read_option)
+ close_warn (p);
+ else
+ close_error (p);
+ }
+ if (atime_preserve_option)
+ utime (p, &restore_times);
+ }
+ if (remove_files_option)
+ {
+ if (unlink (p) == -1)
+ unlink_error (p);
+ }
+ return;
+
+ /* File shrunk or gave error, pad out tape to match the size we
+ specified in the header. */
+
+ padit:
+ while (sizeleft > 0)
+ {
+ save_sizeleft = sizeleft;
+ start = find_next_block ();
+ memset (start->buffer, 0, BLOCKSIZE);
+ set_next_block_after (start);
+ sizeleft -= BLOCKSIZE;
+ }
+ if (multi_volume_option)
+ assign_string (&save_name, 0);
+ if (f >= 0)
+ {
+ close (f);
+ if (atime_preserve_option)
+ utime (p, &restore_times);
+ }
+ return;
+ }
+#ifdef HAVE_READLINK
+ else if (S_ISLNK (current_stat.st_mode))
+ {
+ char *buffer;
+ int size;
+ size_t linklen = current_stat.st_size;
+ if (linklen != current_stat.st_size || linklen + 1 == 0)
+ xalloc_die ();
+ buffer = (char *) alloca (linklen + 1);
+ size = readlink (p, buffer, linklen + 1);
+ if (size < 0)
+ {
+ if (ignore_failed_read_option)
+ readlink_warn (p);
+ else
+ readlink_error (p);
+ return;
+ }
+ buffer[size] = '\0';
+ if (size >= NAME_FIELD_SIZE)
+ write_long (buffer, GNUTYPE_LONGLINK);
+ assign_string (&current_link_name, buffer);
+
+ current_stat.st_size = 0; /* force 0 size on symlink */
+ header = start_header (p, &current_stat);
+ strncpy (header->header.linkname, buffer, NAME_FIELD_SIZE);
+ header->header.linkname[NAME_FIELD_SIZE - 1] = '\0';
+ header->header.typeflag = SYMTYPE;
+ finish_header (header); /* nothing more to do to it */
+ if (remove_files_option)
+ {
+ if (unlink (p) == -1)
+ unlink_error (p);
+ }
+ return;
+ }
+#endif
+ else if (S_ISCHR (current_stat.st_mode))
+ type = CHRTYPE;
+ else if (S_ISBLK (current_stat.st_mode))
+ type = BLKTYPE;
+ else if (S_ISFIFO (current_stat.st_mode))
+ type = FIFOTYPE;
+ else if (S_ISSOCK (current_stat.st_mode))
+ {
+ WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p)));
+ return;
+ }
+ else if (S_ISDOOR (current_stat.st_mode))
+ {
+ WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p)));
+ return;
+ }
+ else
+ goto unknown;
+ }
+
+ if (archive_format == V7_FORMAT)
+ goto unknown;
+
+ current_stat.st_size = 0; /* force 0 size */
+ header = start_header (p, &current_stat);
+ header->header.typeflag = type;
+
+ if (type != FIFOTYPE)
+ {
+ MAJOR_TO_CHARS (major (current_stat.st_rdev), header->header.devmajor);
+ MINOR_TO_CHARS (minor (current_stat.st_rdev), header->header.devminor);
+ }
+
+ finish_header (header);
+ if (remove_files_option)
+ {
+ if (unlink (p) == -1)
+ unlink_error (p);
+ }
+ return;
+
+unknown:
+ WARN ((0, 0, _("%s: Unknown file type; file ignored"),
+ quotearg_colon (p)));
+ if (! ignore_failed_read_option)
+ exit_status = TAREXIT_FAILURE;
+}
diff --git a/contrib/tar/src/delete.c b/contrib/tar/src/delete.c
new file mode 100644
index 0000000..ad7b590
--- /dev/null
+++ b/contrib/tar/src/delete.c
@@ -0,0 +1,364 @@
+/* Delete entries from a tar archive.
+
+ Copyright (C) 1988, 1992, 1994, 1996, 1997, 2000, 2001 Free
+ Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+
+#include "common.h"
+#include "rmt.h"
+
+static union block *new_record;
+static int new_blocks;
+static bool acting_as_filter;
+
+/* FIXME: This module should not directly handle the following
+ variables, instead, the interface should be cleaned up. */
+extern union block *record_start;
+extern union block *record_end;
+extern union block *current_block;
+extern union block *recent_long_name;
+extern union block *recent_long_link;
+extern size_t recent_long_name_blocks;
+extern size_t recent_long_link_blocks;
+extern off_t records_read;
+extern off_t records_written;
+
+/* The number of records skipped at the start of the archive, when
+ passing over members that are not deleted. */
+static off_t records_skipped;
+
+/* Move archive descriptor by COUNT records worth. If COUNT is
+ positive we move forward, else we move negative. If it's a tape,
+ MTIOCTOP had better work. If it's something else, we try to seek
+ on it. If we can't seek, we lose! */
+static void
+move_archive (off_t count)
+{
+ if (count == 0)
+ return;
+
+#ifdef MTIOCTOP
+ {
+ struct mtop operation;
+
+ if (count < 0
+ ? (operation.mt_op = MTBSR,
+ operation.mt_count = -count,
+ operation.mt_count == -count)
+ : (operation.mt_op = MTFSR,
+ operation.mt_count = count,
+ operation.mt_count == count))
+ {
+ if (0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
+ return;
+
+ if (errno == EIO
+ && 0 <= rmtioctl (archive, MTIOCTOP, (char *) &operation))
+ return;
+ }
+ }
+#endif /* MTIOCTOP */
+
+ {
+ off_t position0 = rmtlseek (archive, (off_t) 0, SEEK_CUR);
+ off_t increment = record_size * (off_t) count;
+ off_t position = position0 + increment;
+
+ if (increment / count != record_size
+ || (position < position0) != (increment < 0)
+ || (position = position < 0 ? 0 : position,
+ rmtlseek (archive, position, SEEK_SET) != position))
+ seek_error_details (archive_name_array[0], position);
+
+ return;
+ }
+}
+
+/* Write out the record which has been filled. If MOVE_BACK_FLAG,
+ backspace to where we started. */
+static void
+write_record (int move_back_flag)
+{
+ union block *save_record = record_start;
+ record_start = new_record;
+
+ if (acting_as_filter)
+ {
+ archive = STDOUT_FILENO;
+ flush_write ();
+ archive = STDIN_FILENO;
+ }
+ else
+ {
+ move_archive ((records_written + records_skipped) - records_read);
+ flush_write ();
+ }
+
+ record_start = save_record;
+
+ if (move_back_flag)
+ {
+ /* Move the tape head back to where we were. */
+
+ if (! acting_as_filter)
+ move_archive (records_read - (records_written + records_skipped));
+ }
+
+ new_blocks = 0;
+}
+
+static void
+write_recent_blocks (union block *h, size_t blocks)
+{
+ size_t i;
+ for (i = 0; i < blocks; i++)
+ {
+ new_record[new_blocks++] = h[i];
+ if (new_blocks == blocking_factor)
+ write_record (1);
+ }
+}
+
+void
+delete_archive_members (void)
+{
+ enum read_header logical_status = HEADER_STILL_UNREAD;
+ enum read_header previous_status = HEADER_STILL_UNREAD;
+
+ /* FIXME: Should clean the routine before cleaning these variables :-( */
+ struct name *name;
+ off_t blocks_to_skip = 0;
+ off_t blocks_to_keep = 0;
+ int kept_blocks_in_record;
+
+ name_gather ();
+ open_archive (ACCESS_UPDATE);
+ acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
+
+ do
+ {
+ enum read_header status = read_header (1);
+
+ switch (status)
+ {
+ case HEADER_STILL_UNREAD:
+ abort ();
+
+ case HEADER_SUCCESS:
+ if (name = name_scan (current_file_name), !name)
+ {
+ skip_member ();
+ break;
+ }
+ name->found = 1;
+ /* Fall through. */
+ case HEADER_SUCCESS_EXTENDED:
+ logical_status = status;
+ break;
+
+ case HEADER_ZERO_BLOCK:
+ if (ignore_zeros_option)
+ {
+ set_next_block_after (current_header);
+ break;
+ }
+ /* Fall through. */
+ case HEADER_END_OF_FILE:
+ logical_status = HEADER_END_OF_FILE;
+ break;
+
+ case HEADER_FAILURE:
+ set_next_block_after (current_header);
+ switch (previous_status)
+ {
+ case HEADER_STILL_UNREAD:
+ WARN ((0, 0, _("This does not look like a tar archive")));
+ /* Fall through. */
+
+ case HEADER_SUCCESS:
+ case HEADER_ZERO_BLOCK:
+ ERROR ((0, 0, _("Skipping to next header")));
+ /* Fall through. */
+
+ case HEADER_FAILURE:
+ break;
+
+ case HEADER_END_OF_FILE:
+ abort ();
+ }
+ break;
+ }
+
+ previous_status = status;
+ }
+ while (logical_status == HEADER_STILL_UNREAD);
+
+ records_skipped = records_read - 1;
+ new_record = xmalloc (record_size);
+
+ if (logical_status == HEADER_SUCCESS
+ || logical_status == HEADER_SUCCESS_EXTENDED)
+ {
+ write_archive_to_stdout = 0;
+
+ /* Save away blocks before this one in this record. */
+
+ new_blocks = current_block - record_start;
+ if (new_blocks)
+ memcpy (new_record, record_start, new_blocks * BLOCKSIZE);
+
+ if (logical_status == HEADER_SUCCESS)
+ {
+ /* FIXME: Pheew! This is crufty code! */
+ logical_status = HEADER_STILL_UNREAD;
+ goto flush_file;
+ }
+
+ /* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
+ "delete.c", line 223: warning: loop not entered at top
+ Reported by Bruno Haible. */
+ while (1)
+ {
+ enum read_header status;
+
+ /* Fill in a record. */
+
+ if (current_block == record_end)
+ flush_archive ();
+ status = read_header (0);
+
+ if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
+ {
+ set_next_block_after (current_header);
+ continue;
+ }
+ if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
+ {
+ logical_status = HEADER_END_OF_FILE;
+ break;
+ }
+
+ if (status == HEADER_FAILURE)
+ {
+ ERROR ((0, 0, _("Deleting non-header from archive")));
+ set_next_block_after (current_header);
+ continue;
+ }
+
+ /* Found another header. */
+
+ if (name = name_scan (current_file_name), name)
+ {
+ name->found = 1;
+ flush_file:
+ set_next_block_after (current_header);
+ blocks_to_skip = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
+
+ while (record_end - current_block <= blocks_to_skip)
+ {
+ blocks_to_skip -= (record_end - current_block);
+ flush_archive ();
+ }
+ current_block += blocks_to_skip;
+ blocks_to_skip = 0;
+ continue;
+ }
+
+ /* Copy header. */
+
+ write_recent_blocks (recent_long_name, recent_long_name_blocks);
+ write_recent_blocks (recent_long_link, recent_long_link_blocks);
+ new_record[new_blocks] = *current_header;
+ new_blocks++;
+ blocks_to_keep
+ = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
+ set_next_block_after (current_header);
+ if (new_blocks == blocking_factor)
+ write_record (1);
+
+ /* Copy data. */
+
+ kept_blocks_in_record = record_end - current_block;
+ if (kept_blocks_in_record > blocks_to_keep)
+ kept_blocks_in_record = blocks_to_keep;
+
+ while (blocks_to_keep)
+ {
+ int count;
+
+ if (current_block == record_end)
+ {
+ flush_read ();
+ current_block = record_start;
+ kept_blocks_in_record = blocking_factor;
+ if (kept_blocks_in_record > blocks_to_keep)
+ kept_blocks_in_record = blocks_to_keep;
+ }
+ count = kept_blocks_in_record;
+ if (blocking_factor - new_blocks < count)
+ count = blocking_factor - new_blocks;
+
+ if (! count)
+ abort ();
+
+ memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
+ new_blocks += count;
+ current_block += count;
+ blocks_to_keep -= count;
+ kept_blocks_in_record -= count;
+
+ if (new_blocks == blocking_factor)
+ write_record (1);
+ }
+ }
+ }
+
+ if (logical_status == HEADER_END_OF_FILE)
+ {
+ /* Write the end of tape. FIXME: we can't use write_eot here,
+ as it gets confused when the input is at end of file. */
+
+ int total_zero_blocks = 0;
+
+ do
+ {
+ int zero_blocks = blocking_factor - new_blocks;
+ memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks);
+ total_zero_blocks += zero_blocks;
+ write_record (total_zero_blocks < 2);
+ }
+ while (total_zero_blocks < 2);
+ }
+
+ free (new_record);
+
+ if (! acting_as_filter && ! _isrmt (archive))
+ {
+#if MSDOS
+ int status = write (archive, "", 0);
+#else
+ off_t pos = lseek (archive, (off_t) 0, SEEK_CUR);
+ int status = pos < 0 ? -1 : ftruncate (archive, pos);
+#endif
+ if (status != 0)
+ truncate_warn (archive_name_array[0]);
+ }
+
+ close_archive ();
+ names_notfound ();
+}
diff --git a/contrib/tar/src/extract.c b/contrib/tar/src/extract.c
new file mode 100644
index 0000000..2a3f9bf
--- /dev/null
+++ b/contrib/tar/src/extract.c
@@ -0,0 +1,1313 @@
+/* Extract files from a tar archive.
+
+ Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
+ 2001 Free Software Foundation, Inc.
+
+ Written by John Gilmore, on 1985-11-19.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include <quotearg.h>
+
+#if HAVE_UTIME_H
+# include <utime.h>
+#else
+struct utimbuf
+ {
+ long actime;
+ long modtime;
+ };
+#endif
+
+#include "common.h"
+
+int we_are_root; /* true if our effective uid == 0 */
+static mode_t newdir_umask; /* umask when creating new directories */
+static mode_t current_umask; /* current umask (which is set to 0 if -p) */
+
+/* Status of the permissions of a file that we are extracting. */
+enum permstatus
+{
+ /* This file may have existed already; its permissions are unknown. */
+ UNKNOWN_PERMSTATUS,
+
+ /* This file was created using the permissions from the archive. */
+ ARCHIVED_PERMSTATUS,
+
+ /* This is an intermediate directory; the archive did not specify
+ its permissions. */
+ INTERDIR_PERMSTATUS
+};
+
+/* 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_SYMLINKS is nonzero and [^D]
+ represents an element where AFTER_SYMLINKS 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 stat stat_info;
+ size_t file_name_len;
+ mode_t invert_permissions;
+ enum permstatus permstatus;
+ bool after_symlinks;
+ char file_name[1];
+ };
+
+static struct delayed_set_stat *delayed_set_stat_head;
+
+/* List of symbolic links whose creation we have delayed. */
+struct delayed_symlink
+ {
+ /* The next delayed symbolic link in the list. */
+ struct delayed_symlink *next;
+
+ /* The device, inode number and last-modified time of the placeholder. */
+ dev_t dev;
+ ino_t ino;
+ time_t mtime;
+
+ /* The desired owner and group of the symbolic link. */
+ uid_t uid;
+ gid_t gid;
+
+ /* A list of sources for this symlink. The sources are all to be
+ hard-linked together. */
+ struct string_list *sources;
+
+ /* The desired target of the desired link. */
+ char target[1];
+ };
+
+static struct delayed_symlink *delayed_symlink_head;
+
+struct string_list
+ {
+ struct string_list *next;
+ char string[1];
+ };
+
+/* Set up to extract files. */
+void
+extr_init (void)
+{
+ we_are_root = geteuid () == 0;
+ same_permissions_option += we_are_root;
+ same_owner_option += we_are_root;
+ xalloc_fail_func = extract_finish;
+
+ /* Option -p clears the kernel umask, so it does not affect proper
+ restoration of file permissions. New intermediate directories will
+ comply with umask at start of program. */
+
+ newdir_umask = umask (0);
+ if (0 < same_permissions_option)
+ current_umask = 0;
+ else
+ {
+ umask (newdir_umask); /* restore the kernel umask */
+ current_umask = newdir_umask;
+ }
+}
+
+/* If restoring permissions, restore the mode for FILE_NAME from
+ information given in *STAT_INFO (where *CURRENT_STAT_INFO gives
+ the current status if CURRENT_STAT_INFO is nonzero); otherwise invert the
+ INVERT_PERMISSIONS bits from the file's current permissions.
+ PERMSTATUS specifies the status of the file's permissions.
+ TYPEFLAG specifies the type of the file. */
+static void
+set_mode (char const *file_name, struct stat const *stat_info,
+ struct stat const *current_stat_info,
+ mode_t invert_permissions, enum permstatus permstatus,
+ char typeflag)
+{
+ mode_t mode;
+
+ if (0 < same_permissions_option
+ && permstatus != INTERDIR_PERMSTATUS)
+ {
+ mode = stat_info->st_mode;
+
+ /* If we created the file and it has a usual mode, then its mode
+ is normally set correctly already. But on many hosts, some
+ directories inherit the setgid bits from their parents, so we
+ we must set directories' modes explicitly. */
+ if (permstatus == ARCHIVED_PERMSTATUS
+ && ! (mode & ~ MODE_RWX)
+ && typeflag != DIRTYPE
+ && typeflag != GNUTYPE_DUMPDIR)
+ return;
+ }
+ else if (! invert_permissions)
+ return;
+ else
+ {
+ /* We must inspect a directory's current permissions, since the
+ directory may have inherited its setgid bit from its parent.
+
+ INVERT_PERMISSIONS happens to be nonzero only for directories
+ that we created, so there's no point optimizing this code for
+ other cases. */
+ struct stat st;
+ if (! current_stat_info)
+ {
+ if (stat (file_name, &st) != 0)
+ {
+ stat_error (file_name);
+ return;
+ }
+ current_stat_info = &st;
+ }
+ mode = current_stat_info->st_mode ^ invert_permissions;
+ }
+
+ if (chmod (file_name, mode) != 0)
+ chmod_error_details (file_name, mode);
+}
+
+/* Check time after successfully setting FILE_NAME's time stamp to T. */
+static void
+check_time (char const *file_name, time_t t)
+{
+ time_t now;
+ if (start_time < t && (now = time (0)) < t)
+ WARN ((0, 0, _("%s: time stamp %s is %lu s in the future"),
+ file_name, tartime (t), (unsigned long) (t - now)));
+}
+
+/* Restore stat attributes (owner, group, mode and times) for
+ FILE_NAME, using information given in *STAT_INFO.
+ If CURRENT_STAT_INFO is nonzero, *CURRENT_STAT_INFO is the
+ file's currernt status.
+ If not restoring permissions, invert the
+ INVERT_PERMISSIONS bits from the file's current permissions.
+ PERMSTATUS specifies the status of the file's permissions.
+ TYPEFLAG specifies the type of the file. */
+
+/* FIXME: About proper restoration of symbolic link attributes, we still do
+ not have it right. Pretesters' reports tell us we need further study and
+ probably more configuration. For now, just use lchown if it exists, and
+ punt for the rest. Sigh! */
+
+static void
+set_stat (char const *file_name, struct stat const *stat_info,
+ struct stat const *current_stat_info,
+ mode_t invert_permissions, enum permstatus permstatus,
+ char typeflag)
+{
+ struct utimbuf utimbuf;
+
+ if (typeflag != SYMTYPE)
+ {
+ /* We do the utime before the chmod because some versions of utime are
+ broken and trash the modes of the file. */
+
+ if (! touch_option && permstatus != INTERDIR_PERMSTATUS)
+ {
+ /* We set the accessed time to `now', which is really the time we
+ started extracting files, unless incremental_option is used, in
+ which case .st_atime is used. */
+
+ /* FIXME: incremental_option should set ctime too, but how? */
+
+ if (incremental_option)
+ utimbuf.actime = stat_info->st_atime;
+ else
+ utimbuf.actime = start_time;
+
+ utimbuf.modtime = stat_info->st_mtime;
+
+ if (utime (file_name, &utimbuf) < 0)
+ utime_error (file_name);
+ else
+ {
+ check_time (file_name, stat_info->st_atime);
+ check_time (file_name, stat_info->st_mtime);
+ }
+ }
+
+ /* Some systems allow non-root users to give files away. Once this
+ done, it is not possible anymore to change file permissions, so we
+ have to set permissions prior to possibly giving files away. */
+
+ set_mode (file_name, stat_info, current_stat_info,
+ invert_permissions, permstatus, typeflag);
+ }
+
+ if (0 < same_owner_option && permstatus != INTERDIR_PERMSTATUS)
+ {
+ /* When lchown exists, it should be used to change the attributes of
+ the symbolic link itself. In this case, a mere chown would change
+ the attributes of the file the symbolic link is pointing to, and
+ should be avoided. */
+
+ if (typeflag == SYMTYPE)
+ {
+#if HAVE_LCHOWN
+ if (lchown (file_name, stat_info->st_uid, stat_info->st_gid) < 0)
+ chown_error_details (file_name,
+ stat_info->st_uid, stat_info->st_gid);
+#endif
+ }
+ else
+ {
+ if (chown (file_name, stat_info->st_uid, stat_info->st_gid) < 0)
+ chown_error_details (file_name,
+ stat_info->st_uid, stat_info->st_gid);
+
+ /* On a few systems, and in particular, those allowing to give files
+ away, changing the owner or group destroys the suid or sgid bits.
+ So let's attempt setting these bits once more. */
+ if (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX))
+ set_mode (file_name, stat_info, 0,
+ invert_permissions, permstatus, typeflag);
+ }
+ }
+}
+
+/* Remember to restore stat attributes (owner, group, mode and times)
+ for the directory FILE_NAME, using information given in *STAT_INFO,
+ once we stop extracting files into that directory.
+ If not restoring permissions, remember to invert the
+ INVERT_PERMISSIONS bits from the file's current permissions.
+ PERMSTATUS specifies the status of the file's permissions. */
+static void
+delay_set_stat (char const *file_name, struct stat const *stat_info,
+ mode_t invert_permissions, enum permstatus permstatus)
+{
+ size_t file_name_len = strlen (file_name);
+ struct delayed_set_stat *data =
+ xmalloc (offsetof (struct delayed_set_stat, file_name)
+ + file_name_len + 1);
+ data->file_name_len = file_name_len;
+ strcpy (data->file_name, file_name);
+ data->invert_permissions = invert_permissions;
+ data->permstatus = permstatus;
+ data->after_symlinks = 0;
+ data->stat_info = *stat_info;
+ data->next = delayed_set_stat_head;
+ delayed_set_stat_head = data;
+}
+
+/* Update the delayed_set_stat info for an intermediate directory
+ created on the path to DIR_NAME. 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. */
+static void
+repair_delayed_set_stat (char const *dir_name,
+ struct stat const *dir_stat_info)
+{
+ struct delayed_set_stat *data;
+ for (data = delayed_set_stat_head; data; data = data->next)
+ {
+ struct stat st;
+ if (stat (data->file_name, &st) != 0)
+ {
+ stat_error (data->file_name);
+ return;
+ }
+
+ if (st.st_dev == dir_stat_info->st_dev
+ && st.st_ino == dir_stat_info->st_ino)
+ {
+ data->stat_info = current_stat;
+ data->invert_permissions = (MODE_RWX
+ & (current_stat.st_mode ^ st.st_mode));
+ data->permstatus = ARCHIVED_PERMSTATUS;
+ return;
+ }
+ }
+
+ ERROR ((0, 0, _("%s: Unexpected inconsistency when making directory"),
+ quotearg_colon (dir_name)));
+}
+
+/* After a file/link/symlink/directory creation has failed, see if
+ it's because some required directory was not present, and if so,
+ create all required directories. Return non-zero if a directory
+ was created. */
+static int
+make_directories (char *file_name)
+{
+ char *cursor0 = file_name + FILESYSTEM_PREFIX_LEN (file_name);
+ char *cursor; /* points into path */
+ int did_something = 0; /* did we do anything yet? */
+ int mode;
+ int invert_permissions;
+ int status;
+
+
+ for (cursor = cursor0; *cursor; cursor++)
+ {
+ if (! ISSLASH (*cursor))
+ continue;
+
+ /* Avoid mkdir of empty string, if leading or double '/'. */
+
+ if (cursor == cursor0 || ISSLASH (cursor[-1]))
+ continue;
+
+ /* Avoid mkdir where last part of path is "." or "..". */
+
+ if (cursor[-1] == '.'
+ && (cursor == cursor0 + 1 || ISSLASH (cursor[-2])
+ || (cursor[-2] == '.'
+ && (cursor == cursor0 + 2 || ISSLASH (cursor[-3])))))
+ continue;
+
+ *cursor = '\0'; /* truncate the path there */
+ mode = MODE_RWX & ~ newdir_umask;
+ invert_permissions = we_are_root ? 0 : MODE_WXUSR & ~ mode;
+ status = mkdir (file_name, mode ^ invert_permissions);
+
+ if (status == 0)
+ {
+ /* Create a struct delayed_set_stat even if
+ invert_permissions is zero, because
+ repair_delayed_set_stat may need to update the struct. */
+ delay_set_stat (file_name,
+ &current_stat /* ignored */,
+ invert_permissions, INTERDIR_PERMSTATUS);
+
+ print_for_mkdir (file_name, cursor - file_name, mode);
+ did_something = 1;
+
+ *cursor = '/';
+ continue;
+ }
+
+ *cursor = '/';
+
+ if (errno == EEXIST
+#if MSDOS
+ /* Turbo C mkdir gives a funny errno. */
+ || errno == EACCES
+#endif
+ )
+ /* Directory already exists. */
+ continue;
+
+ /* Some other error in the mkdir. We return to the caller. */
+ break;
+ }
+
+ return did_something; /* tell them to retry if we made one */
+}
+
+/* Prepare to extract a file.
+ Return zero if extraction should not proceed. */
+
+static int
+prepare_to_extract (char const *file_name)
+{
+ if (to_stdout_option)
+ return 0;
+
+ if (old_files_option == UNLINK_FIRST_OLD_FILES
+ && !remove_any_file (file_name, recursive_unlink_option)
+ && errno && errno != ENOENT)
+ {
+ unlink_error (file_name);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Attempt repairing what went wrong with the extraction. Delete an
+ already existing file or create missing intermediate directories.
+ Return nonzero if we somewhat increased our chances at a successful
+ extraction. errno is properly restored on zero return. */
+static int
+maybe_recoverable (char *file_name, int *interdir_made)
+{
+ if (*interdir_made)
+ return 0;
+
+ switch (errno)
+ {
+ case EEXIST:
+ /* Remove an old file, if the options allow this. */
+
+ switch (old_files_option)
+ {
+ default:
+ return 0;
+
+ case DEFAULT_OLD_FILES:
+ case OVERWRITE_OLD_DIRS:
+ case OVERWRITE_OLD_FILES:
+ {
+ int r = remove_any_file (file_name, 0);
+ errno = EEXIST;
+ return r;
+ }
+ }
+
+ case ENOENT:
+ /* Attempt creating missing intermediate directories. */
+ if (! make_directories (file_name))
+ {
+ errno = ENOENT;
+ return 0;
+ }
+ *interdir_made = 1;
+ return 1;
+
+ default:
+ /* Just say we can't do anything about it... */
+
+ return 0;
+ }
+}
+
+static void
+extract_sparse_file (int fd, off_t *sizeleft, off_t totalsize, char *name)
+{
+ int sparse_ind = 0;
+
+ /* assuming sizeleft is initially totalsize */
+
+ while (*sizeleft > 0)
+ {
+ size_t written;
+ size_t count;
+ union block *data_block = find_next_block ();
+ if (! data_block)
+ {
+ ERROR ((0, 0, _("Unexpected EOF in archive")));
+ return;
+ }
+ if (lseek (fd, sparsearray[sparse_ind].offset, SEEK_SET) < 0)
+ {
+ seek_error_details (name, sparsearray[sparse_ind].offset);
+ return;
+ }
+ written = sparsearray[sparse_ind++].numbytes;
+ while (written > BLOCKSIZE)
+ {
+ count = full_write (fd, data_block->buffer, BLOCKSIZE);
+ written -= count;
+ *sizeleft -= count;
+ if (count != BLOCKSIZE)
+ {
+ write_error_details (name, count, BLOCKSIZE);
+ return;
+ }
+ set_next_block_after (data_block);
+ data_block = find_next_block ();
+ if (! data_block)
+ {
+ ERROR ((0, 0, _("Unexpected EOF in archive")));
+ return;
+ }
+ }
+
+ count = full_write (fd, data_block->buffer, written);
+ *sizeleft -= count;
+
+ if (count != written)
+ {
+ write_error_details (name, count, written);
+ return;
+ }
+
+ set_next_block_after (data_block);
+ }
+}
+
+/* Fix the statuses of all directories whose statuses need fixing, and
+ which are not ancestors of FILE_NAME. If AFTER_SYMLINKS is
+ nonzero, do this for all such directories; otherwise, stop at the
+ first directory that is marked to be fixed up only after delayed
+ symlinks are applied. */
+static void
+apply_nonancestor_delayed_set_stat (char const *file_name, bool after_symlinks)
+{
+ size_t file_name_len = strlen (file_name);
+ bool check_for_renamed_directories = 0;
+
+ while (delayed_set_stat_head)
+ {
+ struct delayed_set_stat *data = delayed_set_stat_head;
+ bool skip_this_one = 0;
+ struct stat st;
+ struct stat const *current_stat_info = 0;
+
+ check_for_renamed_directories |= data->after_symlinks;
+
+ if (after_symlinks < data->after_symlinks
+ || (data->file_name_len < file_name_len
+ && file_name[data->file_name_len]
+ && (ISSLASH (file_name[data->file_name_len])
+ || ISSLASH (file_name[data->file_name_len - 1]))
+ && memcmp (file_name, data->file_name, data->file_name_len) == 0))
+ break;
+
+ if (check_for_renamed_directories)
+ {
+ current_stat_info = &st;
+ if (stat (data->file_name, &st) != 0)
+ {
+ stat_error (data->file_name);
+ skip_this_one = 1;
+ }
+ else if (! (st.st_dev == data->stat_info.st_dev
+ && (st.st_ino == data->stat_info.st_ino)))
+ {
+ ERROR ((0, 0,
+ _("%s: Directory renamed before its status could be extracted"),
+ quotearg_colon (data->file_name)));
+ skip_this_one = 1;
+ }
+ }
+
+ if (! skip_this_one)
+ set_stat (data->file_name, &data->stat_info, current_stat_info,
+ data->invert_permissions, data->permstatus, DIRTYPE);
+
+ delayed_set_stat_head = data->next;
+ free (data);
+ }
+}
+
+/* Extract a file from the archive. */
+void
+extract_archive (void)
+{
+ union block *data_block;
+ int fd;
+ int status;
+ size_t count;
+ size_t name_length;
+ size_t written;
+ int openflag;
+ mode_t mode;
+ off_t size;
+ size_t skipcrud;
+ int counter;
+ int interdir_made = 0;
+ char typeflag;
+ union block *exhdr;
+
+#define CURRENT_FILE_NAME (skipcrud + current_file_name)
+
+ set_next_block_after (current_header);
+ decode_header (current_header, &current_stat, &current_format, 1);
+
+ if (interactive_option && !confirm ("extract", current_file_name))
+ {
+ skip_member ();
+ return;
+ }
+
+ /* Print the block from current_header and current_stat. */
+
+ if (verbose_option)
+ print_header ();
+
+ /* Check for fully specified file names and other atrocities. */
+
+ skipcrud = 0;
+ if (! absolute_names_option)
+ {
+ if (contains_dot_dot (CURRENT_FILE_NAME))
+ {
+ ERROR ((0, 0, _("%s: Member name contains `..'"),
+ quotearg_colon (CURRENT_FILE_NAME)));
+ skip_member ();
+ return;
+ }
+
+ skipcrud = FILESYSTEM_PREFIX_LEN (current_file_name);
+ while (ISSLASH (CURRENT_FILE_NAME[0]))
+ skipcrud++;
+
+ if (skipcrud)
+ {
+ static int warned_once;
+
+ if (!warned_once)
+ {
+ warned_once = 1;
+ WARN ((0, 0, _("Removing leading `%.*s' from member names"),
+ (int) skipcrud, current_file_name));
+ }
+ }
+ }
+
+ apply_nonancestor_delayed_set_stat (CURRENT_FILE_NAME, 0);
+
+ /* Take a safety backup of a previously existing file. */
+
+ if (backup_option && !to_stdout_option)
+ if (!maybe_backup_file (CURRENT_FILE_NAME, 0))
+ {
+ int e = errno;
+ ERROR ((0, e, _("%s: Was unable to backup this file"),
+ quotearg_colon (CURRENT_FILE_NAME)));
+ skip_member ();
+ return;
+ }
+
+ /* Extract the archive entry according to its type. */
+
+ typeflag = current_header->header.typeflag;
+ switch (typeflag)
+ {
+ /* JK - What we want to do if the file is sparse is loop through
+ the array of sparse structures in the header and read in and
+ translate the character strings representing 1) the offset at
+ which to write and 2) how many bytes to write into numbers,
+ which we store into the scratch array, "sparsearray". This
+ array makes our life easier the same way it did in creating the
+ tar file that had to deal with a sparse file.
+
+ After we read in the first five (at most) sparse structures, we
+ check to see if the file has an extended header, i.e., if more
+ sparse structures are needed to describe the contents of the new
+ file. If so, we read in the extended headers and continue to
+ store their contents into the sparsearray. */
+
+ case GNUTYPE_SPARSE:
+ sp_array_size = 10;
+ sparsearray =
+ xmalloc (sp_array_size * sizeof (struct sp_array));
+
+ for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++)
+ {
+ struct sparse const *s = &current_header->oldgnu_header.sp[counter];
+ sparsearray[counter].offset = OFF_FROM_HEADER (s->offset);
+ sparsearray[counter].numbytes = SIZE_FROM_HEADER (s->numbytes);
+ if (!sparsearray[counter].numbytes)
+ break;
+ }
+
+ if (current_header->oldgnu_header.isextended)
+ {
+ /* Read in the list of extended headers and translate them
+ into the sparsearray as before. Note that this
+ invalidates current_header. */
+
+ /* static */ int ind = SPARSES_IN_OLDGNU_HEADER;
+
+ while (1)
+ {
+ exhdr = find_next_block ();
+ if (! exhdr)
+ {
+ ERROR ((0, 0, _("Unexpected EOF in archive")));
+ return;
+ }
+ for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++)
+ {
+ struct sparse const *s = &exhdr->sparse_header.sp[counter];
+ if (counter + ind > sp_array_size - 1)
+ {
+ /* Realloc the scratch area since we've run out of
+ room. */
+
+ sp_array_size *= 2;
+ sparsearray =
+ xrealloc (sparsearray,
+ sp_array_size * sizeof (struct sp_array));
+ }
+ if (s->numbytes[0] == 0)
+ break;
+ sparsearray[counter + ind].offset =
+ OFF_FROM_HEADER (s->offset);
+ sparsearray[counter + ind].numbytes =
+ SIZE_FROM_HEADER (s->numbytes);
+ }
+ if (!exhdr->sparse_header.isextended)
+ break;
+ else
+ {
+ ind += SPARSES_IN_SPARSE_HEADER;
+ set_next_block_after (exhdr);
+ }
+ }
+ set_next_block_after (exhdr);
+ }
+ /* Fall through. */
+
+ case AREGTYPE:
+ case REGTYPE:
+ case CONTTYPE:
+
+ /* Appears to be a file. But BSD tar uses the convention that a slash
+ suffix means a directory. */
+
+ name_length = strlen (CURRENT_FILE_NAME);
+ if (FILESYSTEM_PREFIX_LEN (CURRENT_FILE_NAME) < name_length
+ && CURRENT_FILE_NAME[name_length - 1] == '/')
+ goto really_dir;
+
+ /* FIXME: deal with protection issues. */
+
+ again_file:
+ openflag = (O_WRONLY | O_BINARY | O_CREAT
+ | (old_files_option == OVERWRITE_OLD_FILES
+ ? O_TRUNC
+ : O_EXCL));
+ mode = current_stat.st_mode & MODE_RWX & ~ current_umask;
+
+ if (to_stdout_option)
+ {
+ fd = STDOUT_FILENO;
+ goto extract_file;
+ }
+
+ if (! prepare_to_extract (CURRENT_FILE_NAME))
+ {
+ skip_member ();
+ if (backup_option)
+ undo_last_backup ();
+ break;
+ }
+
+#if O_CTG
+ /* Contiguous files (on the Masscomp) have to specify the size in
+ the open call that creates them. */
+
+ if (typeflag == CONTTYPE)
+ fd = open (CURRENT_FILE_NAME, openflag | O_CTG,
+ mode, current_stat.st_size);
+ else
+ fd = open (CURRENT_FILE_NAME, openflag, mode);
+
+#else /* not O_CTG */
+ if (typeflag == CONTTYPE)
+ {
+ static int conttype_diagnosed;
+
+ if (!conttype_diagnosed)
+ {
+ conttype_diagnosed = 1;
+ WARN ((0, 0, _("Extracting contiguous files as regular files")));
+ }
+ }
+ fd = open (CURRENT_FILE_NAME, openflag, mode);
+
+#endif /* not O_CTG */
+
+ if (fd < 0)
+ {
+ if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
+ goto again_file;
+
+ open_error (CURRENT_FILE_NAME);
+ skip_member ();
+ if (backup_option)
+ undo_last_backup ();
+ break;
+ }
+
+ extract_file:
+ if (typeflag == GNUTYPE_SPARSE)
+ {
+ char *name;
+ size_t name_length_bis;
+
+ /* Kludge alert. NAME is assigned to header.name because
+ during the extraction, the space that contains the header
+ will get scribbled on, and the name will get munged, so any
+ error messages that happen to contain the filename will look
+ REAL interesting unless we do this. */
+
+ name_length_bis = strlen (CURRENT_FILE_NAME) + 1;
+ name = xmalloc (name_length_bis);
+ memcpy (name, CURRENT_FILE_NAME, name_length_bis);
+ size = current_stat.st_size;
+ extract_sparse_file (fd, &size, current_stat.st_size, name);
+ free (sparsearray);
+ }
+ else
+ for (size = current_stat.st_size; size > 0; )
+ {
+ if (multi_volume_option)
+ {
+ assign_string (&save_name, current_file_name);
+ save_totsize = current_stat.st_size;
+ save_sizeleft = size;
+ }
+
+ /* Locate data, determine max length writeable, write it,
+ block that we have used the data, then check if the write
+ worked. */
+
+ data_block = find_next_block ();
+ if (! data_block)
+ {
+ ERROR ((0, 0, _("Unexpected EOF in archive")));
+ break; /* FIXME: What happens, then? */
+ }
+
+ written = available_space_after (data_block);
+
+ if (written > size)
+ written = size;
+ errno = 0;
+ count = full_write (fd, data_block->buffer, written);
+ size -= count;
+
+ set_next_block_after ((union block *)
+ (data_block->buffer + written - 1));
+ if (count != written)
+ {
+ write_error_details (CURRENT_FILE_NAME, count, written);
+ break;
+ }
+ }
+
+ skip_file (size);
+
+ if (multi_volume_option)
+ assign_string (&save_name, 0);
+
+ /* If writing to stdout, don't try to do anything to the filename;
+ it doesn't exist, or we don't want to touch it anyway. */
+
+ if (to_stdout_option)
+ break;
+
+ status = close (fd);
+ if (status < 0)
+ {
+ close_error (CURRENT_FILE_NAME);
+ if (backup_option)
+ undo_last_backup ();
+ }
+
+ set_stat (CURRENT_FILE_NAME, &current_stat, 0, 0,
+ (old_files_option == OVERWRITE_OLD_FILES
+ ? UNKNOWN_PERMSTATUS
+ : ARCHIVED_PERMSTATUS),
+ typeflag);
+ break;
+
+ case SYMTYPE:
+#ifdef HAVE_SYMLINK
+ if (! prepare_to_extract (CURRENT_FILE_NAME))
+ break;
+
+ if (absolute_names_option
+ || ! (ISSLASH (current_link_name
+ [FILESYSTEM_PREFIX_LEN (current_link_name)])
+ || contains_dot_dot (current_link_name)))
+ {
+ while (status = symlink (current_link_name, CURRENT_FILE_NAME),
+ status != 0)
+ if (!maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
+ break;
+
+ if (status == 0)
+ set_stat (CURRENT_FILE_NAME, &current_stat, 0, 0, 0, SYMTYPE);
+ else
+ symlink_error (current_link_name, CURRENT_FILE_NAME);
+ }
+ else
+ {
+ /* This symbolic link is potentially dangerous. Don't
+ create it now; instead, create a placeholder file, which
+ will be replaced after other extraction is done. */
+ struct stat st;
+
+ while (fd = open (CURRENT_FILE_NAME, O_WRONLY | O_CREAT | O_EXCL, 0),
+ fd < 0)
+ if (! maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
+ break;
+
+ status = -1;
+ if (fd < 0)
+ open_error (CURRENT_FILE_NAME);
+ else if (fstat (fd, &st) != 0)
+ {
+ stat_error (CURRENT_FILE_NAME);
+ close (fd);
+ }
+ else if (close (fd) != 0)
+ close_error (CURRENT_FILE_NAME);
+ else
+ {
+ struct delayed_set_stat *h;
+ struct delayed_symlink *p =
+ xmalloc (offsetof (struct delayed_symlink, target)
+ + strlen (current_link_name) + 1);
+ p->next = delayed_symlink_head;
+ delayed_symlink_head = p;
+ p->dev = st.st_dev;
+ p->ino = st.st_ino;
+ p->mtime = st.st_mtime;
+ p->uid = current_stat.st_uid;
+ p->gid = current_stat.st_gid;
+ p->sources = xmalloc (offsetof (struct string_list, string)
+ + strlen (CURRENT_FILE_NAME) + 1);
+ p->sources->next = 0;
+ strcpy (p->sources->string, CURRENT_FILE_NAME);
+ strcpy (p->target, current_link_name);
+
+ h = delayed_set_stat_head;
+ if (h && ! h->after_symlinks
+ && strncmp (CURRENT_FILE_NAME, h->file_name, h->file_name_len) == 0
+ && ISSLASH (CURRENT_FILE_NAME[h->file_name_len])
+ && (base_name (CURRENT_FILE_NAME)
+ == CURRENT_FILE_NAME + h->file_name_len + 1))
+ {
+ do
+ {
+ h->after_symlinks = 1;
+
+ if (stat (h->file_name, &st) != 0)
+ stat_error (h->file_name);
+ else
+ {
+ h->stat_info.st_dev = st.st_dev;
+ h->stat_info.st_ino = st.st_ino;
+ }
+ }
+ while ((h = h->next) && ! h->after_symlinks);
+ }
+
+ status = 0;
+ }
+ }
+
+ if (status != 0 && backup_option)
+ undo_last_backup ();
+ break;
+
+#else
+ {
+ static int warned_once;
+
+ if (!warned_once)
+ {
+ warned_once = 1;
+ WARN ((0, 0,
+ _("Attempting extraction of symbolic links as hard links")));
+ }
+ }
+ typeflag = LNKTYPE;
+ /* Fall through. */
+#endif
+
+ case LNKTYPE:
+ if (! prepare_to_extract (CURRENT_FILE_NAME))
+ break;
+
+ again_link:
+ {
+ struct stat st1, st2;
+ int e;
+
+ /* MSDOS does not implement links. However, djgpp's link() actually
+ copies the file. */
+ status = link (current_link_name, CURRENT_FILE_NAME);
+
+ if (status == 0)
+ {
+ struct delayed_symlink *ds = delayed_symlink_head;
+ if (ds && stat (current_link_name, &st1) == 0)
+ for (; ds; ds = ds->next)
+ if (ds->dev == st1.st_dev
+ && ds->ino == st1.st_ino
+ && ds->mtime == st1.st_mtime)
+ {
+ struct string_list *p =
+ xmalloc (offsetof (struct string_list, string)
+ + strlen (CURRENT_FILE_NAME) + 1);
+ strcpy (p->string, CURRENT_FILE_NAME);
+ p->next = ds->sources;
+ ds->sources = p;
+ break;
+ }
+ break;
+ }
+ if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
+ goto again_link;
+
+ if (incremental_option && errno == EEXIST)
+ break;
+ e = errno;
+ if (stat (current_link_name, &st1) == 0
+ && stat (CURRENT_FILE_NAME, &st2) == 0
+ && st1.st_dev == st2.st_dev
+ && st1.st_ino == st2.st_ino)
+ break;
+
+ link_error (current_link_name, CURRENT_FILE_NAME);
+ if (backup_option)
+ undo_last_backup ();
+ }
+ break;
+
+#if S_IFCHR
+ case CHRTYPE:
+ current_stat.st_mode |= S_IFCHR;
+ goto make_node;
+#endif
+
+#if S_IFBLK
+ case BLKTYPE:
+ current_stat.st_mode |= S_IFBLK;
+#endif
+
+#if S_IFCHR || S_IFBLK
+ make_node:
+ if (! prepare_to_extract (CURRENT_FILE_NAME))
+ break;
+
+ status = mknod (CURRENT_FILE_NAME, current_stat.st_mode,
+ current_stat.st_rdev);
+ if (status != 0)
+ {
+ if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
+ goto make_node;
+ mknod_error (CURRENT_FILE_NAME);
+ if (backup_option)
+ undo_last_backup ();
+ break;
+ };
+ set_stat (CURRENT_FILE_NAME, &current_stat, 0, 0,
+ ARCHIVED_PERMSTATUS, typeflag);
+ break;
+#endif
+
+#if HAVE_MKFIFO || defined mkfifo
+ case FIFOTYPE:
+ if (! prepare_to_extract (CURRENT_FILE_NAME))
+ break;
+
+ while (status = mkfifo (CURRENT_FILE_NAME, current_stat.st_mode),
+ status != 0)
+ if (!maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
+ break;
+
+ if (status == 0)
+ set_stat (CURRENT_FILE_NAME, &current_stat, 0, 0,
+ ARCHIVED_PERMSTATUS, typeflag);
+ else
+ {
+ mkfifo_error (CURRENT_FILE_NAME);
+ if (backup_option)
+ undo_last_backup ();
+ }
+ break;
+#endif
+
+ case DIRTYPE:
+ case GNUTYPE_DUMPDIR:
+ name_length = strlen (CURRENT_FILE_NAME);
+
+ really_dir:
+ /* Remove any redundant trailing "/"s. */
+ while (FILESYSTEM_PREFIX_LEN (CURRENT_FILE_NAME) < name_length
+ && CURRENT_FILE_NAME[name_length - 1] == '/')
+ name_length--;
+ CURRENT_FILE_NAME[name_length] = '\0';
+
+ if (incremental_option)
+ {
+ /* Read the entry and delete files that aren't listed in the
+ archive. */
+
+ gnu_restore (skipcrud);
+ }
+ else if (typeflag == GNUTYPE_DUMPDIR)
+ skip_member ();
+
+ if (! prepare_to_extract (CURRENT_FILE_NAME))
+ break;
+
+ mode = ((current_stat.st_mode
+ | (we_are_root ? 0 : MODE_WXUSR))
+ & MODE_RWX);
+
+ again_dir:
+ status = mkdir (CURRENT_FILE_NAME, mode);
+
+ if (status != 0)
+ {
+ if (errno == EEXIST
+ && (interdir_made
+ || old_files_option == OVERWRITE_OLD_DIRS
+ || old_files_option == OVERWRITE_OLD_FILES))
+ {
+ struct stat st;
+ if (stat (CURRENT_FILE_NAME, &st) == 0)
+ {
+ if (interdir_made)
+ {
+ repair_delayed_set_stat (CURRENT_FILE_NAME, &st);
+ break;
+ }
+ if (S_ISDIR (st.st_mode))
+ {
+ mode = st.st_mode & ~ current_umask;
+ goto directory_exists;
+ }
+ }
+ errno = EEXIST;
+ }
+
+ if (maybe_recoverable (CURRENT_FILE_NAME, &interdir_made))
+ goto again_dir;
+
+ if (errno != EEXIST)
+ {
+ mkdir_error (CURRENT_FILE_NAME);
+ if (backup_option)
+ undo_last_backup ();
+ break;
+ }
+ }
+
+ directory_exists:
+ if (status == 0
+ || old_files_option == OVERWRITE_OLD_DIRS
+ || old_files_option == OVERWRITE_OLD_FILES)
+ delay_set_stat (CURRENT_FILE_NAME, &current_stat,
+ MODE_RWX & (mode ^ current_stat.st_mode),
+ (status == 0
+ ? ARCHIVED_PERMSTATUS
+ : UNKNOWN_PERMSTATUS));
+ break;
+
+ case GNUTYPE_VOLHDR:
+ if (verbose_option)
+ fprintf (stdlis, _("Reading %s\n"), quote (current_file_name));
+ break;
+
+ case GNUTYPE_NAMES:
+ extract_mangle ();
+ break;
+
+ case GNUTYPE_MULTIVOL:
+ ERROR ((0, 0,
+ _("%s: Cannot extract -- file is continued from another volume"),
+ quotearg_colon (current_file_name)));
+ skip_member ();
+ if (backup_option)
+ undo_last_backup ();
+ break;
+
+ case GNUTYPE_LONGNAME:
+ case GNUTYPE_LONGLINK:
+ ERROR ((0, 0, _("Visible long name error")));
+ skip_member ();
+ if (backup_option)
+ undo_last_backup ();
+ break;
+
+ default:
+ WARN ((0, 0,
+ _("%s: Unknown file type '%c', extracted as normal file"),
+ quotearg_colon (CURRENT_FILE_NAME), typeflag));
+ goto again_file;
+ }
+
+#undef CURRENT_FILE_NAME
+}
+
+/* Extract the symbolic links whose final extraction were delayed. */
+static void
+apply_delayed_symlinks (void)
+{
+ struct delayed_symlink *ds;
+
+ for (ds = delayed_symlink_head; ds; )
+ {
+ struct string_list *sources = ds->sources;
+ char const *valid_source = 0;
+
+ for (sources = ds->sources; sources; sources = sources->next)
+ {
+ char const *source = sources->string;
+ struct stat st;
+
+ /* Make sure the placeholder file is still there. If not,
+ don't create a symlink, as the placeholder was probably
+ removed by a later extraction. */
+ if (lstat (source, &st) == 0
+ && st.st_dev == ds->dev
+ && st.st_ino == ds->ino
+ && st.st_mtime == ds->mtime)
+ {
+ /* Unlink the placeholder, then create a hard link if possible,
+ a symbolic link otherwise. */
+ if (unlink (source) != 0)
+ unlink_error (source);
+ else if (valid_source && link (valid_source, source) == 0)
+ ;
+ else if (symlink (ds->target, source) != 0)
+ symlink_error (ds->target, source);
+ else
+ {
+ valid_source = source;
+ st.st_uid = ds->uid;
+ st.st_gid = ds->gid;
+ set_stat (source, &st, 0, 0, 0, SYMTYPE);
+ }
+ }
+ }
+
+ for (sources = ds->sources; sources; )
+ {
+ struct string_list *next = sources->next;
+ free (sources);
+ sources = next;
+ }
+
+ {
+ struct delayed_symlink *next = ds->next;
+ free (ds);
+ ds = next;
+ }
+ }
+
+ delayed_symlink_head = 0;
+}
+
+/* Finish the extraction of an archive. */
+void
+extract_finish (void)
+{
+ /* First, fix the status of ordinary directories that need fixing. */
+ apply_nonancestor_delayed_set_stat ("", 0);
+
+ /* Then, apply delayed symlinks, so that they don't affect delayed
+ directory status-setting for ordinary directories. */
+ apply_delayed_symlinks ();
+
+ /* Finally, fix the status of directories that are ancestors
+ of delayed symlinks. */
+ apply_nonancestor_delayed_set_stat ("", 1);
+}
+
+void
+fatal_exit (void)
+{
+ extract_finish ();
+ error (TAREXIT_FAILURE, 0, _("Error is not recoverable: exiting now"));
+ abort ();
+}
diff --git a/contrib/tar/src/incremen.c b/contrib/tar/src/incremen.c
new file mode 100644
index 0000000..7dd43e9
--- /dev/null
+++ b/contrib/tar/src/incremen.c
@@ -0,0 +1,584 @@
+/* GNU dump extensions to tar.
+
+ Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free
+ Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include <getline.h>
+#include <hash.h>
+#include <quotearg.h>
+#include "common.h"
+
+/* Variable sized generic character buffers. */
+
+struct accumulator
+{
+ size_t allocated;
+ size_t length;
+ char *pointer;
+};
+
+/* Amount of space guaranteed just after a reallocation. */
+#define ACCUMULATOR_SLACK 50
+
+/* Return the accumulated data from an ACCUMULATOR buffer. */
+static char *
+get_accumulator (struct accumulator *accumulator)
+{
+ return accumulator->pointer;
+}
+
+/* Allocate and return a new accumulator buffer. */
+static struct accumulator *
+new_accumulator (void)
+{
+ struct accumulator *accumulator
+ = xmalloc (sizeof (struct accumulator));
+
+ accumulator->allocated = ACCUMULATOR_SLACK;
+ accumulator->pointer = xmalloc (ACCUMULATOR_SLACK);
+ accumulator->length = 0;
+ return accumulator;
+}
+
+/* Deallocate an ACCUMULATOR buffer. */
+static void
+delete_accumulator (struct accumulator *accumulator)
+{
+ free (accumulator->pointer);
+ free (accumulator);
+}
+
+/* At the end of an ACCUMULATOR buffer, add a DATA block of SIZE bytes. */
+static void
+add_to_accumulator (struct accumulator *accumulator,
+ const char *data, size_t size)
+{
+ if (accumulator->length + size > accumulator->allocated)
+ {
+ accumulator->allocated = accumulator->length + size + ACCUMULATOR_SLACK;
+ accumulator->pointer =
+ xrealloc (accumulator->pointer, accumulator->allocated);
+ }
+ memcpy (accumulator->pointer + accumulator->length, data, size);
+ accumulator->length += size;
+}
+
+/* Incremental dump specialities. */
+
+/* Which child files to save under a directory. */
+enum children {NO_CHILDREN, CHANGED_CHILDREN, ALL_CHILDREN};
+
+/* Directory attributes. */
+struct directory
+ {
+ dev_t device_number; /* device number for directory */
+ ino_t inode_number; /* inode number for directory */
+ enum children children;
+ char nfs;
+ char found;
+ char name[1]; /* path name of directory */
+ };
+
+static Hash_table *directory_table;
+
+#if HAVE_ST_FSTYPE_STRING
+ static char const nfs_string[] = "nfs";
+# define NFS_FILE_STAT(st) (strcmp ((st).st_fstype, nfs_string) == 0)
+#else
+# define ST_DEV_MSB(st) (~ (dev_t) 0 << (sizeof (st).st_dev * CHAR_BIT - 1))
+# define NFS_FILE_STAT(st) (((st).st_dev & ST_DEV_MSB (st)) != 0)
+#endif
+
+/* Calculate the hash of a directory. */
+static unsigned
+hash_directory (void const *entry, unsigned n_buckets)
+{
+ struct directory const *directory = entry;
+ return hash_string (directory->name, n_buckets);
+}
+
+/* Compare two directories for equality. */
+static bool
+compare_directories (void const *entry1, void const *entry2)
+{
+ struct directory const *directory1 = entry1;
+ struct directory const *directory2 = entry2;
+ return strcmp (directory1->name, directory2->name) == 0;
+}
+
+/* Create and link a new directory entry for directory NAME, having a
+ device number DEV and an inode number INO, with NFS indicating
+ whether it is an NFS device and FOUND indicating whether we have
+ found that the directory exists. */
+static struct directory *
+note_directory (char const *name, dev_t dev, ino_t ino, bool nfs, bool found)
+{
+ size_t size = offsetof (struct directory, name) + strlen (name) + 1;
+ struct directory *directory = xmalloc (size);
+
+ directory->device_number = dev;
+ directory->inode_number = ino;
+ directory->children = CHANGED_CHILDREN;
+ directory->nfs = nfs;
+ directory->found = found;
+ strcpy (directory->name, name);
+
+ if (! ((directory_table
+ || (directory_table = hash_initialize (0, 0, hash_directory,
+ compare_directories, 0)))
+ && hash_insert (directory_table, directory)))
+ xalloc_die ();
+
+ return directory;
+}
+
+/* Return a directory entry for a given path NAME, or zero if none found. */
+static struct directory *
+find_directory (char *name)
+{
+ if (! directory_table)
+ return 0;
+ else
+ {
+ size_t size = offsetof (struct directory, name) + strlen (name) + 1;
+ struct directory *dir = alloca (size);
+ strcpy (dir->name, name);
+ return hash_lookup (directory_table, dir);
+ }
+}
+
+static int
+compare_dirents (const void *first, const void *second)
+{
+ return strcmp ((*(char *const *) first) + 1,
+ (*(char *const *) second) + 1);
+}
+
+char *
+get_directory_contents (char *path, dev_t device)
+{
+ struct accumulator *accumulator;
+
+ /* Recursively scan the given PATH. */
+
+ {
+ char *dirp = savedir (path); /* for scanning directory */
+ char const *entry; /* directory entry being scanned */
+ size_t entrylen; /* length of directory entry */
+ char *name_buffer; /* directory, `/', and directory member */
+ size_t name_buffer_size; /* allocated size of name_buffer, minus 2 */
+ size_t name_length; /* used length in name_buffer */
+ struct directory *directory; /* for checking if already already seen */
+ enum children children;
+
+ if (! dirp)
+ savedir_error (path);
+ errno = 0;
+
+ name_buffer_size = strlen (path) + NAME_FIELD_SIZE;
+ name_buffer = xmalloc (name_buffer_size + 2);
+ strcpy (name_buffer, path);
+ if (! ISSLASH (path[strlen (path) - 1]))
+ strcat (name_buffer, "/");
+ name_length = strlen (name_buffer);
+
+ directory = find_directory (path);
+ children = directory ? directory->children : CHANGED_CHILDREN;
+
+ accumulator = new_accumulator ();
+
+ if (children != NO_CHILDREN)
+ for (entry = dirp;
+ (entrylen = strlen (entry)) != 0;
+ entry += entrylen + 1)
+ {
+ if (name_buffer_size <= entrylen + name_length)
+ {
+ do
+ name_buffer_size += NAME_FIELD_SIZE;
+ while (name_buffer_size <= entrylen + name_length);
+ name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
+ }
+ strcpy (name_buffer + name_length, entry);
+
+ if (excluded_name (name_buffer))
+ add_to_accumulator (accumulator, "N", 1);
+ else
+ {
+ struct stat stat_data;
+
+ if (deref_stat (dereference_option, name_buffer, &stat_data))
+ {
+ if (ignore_failed_read_option)
+ stat_warn (name_buffer);
+ else
+ stat_error (name_buffer);
+ continue;
+ }
+
+ if (S_ISDIR (stat_data.st_mode))
+ {
+ bool nfs = NFS_FILE_STAT (stat_data);
+
+ if (directory = find_directory (name_buffer), directory)
+ {
+ /* With NFS, the same file can have two different devices
+ if an NFS directory is mounted in multiple locations,
+ which is relatively common when automounting.
+ To avoid spurious incremental redumping of
+ directories, consider all NFS devices as equal,
+ relying on the i-node to establish differences. */
+
+ if (! (((directory->nfs & nfs)
+ || directory->device_number == stat_data.st_dev)
+ && directory->inode_number == stat_data.st_ino))
+ {
+ if (verbose_option)
+ WARN ((0, 0, _("%s: Directory has been renamed"),
+ quotearg_colon (name_buffer)));
+ directory->children = ALL_CHILDREN;
+ directory->nfs = nfs;
+ directory->device_number = stat_data.st_dev;
+ directory->inode_number = stat_data.st_ino;
+ }
+ directory->found = 1;
+ }
+ else
+ {
+ if (verbose_option)
+ WARN ((0, 0, _("%s: Directory is new"),
+ quotearg_colon (name_buffer)));
+ directory = note_directory (name_buffer,
+ stat_data.st_dev,
+ stat_data.st_ino, nfs, 1);
+ directory->children =
+ ((listed_incremental_option
+ || newer_mtime_option <= stat_data.st_mtime
+ || (after_date_option &&
+ newer_ctime_option <= stat_data.st_ctime))
+ ? ALL_CHILDREN
+ : CHANGED_CHILDREN);
+ }
+
+ if (one_file_system_option && device != stat_data.st_dev)
+ directory->children = NO_CHILDREN;
+ else if (children == ALL_CHILDREN)
+ directory->children = ALL_CHILDREN;
+
+ add_to_accumulator (accumulator, "D", 1);
+ }
+
+ else if (one_file_system_option && device != stat_data.st_dev)
+ add_to_accumulator (accumulator, "N", 1);
+
+#ifdef S_ISHIDDEN
+ else if (S_ISHIDDEN (stat_data.st_mode))
+ {
+ add_to_accumulator (accumulator, "D", 1);
+ add_to_accumulator (accumulator, entry, entrylen);
+ add_to_accumulator (accumulator, "A", 2);
+ continue;
+ }
+#endif
+
+ else
+ if (children == CHANGED_CHILDREN
+ && stat_data.st_mtime < newer_mtime_option
+ && (!after_date_option
+ || stat_data.st_ctime < newer_ctime_option))
+ add_to_accumulator (accumulator, "N", 1);
+ else
+ add_to_accumulator (accumulator, "Y", 1);
+ }
+
+ add_to_accumulator (accumulator, entry, entrylen + 1);
+ }
+
+ add_to_accumulator (accumulator, "\000\000", 2);
+
+ free (name_buffer);
+ free (dirp);
+ }
+
+ /* Sort the contents of the directory, now that we have it all. */
+
+ {
+ char *pointer = get_accumulator (accumulator);
+ size_t counter;
+ char *cursor;
+ char *buffer;
+ char **array;
+ char **array_cursor;
+
+ counter = 0;
+ for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
+ counter++;
+
+ if (! counter)
+ {
+ delete_accumulator (accumulator);
+ return 0;
+ }
+
+ array = xmalloc (sizeof (char *) * (counter + 1));
+
+ array_cursor = array;
+ for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
+ *array_cursor++ = cursor;
+ *array_cursor = 0;
+
+ qsort (array, counter, sizeof (char *), compare_dirents);
+
+ buffer = xmalloc (cursor - pointer + 2);
+
+ cursor = buffer;
+ for (array_cursor = array; *array_cursor; array_cursor++)
+ {
+ char *string = *array_cursor;
+
+ while ((*cursor++ = *string++))
+ continue;
+ }
+ *cursor = '\0';
+
+ delete_accumulator (accumulator);
+ free (array);
+ return buffer;
+ }
+}
+
+static FILE *listed_incremental_stream;
+
+void
+read_directory_file (void)
+{
+ int fd;
+ FILE *fp;
+ char *buf = 0;
+ size_t bufsize;
+
+ /* Open the file for both read and write. That way, we can write
+ it later without having to reopen it, and don't have to worry if
+ we chdir in the meantime. */
+ fd = open (listed_incremental_option, O_RDWR | O_CREAT, MODE_RW);
+ if (fd < 0)
+ {
+ open_error (listed_incremental_option);
+ return;
+ }
+
+ fp = fdopen (fd, "r+");
+ if (! fp)
+ {
+ open_error (listed_incremental_option);
+ close (fd);
+ return;
+ }
+
+ listed_incremental_stream = fp;
+
+ if (0 < getline (&buf, &bufsize, fp))
+ {
+ char *ebuf;
+ int n;
+ long lineno = 1;
+ unsigned long u = (errno = 0, strtoul (buf, &ebuf, 10));
+ time_t t = u;
+ if (buf == ebuf || (u == 0 && errno == EINVAL))
+ ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option),
+ _("Invalid time stamp")));
+ else if (t != u || (u == -1 && errno == ERANGE))
+ ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option),
+ _("Time stamp out of range")));
+ else
+ newer_mtime_option = t;
+
+ while (0 < (n = getline (&buf, &bufsize, fp)))
+ {
+ dev_t dev;
+ ino_t ino;
+ int nfs = buf[0] == '+';
+ char *strp = buf + nfs;
+
+ lineno++;
+
+ if (buf[n - 1] == '\n')
+ buf[n - 1] = '\0';
+
+ errno = 0;
+ dev = u = strtoul (strp, &ebuf, 10);
+ if (strp == ebuf || (u == 0 && errno == EINVAL))
+ ERROR ((0, 0, "%s:%ld: %s",
+ quotearg_colon (listed_incremental_option), lineno,
+ _("Invalid device number")));
+ else if (dev != u || (u == -1 && errno == ERANGE))
+ ERROR ((0, 0, "%s:%ld: %s",
+ quotearg_colon (listed_incremental_option), lineno,
+ _("Device number out of range")));
+ strp = ebuf;
+
+ errno = 0;
+ ino = u = strtoul (strp, &ebuf, 10);
+ if (strp == ebuf || (u == 0 && errno == EINVAL))
+ ERROR ((0, 0, "%s:%ld: %s",
+ quotearg_colon (listed_incremental_option), lineno,
+ _("Invalid inode number")));
+ else if (ino != u || (u == -1 && errno == ERANGE))
+ ERROR ((0, 0, "%s:%ld: %s",
+ quotearg_colon (listed_incremental_option), lineno,
+ _("Inode number out of range")));
+ strp = ebuf;
+
+ strp++;
+ unquote_string (strp);
+ note_directory (strp, dev, ino, nfs, 0);
+ }
+ }
+
+ if (ferror (fp))
+ read_error (listed_incremental_option);
+ if (buf)
+ free (buf);
+}
+
+/* Output incremental data for the directory ENTRY to the file DATA.
+ Return nonzero if successful, preserving errno on write failure. */
+static bool
+write_directory_file_entry (void *entry, void *data)
+{
+ struct directory const *directory = entry;
+ FILE *fp = data;
+
+ if (directory->found)
+ {
+ int e;
+ char *str = quote_copy_string (directory->name);
+ fprintf (fp, "+%lu %lu %s\n" + ! directory->nfs,
+ (unsigned long) directory->device_number,
+ (unsigned long) directory->inode_number,
+ str ? str : directory->name);
+ e = errno;
+ if (str)
+ free (str);
+ errno = e;
+ }
+
+ return ! ferror (fp);
+}
+
+void
+write_directory_file (void)
+{
+ FILE *fp = listed_incremental_stream;
+
+ if (! fp)
+ return;
+
+ if (fseek (fp, 0L, SEEK_SET) != 0)
+ seek_error (listed_incremental_option);
+ if (ftruncate (fileno (fp), (off_t) 0) != 0)
+ truncate_error (listed_incremental_option);
+
+ fprintf (fp, "%lu\n", (unsigned long) start_time);
+ if (! ferror (fp) && directory_table)
+ hash_do_for_each (directory_table, write_directory_file_entry, fp);
+ if (ferror (fp))
+ write_error (listed_incremental_option);
+ if (fclose (fp) != 0)
+ close_error (listed_incremental_option);
+}
+
+/* Restoration of incremental dumps. */
+
+void
+gnu_restore (size_t skipcrud)
+{
+ char *archive_dir;
+ char *current_dir;
+ char *cur, *arc;
+ size_t size;
+ size_t copied;
+ union block *data_block;
+ char *to;
+
+#define CURRENT_FILE_NAME (skipcrud + current_file_name)
+
+ current_dir = savedir (CURRENT_FILE_NAME);
+
+ if (!current_dir)
+ {
+ /* The directory doesn't exist now. It'll be created. In any
+ case, we don't have to delete any files out of it. */
+
+ skip_member ();
+ return;
+ }
+
+ size = current_stat.st_size;
+ if (size != current_stat.st_size)
+ xalloc_die ();
+ archive_dir = xmalloc (size);
+ to = archive_dir;
+ for (; size > 0; size -= copied)
+ {
+ data_block = find_next_block ();
+ if (!data_block)
+ {
+ ERROR ((0, 0, _("Unexpected EOF in archive")));
+ break; /* FIXME: What happens then? */
+ }
+ copied = available_space_after (data_block);
+ if (copied > size)
+ copied = size;
+ memcpy (to, data_block->buffer, copied);
+ to += copied;
+ set_next_block_after ((union block *)
+ (data_block->buffer + copied - 1));
+ }
+
+ for (cur = current_dir; *cur; cur += strlen (cur) + 1)
+ {
+ for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
+ {
+ arc++;
+ if (!strcmp (arc, cur))
+ break;
+ }
+ if (*arc == '\0')
+ {
+ char *p = new_name (CURRENT_FILE_NAME, cur);
+ if (! interactive_option || confirm ("delete", p))
+ {
+ if (verbose_option)
+ fprintf (stdlis, _("%s: Deleting %s\n"),
+ program_name, quote (p));
+ if (! remove_any_file (p, 1))
+ {
+ int e = errno;
+ ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));
+ }
+ }
+ free (p);
+ }
+
+ }
+ free (current_dir);
+ free (archive_dir);
+
+#undef CURRENT_FILE_NAME
+}
diff --git a/contrib/tar/src/list.c b/contrib/tar/src/list.c
new file mode 100644
index 0000000..e88d53b
--- /dev/null
+++ b/contrib/tar/src/list.c
@@ -0,0 +1,1191 @@
+/* List a tar archive, with support routines for reading a tar archive.
+
+ Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
+ 2001 Free Software Foundation, Inc.
+
+ Written by John Gilmore, on 1985-08-26.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Define to non-zero for forcing old ctime format instead of ISO format. */
+#undef USE_OLD_CTIME
+
+#include "system.h"
+#include <quotearg.h>
+
+#include "common.h"
+
+#define max(a, b) ((a) < (b) ? (b) : (a))
+
+union block *current_header; /* points to current archive header */
+struct stat current_stat; /* stat struct corresponding */
+enum archive_format current_format; /* recognized format */
+union block *recent_long_name; /* recent long name header and contents */
+union block *recent_long_link; /* likewise, for long link */
+size_t recent_long_name_blocks; /* number of blocks in recent_long_name */
+size_t recent_long_link_blocks; /* likewise, for long link */
+
+static uintmax_t from_header PARAMS ((const char *, size_t, const char *,
+ uintmax_t, uintmax_t));
+
+/* Base 64 digits; see Internet RFC 2045 Table 1. */
+static char const base_64_digits[64] =
+{
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+/* Table of base-64 digit values indexed by unsigned chars.
+ The value is 64 for unsigned chars that are not base-64 digits. */
+static char base64_map[UCHAR_MAX + 1];
+
+static void
+base64_init (void)
+{
+ int i;
+ memset (base64_map, 64, sizeof base64_map);
+ for (i = 0; i < 64; i++)
+ base64_map[(int) base_64_digits[i]] = i;
+}
+
+/* Main loop for reading an archive. */
+void
+read_and (void (*do_something) ())
+{
+ enum read_header status = HEADER_STILL_UNREAD;
+ enum read_header prev_status;
+
+ base64_init ();
+ name_gather ();
+ open_archive (ACCESS_READ);
+
+ while (1)
+ {
+ prev_status = status;
+ status = read_header (0);
+ switch (status)
+ {
+ case HEADER_STILL_UNREAD:
+ abort ();
+
+ case HEADER_SUCCESS:
+
+ /* Valid header. We should decode next field (mode) first.
+ Ensure incoming names are null terminated. */
+
+ if (! name_match (current_file_name)
+ || (newer_mtime_option != TYPE_MINIMUM (time_t)
+ /* FIXME: We get mtime now, and again later; this causes
+ duplicate diagnostics if header.mtime is bogus. */
+ && ((current_stat.st_mtime
+ = TIME_FROM_HEADER (current_header->header.mtime))
+ < newer_mtime_option))
+ || excluded_name (current_file_name))
+ {
+ switch (current_header->header.typeflag)
+ {
+ case GNUTYPE_VOLHDR:
+ case GNUTYPE_MULTIVOL:
+ case GNUTYPE_NAMES:
+ break;
+
+ case DIRTYPE:
+ if (show_omitted_dirs_option)
+ WARN ((0, 0, _("%s: Omitting"),
+ quotearg_colon (current_file_name)));
+ /* Fall through. */
+ default:
+ skip_member ();
+ continue;
+ }
+ }
+
+ (*do_something) ();
+ continue;
+
+ case HEADER_ZERO_BLOCK:
+ if (block_number_option)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+ fprintf (stdlis, _("block %s: ** Block of NULs **\n"),
+ STRINGIFY_BIGINT (current_block_ordinal (), buf));
+ }
+
+ set_next_block_after (current_header);
+ status = prev_status;
+ if (ignore_zeros_option)
+ continue;
+ break;
+
+ case HEADER_END_OF_FILE:
+ if (block_number_option)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+ fprintf (stdlis, _("block %s: ** End of File **\n"),
+ STRINGIFY_BIGINT (current_block_ordinal (), buf));
+ }
+ break;
+
+ case HEADER_FAILURE:
+ /* If the previous header was good, tell them that we are
+ skipping bad ones. */
+ set_next_block_after (current_header);
+ switch (prev_status)
+ {
+ case HEADER_STILL_UNREAD:
+ ERROR ((0, 0, _("This does not look like a tar archive")));
+ /* Fall through. */
+
+ case HEADER_ZERO_BLOCK:
+ case HEADER_SUCCESS:
+ ERROR ((0, 0, _("Skipping to next header")));
+ break;
+
+ case HEADER_END_OF_FILE:
+ case HEADER_FAILURE:
+ /* We are in the middle of a cascade of errors. */
+ break;
+ }
+ continue;
+ }
+ break;
+ }
+
+ close_archive ();
+ names_notfound (); /* print names not found */
+}
+
+/* Print a header block, based on tar options. */
+void
+list_archive (void)
+{
+ /* Print the header block. */
+
+ if (verbose_option)
+ {
+ if (verbose_option > 1)
+ decode_header (current_header, &current_stat, &current_format, 0);
+ print_header ();
+ }
+
+ if (incremental_option && current_header->header.typeflag == GNUTYPE_DUMPDIR)
+ {
+ off_t size;
+ size_t written, check;
+ union block *data_block;
+
+ set_next_block_after (current_header);
+ if (multi_volume_option)
+ {
+ assign_string (&save_name, current_file_name);
+ save_totsize = current_stat.st_size;
+ }
+ for (size = current_stat.st_size; size > 0; size -= written)
+ {
+ if (multi_volume_option)
+ save_sizeleft = size;
+ data_block = find_next_block ();
+ if (!data_block)
+ {
+ ERROR ((0, 0, _("Unexpected EOF in archive")));
+ break; /* FIXME: What happens, then? */
+ }
+ written = available_space_after (data_block);
+ if (written > size)
+ written = size;
+ errno = 0;
+ check = fwrite (data_block->buffer, sizeof (char), written, stdlis);
+ set_next_block_after ((union block *)
+ (data_block->buffer + written - 1));
+ if (check != written)
+ {
+ write_error_details (current_file_name, check, written);
+ skip_file (size - written);
+ break;
+ }
+ }
+ if (multi_volume_option)
+ assign_string (&save_name, 0);
+ fputc ('\n', stdlis);
+ fflush (stdlis);
+ return;
+
+ }
+
+ if (multi_volume_option)
+ assign_string (&save_name, current_file_name);
+
+ skip_member ();
+
+ if (multi_volume_option)
+ assign_string (&save_name, 0);
+}
+
+/* Read a block that's supposed to be a header block. Return its
+ address in "current_header", and if it is good, the file's size in
+ current_stat.st_size.
+
+ Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a
+ block full of zeros (EOF marker).
+
+ If RAW_EXTENDED_HEADERS is nonzero, do not automagically fold the
+ GNU long name and link headers into later headers.
+
+ You must always set_next_block_after(current_header) to skip past
+ the header which this routine reads. */
+
+/* The standard BSD tar sources create the checksum by adding up the
+ bytes in the header as type char. I think the type char was unsigned
+ on the PDP-11, but it's signed on the Next and Sun. It looks like the
+ sources to BSD tar were never changed to compute the checksum
+ correctly, so both the Sun and Next add the bytes of the header as
+ signed chars. This doesn't cause a problem until you get a file with
+ a name containing characters with the high bit set. So read_header
+ computes two checksums -- signed and unsigned. */
+
+enum read_header
+read_header (bool raw_extended_headers)
+{
+ size_t i;
+ int unsigned_sum; /* the POSIX one :-) */
+ int signed_sum; /* the Sun one :-( */
+ int recorded_sum;
+ uintmax_t parsed_sum;
+ char *p;
+ union block *header;
+ union block *header_copy;
+ char *bp;
+ union block *data_block;
+ size_t size, written;
+ union block *next_long_name = 0;
+ union block *next_long_link = 0;
+ size_t next_long_name_blocks;
+ size_t next_long_link_blocks;
+
+ while (1)
+ {
+ header = find_next_block ();
+ current_header = header;
+ if (!header)
+ return HEADER_END_OF_FILE;
+
+ unsigned_sum = 0;
+ signed_sum = 0;
+ p = header->buffer;
+ for (i = sizeof *header; i-- != 0;)
+ {
+ unsigned_sum += (unsigned char) *p;
+ signed_sum += (signed char) (*p++);
+ }
+
+ if (unsigned_sum == 0)
+ return HEADER_ZERO_BLOCK;
+
+ /* Adjust checksum to count the "chksum" field as blanks. */
+
+ for (i = sizeof header->header.chksum; i-- != 0;)
+ {
+ unsigned_sum -= (unsigned char) header->header.chksum[i];
+ signed_sum -= (signed char) (header->header.chksum[i]);
+ }
+ unsigned_sum += ' ' * sizeof header->header.chksum;
+ signed_sum += ' ' * sizeof header->header.chksum;
+
+ parsed_sum = from_header (header->header.chksum,
+ sizeof header->header.chksum, 0,
+ (uintmax_t) 0,
+ (uintmax_t) TYPE_MAXIMUM (int));
+ if (parsed_sum == (uintmax_t) -1)
+ return HEADER_FAILURE;
+
+ recorded_sum = parsed_sum;
+
+ if (unsigned_sum != recorded_sum && signed_sum != recorded_sum)
+ return HEADER_FAILURE;
+
+ /* Good block. Decode file size and return. */
+
+ if (header->header.typeflag == LNKTYPE)
+ current_stat.st_size = 0; /* links 0 size on tape */
+ else
+ current_stat.st_size = OFF_FROM_HEADER (header->header.size);
+
+ if (header->header.typeflag == GNUTYPE_LONGNAME
+ || header->header.typeflag == GNUTYPE_LONGLINK)
+ {
+ if (raw_extended_headers)
+ return HEADER_SUCCESS_EXTENDED;
+ else
+ {
+ size_t name_size = current_stat.st_size;
+ size = name_size - name_size % BLOCKSIZE + 2 * BLOCKSIZE;
+ if (name_size != current_stat.st_size || size < name_size)
+ xalloc_die ();
+ }
+
+ header_copy = xmalloc (size + 1);
+
+ if (header->header.typeflag == GNUTYPE_LONGNAME)
+ {
+ if (next_long_name)
+ free (next_long_name);
+ next_long_name = header_copy;
+ next_long_name_blocks = size / BLOCKSIZE;
+ }
+ else
+ {
+ if (next_long_link)
+ free (next_long_link);
+ next_long_link = header_copy;
+ next_long_link_blocks = size / BLOCKSIZE;
+ }
+
+ set_next_block_after (header);
+ *header_copy = *header;
+ bp = header_copy->buffer + BLOCKSIZE;
+
+ for (size -= BLOCKSIZE; size > 0; size -= written)
+ {
+ data_block = find_next_block ();
+ if (! data_block)
+ {
+ ERROR ((0, 0, _("Unexpected EOF in archive")));
+ break;
+ }
+ written = available_space_after (data_block);
+ if (written > size)
+ written = size;
+
+ memcpy (bp, data_block->buffer, written);
+ bp += written;
+ set_next_block_after ((union block *)
+ (data_block->buffer + written - 1));
+ }
+
+ *bp = '\0';
+
+ /* Loop! */
+
+ }
+ else
+ {
+ char const *name;
+ struct posix_header const *h = &current_header->header;
+ char namebuf[sizeof h->prefix + 1 + NAME_FIELD_SIZE + 1];
+
+ if (recent_long_name)
+ free (recent_long_name);
+
+ if (next_long_name)
+ {
+ name = next_long_name->buffer + BLOCKSIZE;
+ recent_long_name = next_long_name;
+ recent_long_name_blocks = next_long_name_blocks;
+ }
+ else
+ {
+ /* Accept file names as specified by POSIX.1-1996
+ section 10.1.1. */
+ char *np = namebuf;
+
+ if (h->prefix[0] && strcmp (h->magic, TMAGIC) == 0)
+ {
+ memcpy (np, h->prefix, sizeof h->prefix);
+ np[sizeof h->prefix] = '\0';
+ np += strlen (np);
+ *np++ = '/';
+
+ /* Prevent later references to current_header from
+ mistakenly treating this as an old GNU header.
+ This assignment invalidates h->prefix. */
+ current_header->oldgnu_header.isextended = 0;
+ }
+ memcpy (np, h->name, sizeof h->name);
+ np[sizeof h->name] = '\0';
+ name = namebuf;
+ recent_long_name = 0;
+ recent_long_name_blocks = 0;
+ }
+ assign_string (&current_file_name, name);
+
+ if (recent_long_link)
+ free (recent_long_link);
+
+ if (next_long_link)
+ {
+ name = next_long_link->buffer + BLOCKSIZE;
+ recent_long_link = next_long_link;
+ recent_long_link_blocks = next_long_link_blocks;
+ }
+ else
+ {
+ memcpy (namebuf, h->linkname, sizeof h->linkname);
+ namebuf[sizeof h->linkname] = '\0';
+ name = namebuf;
+ recent_long_link = 0;
+ recent_long_link_blocks = 0;
+ }
+ assign_string (&current_link_name, name);
+
+ return HEADER_SUCCESS;
+ }
+ }
+}
+
+/* Decode things from a file HEADER block into STAT_INFO, also setting
+ *FORMAT_POINTER depending on the header block format. If
+ DO_USER_GROUP, decode the user/group information (this is useful
+ for extraction, but waste time when merely listing).
+
+ read_header() has already decoded the checksum and length, so we don't.
+
+ This routine should *not* be called twice for the same block, since
+ the two calls might use different DO_USER_GROUP values and thus
+ might end up with different uid/gid for the two calls. If anybody
+ wants the uid/gid they should decode it first, and other callers
+ should decode it without uid/gid before calling a routine,
+ e.g. print_header, that assumes decoded data. */
+void
+decode_header (union block *header, struct stat *stat_info,
+ enum archive_format *format_pointer, int do_user_group)
+{
+ enum archive_format format;
+
+ if (strcmp (header->header.magic, TMAGIC) == 0)
+ format = POSIX_FORMAT;
+ else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0)
+ format = OLDGNU_FORMAT;
+ else
+ format = V7_FORMAT;
+ *format_pointer = format;
+
+ stat_info->st_mode = MODE_FROM_HEADER (header->header.mode);
+ stat_info->st_mtime = TIME_FROM_HEADER (header->header.mtime);
+
+ if (format == OLDGNU_FORMAT && incremental_option)
+ {
+ stat_info->st_atime = TIME_FROM_HEADER (header->oldgnu_header.atime);
+ stat_info->st_ctime = TIME_FROM_HEADER (header->oldgnu_header.ctime);
+ }
+
+ if (format == V7_FORMAT)
+ {
+ stat_info->st_uid = UID_FROM_HEADER (header->header.uid);
+ stat_info->st_gid = GID_FROM_HEADER (header->header.gid);
+ stat_info->st_rdev = 0;
+ }
+ else
+ {
+ if (do_user_group)
+ {
+ /* FIXME: Decide if this should somewhat depend on -p. */
+
+ if (numeric_owner_option
+ || !*header->header.uname
+ || !uname_to_uid (header->header.uname, &stat_info->st_uid))
+ stat_info->st_uid = UID_FROM_HEADER (header->header.uid);
+
+ if (numeric_owner_option
+ || !*header->header.gname
+ || !gname_to_gid (header->header.gname, &stat_info->st_gid))
+ stat_info->st_gid = GID_FROM_HEADER (header->header.gid);
+ }
+ switch (header->header.typeflag)
+ {
+ case BLKTYPE:
+ stat_info->st_rdev
+ = makedev (MAJOR_FROM_HEADER (header->header.devmajor),
+ MINOR_FROM_HEADER (header->header.devminor));
+ break;
+
+ case CHRTYPE:
+ stat_info->st_rdev
+ = makedev (MAJOR_FROM_HEADER (header->header.devmajor),
+ MINOR_FROM_HEADER (header->header.devminor));
+ break;
+
+ default:
+ stat_info->st_rdev = 0;
+ }
+ }
+}
+
+/* Convert buffer at WHERE0 of size DIGS from external format to
+ uintmax_t. The data is of type TYPE. The buffer must represent a
+ value in the range -MINUS_MINVAL through MAXVAL. DIGS must be
+ positive. Return -1 on error, diagnosing the error if TYPE is
+ nonzero. */
+static uintmax_t
+from_header (char const *where0, size_t digs, char const *type,
+ uintmax_t minus_minval, uintmax_t maxval)
+{
+ uintmax_t value;
+ char const *where = where0;
+ char const *lim = where + digs;
+ int negative = 0;
+
+ /* Accommodate buggy tar of unknown vintage, which outputs leading
+ NUL if the previous field overflows. */
+ where += !*where;
+
+ /* Accommodate older tars, which output leading spaces. */
+ for (;;)
+ {
+ if (where == lim)
+ {
+ if (type)
+ ERROR ((0, 0,
+ _("Blanks in header where numeric %s value expected"),
+ type));
+ return -1;
+ }
+ if (!ISSPACE ((unsigned char) *where))
+ break;
+ where++;
+ }
+
+ value = 0;
+ if (ISODIGIT (*where))
+ {
+ char const *where1 = where;
+ uintmax_t overflow = 0;
+
+ for (;;)
+ {
+ value += *where++ - '0';
+ if (where == lim || ! ISODIGIT (*where))
+ break;
+ overflow |= value ^ (value << LG_8 >> LG_8);
+ value <<= LG_8;
+ }
+
+ /* Parse the output of older, unportable tars, which generate
+ negative values in two's complement octal. If the leading
+ nonzero digit is 1, we can't recover the original value
+ reliably; so do this only if the digit is 2 or more. This
+ catches the common case of 32-bit negative time stamps. */
+ if ((overflow || maxval < value) && '2' <= *where1 && type)
+ {
+ /* Compute the negative of the input value, assuming two's
+ complement. */
+ int digit = (*where1 - '0') | 4;
+ overflow = 0;
+ value = 0;
+ where = where1;
+ for (;;)
+ {
+ value += 7 - digit;
+ where++;
+ if (where == lim || ! ISODIGIT (*where))
+ break;
+ digit = *where - '0';
+ overflow |= value ^ (value << LG_8 >> LG_8);
+ value <<= LG_8;
+ }
+ value++;
+ overflow |= !value;
+
+ if (!overflow && value <= minus_minval)
+ {
+ WARN ((0, 0,
+ _("Archive octal value %.*s is out of %s range; assuming two's complement"),
+ (int) (where - where1), where1, type));
+ negative = 1;
+ }
+ }
+
+ if (overflow)
+ {
+ if (type)
+ ERROR ((0, 0,
+ _("Archive octal value %.*s is out of %s range"),
+ (int) (where - where1), where1, type));
+ return -1;
+ }
+ }
+ else if (*where == '-' || *where == '+')
+ {
+ /* Parse base-64 output produced only by tar test versions
+ 1.13.6 (1999-08-11) through 1.13.11 (1999-08-23).
+ Support for this will be withdrawn in future releases. */
+ int dig;
+ static int warned_once;
+ if (! warned_once)
+ {
+ warned_once = 1;
+ WARN ((0, 0,
+ _("Archive contains obsolescent base-64 headers")));
+ }
+ negative = *where++ == '-';
+ while (where != lim
+ && (dig = base64_map[(unsigned char) *where]) < 64)
+ {
+ if (value << LG_64 >> LG_64 != value)
+ {
+ char *string = alloca (digs + 1);
+ memcpy (string, where0, digs);
+ string[digs] = '\0';
+ if (type)
+ ERROR ((0, 0,
+ _("Archive signed base-64 string %s is out of %s range"),
+ quote (string), type));
+ return -1;
+ }
+ value = (value << LG_64) | dig;
+ where++;
+ }
+ }
+ else if (*where == '\200' /* positive base-256 */
+ || *where == '\377' /* negative base-256 */)
+ {
+ /* Parse base-256 output. A nonnegative number N is
+ represented as (256**DIGS)/2 + N; a negative number -N is
+ represented as (256**DIGS) - N, i.e. as two's complement.
+ The representation guarantees that the leading bit is
+ always on, so that we don't confuse this format with the
+ others (assuming ASCII bytes of 8 bits or more). */
+ int signbit = *where & (1 << (LG_256 - 2));
+ uintmax_t topbits = (((uintmax_t) - signbit)
+ << (CHAR_BIT * sizeof (uintmax_t)
+ - LG_256 - (LG_256 - 2)));
+ value = (*where++ & ((1 << (LG_256 - 2)) - 1)) - signbit;
+ for (;;)
+ {
+ value = (value << LG_256) + (unsigned char) *where++;
+ if (where == lim)
+ break;
+ if (((value << LG_256 >> LG_256) | topbits) != value)
+ {
+ if (type)
+ ERROR ((0, 0,
+ _("Archive base-256 value is out of %s range"),
+ type));
+ return -1;
+ }
+ }
+ negative = signbit;
+ if (negative)
+ value = -value;
+ }
+
+ if (where != lim && *where && !ISSPACE ((unsigned char) *where))
+ {
+ if (type)
+ {
+ char buf[1000]; /* Big enough to represent any header. */
+ static struct quoting_options *o;
+
+ if (!o)
+ {
+ o = clone_quoting_options (0);
+ set_quoting_style (o, locale_quoting_style);
+ }
+
+ while (where0 != lim && ! lim[-1])
+ lim--;
+ quotearg_buffer (buf, sizeof buf, where0, lim - where, o);
+ ERROR ((0, 0,
+ _("Archive contains %.*s where numeric %s value expected"),
+ (int) sizeof buf, buf, type));
+ }
+
+ return -1;
+ }
+
+ if (value <= (negative ? minus_minval : maxval))
+ return negative ? -value : value;
+
+ if (type)
+ {
+ char minval_buf[UINTMAX_STRSIZE_BOUND + 1];
+ char maxval_buf[UINTMAX_STRSIZE_BOUND];
+ char value_buf[UINTMAX_STRSIZE_BOUND + 1];
+ char *minval_string = STRINGIFY_BIGINT (minus_minval, minval_buf + 1);
+ char *value_string = STRINGIFY_BIGINT (value, value_buf + 1);
+ if (negative)
+ *--value_string = '-';
+ if (minus_minval)
+ *--minval_string = '-';
+ ERROR ((0, 0, _("Archive value %s is out of %s range %s..%s"),
+ value_string, type,
+ minval_string, STRINGIFY_BIGINT (maxval, maxval_buf)));
+ }
+
+ return -1;
+}
+
+gid_t
+gid_from_header (const char *p, size_t s)
+{
+ return from_header (p, s, "gid_t",
+ - (uintmax_t) TYPE_MINIMUM (gid_t),
+ (uintmax_t) TYPE_MAXIMUM (gid_t));
+}
+
+major_t
+major_from_header (const char *p, size_t s)
+{
+ return from_header (p, s, "major_t",
+ - (uintmax_t) TYPE_MINIMUM (major_t),
+ (uintmax_t) TYPE_MAXIMUM (major_t));
+}
+
+minor_t
+minor_from_header (const char *p, size_t s)
+{
+ return from_header (p, s, "minor_t",
+ - (uintmax_t) TYPE_MINIMUM (minor_t),
+ (uintmax_t) TYPE_MAXIMUM (minor_t));
+}
+
+mode_t
+mode_from_header (const char *p, size_t s)
+{
+ /* Do not complain about unrecognized mode bits. */
+ unsigned u = from_header (p, s, "mode_t",
+ - (uintmax_t) TYPE_MINIMUM (mode_t),
+ TYPE_MAXIMUM (uintmax_t));
+ return ((u & TSUID ? S_ISUID : 0)
+ | (u & TSGID ? S_ISGID : 0)
+ | (u & TSVTX ? S_ISVTX : 0)
+ | (u & TUREAD ? S_IRUSR : 0)
+ | (u & TUWRITE ? S_IWUSR : 0)
+ | (u & TUEXEC ? S_IXUSR : 0)
+ | (u & TGREAD ? S_IRGRP : 0)
+ | (u & TGWRITE ? S_IWGRP : 0)
+ | (u & TGEXEC ? S_IXGRP : 0)
+ | (u & TOREAD ? S_IROTH : 0)
+ | (u & TOWRITE ? S_IWOTH : 0)
+ | (u & TOEXEC ? S_IXOTH : 0));
+}
+
+off_t
+off_from_header (const char *p, size_t s)
+{
+ /* Negative offsets are not allowed in tar files, so invoke
+ from_header with minimum value 0, not TYPE_MINIMUM (off_t). */
+ return from_header (p, s, "off_t", (uintmax_t) 0,
+ (uintmax_t) TYPE_MAXIMUM (off_t));
+}
+
+size_t
+size_from_header (const char *p, size_t s)
+{
+ return from_header (p, s, "size_t", (uintmax_t) 0,
+ (uintmax_t) TYPE_MAXIMUM (size_t));
+}
+
+time_t
+time_from_header (const char *p, size_t s)
+{
+ return from_header (p, s, "time_t",
+ - (uintmax_t) TYPE_MINIMUM (time_t),
+ (uintmax_t) TYPE_MAXIMUM (time_t));
+}
+
+uid_t
+uid_from_header (const char *p, size_t s)
+{
+ return from_header (p, s, "uid_t",
+ - (uintmax_t) TYPE_MINIMUM (uid_t),
+ (uintmax_t) TYPE_MAXIMUM (uid_t));
+}
+
+uintmax_t
+uintmax_from_header (const char *p, size_t s)
+{
+ return from_header (p, s, "uintmax_t", (uintmax_t) 0,
+ TYPE_MAXIMUM (uintmax_t));
+}
+
+
+/* Format O as a null-terminated decimal string into BUF _backwards_;
+ return pointer to start of result. */
+char *
+stringify_uintmax_t_backwards (uintmax_t o, char *buf)
+{
+ *--buf = '\0';
+ do
+ *--buf = '0' + (int) (o % 10);
+ while ((o /= 10) != 0);
+ return buf;
+}
+
+/* Return a printable representation of T. The result points to
+ static storage that can be reused in the next call to this
+ function, to ctime, or to asctime. */
+char const *
+tartime (time_t t)
+{
+ static char buffer[max (UINTMAX_STRSIZE_BOUND + 1,
+ INT_STRLEN_BOUND (int) + 16)];
+ char *p;
+
+#if USE_OLD_CTIME
+ p = ctime (&t);
+ if (p)
+ {
+ char const *time_stamp = p + 4;
+ for (p += 16; p[3] != '\n'; p++)
+ p[0] = p[3];
+ p[0] = '\0';
+ return time_stamp;
+ }
+#else
+ /* Use ISO 8610 format. See:
+ http://www.cl.cam.ac.uk/~mgk25/iso-time.html */
+ struct tm *tm = localtime (&t);
+ if (tm)
+ {
+ sprintf (buffer, "%04d-%02d-%02d %02d:%02d:%02d",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ return buffer;
+ }
+#endif
+
+ /* The time stamp cannot be broken down, most likely because it
+ is out of range. Convert it as an integer,
+ right-adjusted in a field with the same width as the usual
+ 19-byte 4-year ISO time format. */
+ p = stringify_uintmax_t_backwards (t < 0 ? - (uintmax_t) t : (uintmax_t) t,
+ buffer + sizeof buffer);
+ if (t < 0)
+ *--p = '-';
+ while (buffer + sizeof buffer - 19 - 1 < p)
+ *--p = ' ';
+ return p;
+}
+
+/* Actually print it.
+
+ Plain and fancy file header block logging. Non-verbose just prints
+ the name, e.g. for "tar t" or "tar x". This should just contain
+ file names, so it can be fed back into tar with xargs or the "-T"
+ option. The verbose option can give a bunch of info, one line per
+ file. I doubt anybody tries to parse its format, or if they do,
+ they shouldn't. Unix tar is pretty random here anyway. */
+
+
+/* FIXME: Note that print_header uses the globals HEAD, HSTAT, and
+ HEAD_STANDARD, which must be set up in advance. Not very clean... */
+
+/* UGSWIDTH starts with 18, so with user and group names <= 8 chars, the
+ columns never shift during the listing. */
+#define UGSWIDTH 18
+static int ugswidth = UGSWIDTH; /* maximum width encountered so far */
+
+/* DATEWIDTH is the number of columns taken by the date and time fields. */
+#if USE_OLD_CDATE
+# define DATEWIDTH 19
+#else
+# define DATEWIDTH 18
+#endif
+
+void
+print_header (void)
+{
+ char modes[11];
+ char const *time_stamp;
+ /* These hold formatted ints. */
+ char uform[UINTMAX_STRSIZE_BOUND], gform[UINTMAX_STRSIZE_BOUND];
+ char *user, *group;
+ char size[2 * UINTMAX_STRSIZE_BOUND];
+ /* holds formatted size or major,minor */
+ char uintbuf[UINTMAX_STRSIZE_BOUND];
+ int pad;
+
+ if (block_number_option)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+ fprintf (stdlis, _("block %s: "),
+ STRINGIFY_BIGINT (current_block_ordinal (), buf));
+ }
+
+ if (verbose_option <= 1)
+ {
+ /* Just the fax, mam. */
+ fprintf (stdlis, "%s\n", quotearg (current_file_name));
+ }
+ else
+ {
+ /* File type and modes. */
+
+ modes[0] = '?';
+ switch (current_header->header.typeflag)
+ {
+ case GNUTYPE_VOLHDR:
+ modes[0] = 'V';
+ break;
+
+ case GNUTYPE_MULTIVOL:
+ modes[0] = 'M';
+ break;
+
+ case GNUTYPE_NAMES:
+ modes[0] = 'N';
+ break;
+
+ case GNUTYPE_LONGNAME:
+ case GNUTYPE_LONGLINK:
+ ERROR ((0, 0, _("Visible longname error")));
+ break;
+
+ case GNUTYPE_SPARSE:
+ case REGTYPE:
+ case AREGTYPE:
+ case LNKTYPE:
+ modes[0] = '-';
+ if (current_file_name[strlen (current_file_name) - 1] == '/')
+ modes[0] = 'd';
+ break;
+ case GNUTYPE_DUMPDIR:
+ modes[0] = 'd';
+ break;
+ case DIRTYPE:
+ modes[0] = 'd';
+ break;
+ case SYMTYPE:
+ modes[0] = 'l';
+ break;
+ case BLKTYPE:
+ modes[0] = 'b';
+ break;
+ case CHRTYPE:
+ modes[0] = 'c';
+ break;
+ case FIFOTYPE:
+ modes[0] = 'p';
+ break;
+ case CONTTYPE:
+ modes[0] = 'C';
+ break;
+ }
+
+ decode_mode (current_stat.st_mode, modes + 1);
+
+ /* Time stamp. */
+
+ time_stamp = tartime (current_stat.st_mtime);
+
+ /* User and group names. */
+
+ if (*current_header->header.uname && current_format != V7_FORMAT
+ && !numeric_owner_option)
+ user = current_header->header.uname;
+ else
+ {
+ /* Try parsing it as an unsigned integer first, and as a
+ uid_t if that fails. This method can list positive user
+ ids that are too large to fit in a uid_t. */
+ uintmax_t u = from_header (current_header->header.uid,
+ sizeof current_header->header.uid, 0,
+ (uintmax_t) 0,
+ (uintmax_t) TYPE_MAXIMUM (uintmax_t));
+ if (u != -1)
+ user = STRINGIFY_BIGINT (u, uform);
+ else
+ {
+ sprintf (uform, "%ld",
+ (long) UID_FROM_HEADER (current_header->header.uid));
+ user = uform;
+ }
+ }
+
+ if (*current_header->header.gname && current_format != V7_FORMAT
+ && !numeric_owner_option)
+ group = current_header->header.gname;
+ else
+ {
+ /* Try parsing it as an unsigned integer first, and as a
+ gid_t if that fails. This method can list positive group
+ ids that are too large to fit in a gid_t. */
+ uintmax_t g = from_header (current_header->header.gid,
+ sizeof current_header->header.gid, 0,
+ (uintmax_t) 0,
+ (uintmax_t) TYPE_MAXIMUM (uintmax_t));
+ if (g != -1)
+ group = STRINGIFY_BIGINT (g, gform);
+ else
+ {
+ sprintf (gform, "%ld",
+ (long) GID_FROM_HEADER (current_header->header.gid));
+ group = gform;
+ }
+ }
+
+ /* Format the file size or major/minor device numbers. */
+
+ switch (current_header->header.typeflag)
+ {
+ case CHRTYPE:
+ case BLKTYPE:
+ strcpy (size,
+ STRINGIFY_BIGINT (major (current_stat.st_rdev), uintbuf));
+ strcat (size, ",");
+ strcat (size,
+ STRINGIFY_BIGINT (minor (current_stat.st_rdev), uintbuf));
+ break;
+ case GNUTYPE_SPARSE:
+ strcpy (size,
+ STRINGIFY_BIGINT
+ (UINTMAX_FROM_HEADER (current_header
+ ->oldgnu_header.realsize),
+ uintbuf));
+ break;
+ default:
+ strcpy (size, STRINGIFY_BIGINT (current_stat.st_size, uintbuf));
+ break;
+ }
+
+ /* Figure out padding and print the whole line. */
+
+ pad = strlen (user) + strlen (group) + strlen (size) + 1;
+ if (pad > ugswidth)
+ ugswidth = pad;
+
+ fprintf (stdlis, "%s %s/%s %*s%s %s",
+ modes, user, group, ugswidth - pad, "", size, time_stamp);
+
+ fprintf (stdlis, " %s", quotearg (current_file_name));
+
+ switch (current_header->header.typeflag)
+ {
+ case SYMTYPE:
+ fprintf (stdlis, " -> %s\n", quotearg (current_link_name));
+ break;
+
+ case LNKTYPE:
+ fprintf (stdlis, _(" link to %s\n"), quotearg (current_link_name));
+ break;
+
+ default:
+ {
+ char type_string[2];
+ type_string[0] = current_header->header.typeflag;
+ type_string[1] = '\0';
+ fprintf (stdlis, _(" unknown file type %s\n"),
+ quote (type_string));
+ }
+ break;
+
+ case AREGTYPE:
+ case REGTYPE:
+ case GNUTYPE_SPARSE:
+ case CHRTYPE:
+ case BLKTYPE:
+ case DIRTYPE:
+ case FIFOTYPE:
+ case CONTTYPE:
+ case GNUTYPE_DUMPDIR:
+ putc ('\n', stdlis);
+ break;
+
+ case GNUTYPE_VOLHDR:
+ fprintf (stdlis, _("--Volume Header--\n"));
+ break;
+
+ case GNUTYPE_MULTIVOL:
+ strcpy (size,
+ STRINGIFY_BIGINT
+ (UINTMAX_FROM_HEADER (current_header->oldgnu_header.offset),
+ uintbuf));
+ fprintf (stdlis, _("--Continued at byte %s--\n"), size);
+ break;
+
+ case GNUTYPE_NAMES:
+ fprintf (stdlis, _("--Mangled file names--\n"));
+ break;
+ }
+ }
+ fflush (stdlis);
+}
+
+/* Print a similar line when we make a directory automatically. */
+void
+print_for_mkdir (char *pathname, int length, mode_t mode)
+{
+ char modes[11];
+
+ if (verbose_option > 1)
+ {
+ /* File type and modes. */
+
+ modes[0] = 'd';
+ decode_mode (mode, modes + 1);
+
+ if (block_number_option)
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+ fprintf (stdlis, _("block %s: "),
+ STRINGIFY_BIGINT (current_block_ordinal (), buf));
+ }
+
+ fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
+ _("Creating directory:"), length, quotearg (pathname));
+ }
+}
+
+/* Skip over SIZE bytes of data in blocks in the archive. */
+void
+skip_file (off_t size)
+{
+ union block *x;
+
+ if (multi_volume_option)
+ {
+ save_totsize = size;
+ save_sizeleft = size;
+ }
+
+ while (size > 0)
+ {
+ x = find_next_block ();
+ if (! x)
+ FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
+
+ set_next_block_after (x);
+ size -= BLOCKSIZE;
+ if (multi_volume_option)
+ save_sizeleft -= BLOCKSIZE;
+ }
+}
+
+/* Skip the current member in the archive. */
+void
+skip_member (void)
+{
+ char save_typeflag = current_header->header.typeflag;
+ set_next_block_after (current_header);
+
+ if (current_header->oldgnu_header.isextended)
+ {
+ union block *exhdr;
+ do
+ {
+ exhdr = find_next_block ();
+ if (!exhdr)
+ FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
+ set_next_block_after (exhdr);
+ }
+ while (exhdr->sparse_header.isextended);
+ }
+
+ if (save_typeflag != DIRTYPE)
+ skip_file (current_stat.st_size);
+}
diff --git a/contrib/tar/src/mangle.c b/contrib/tar/src/mangle.c
new file mode 100644
index 0000000..204bf7c
--- /dev/null
+++ b/contrib/tar/src/mangle.c
@@ -0,0 +1,121 @@
+/* Encode long filenames for GNU tar.
+ Copyright 1988, 92, 94, 96, 97, 99, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include "common.h"
+#include <quotearg.h>
+
+struct mangled
+ {
+ struct mangled *next;
+ int type;
+ char mangled[NAME_FIELD_SIZE];
+ char *linked_to;
+ char normal[1];
+ };
+
+/* Extract a GNUTYPE_NAMES record contents. It seems that such are
+ not produced anymore by GNU tar, but we leave the reading code
+ around nevertheless, for salvaging old tapes. */
+void
+extract_mangle (void)
+{
+ off_t size = current_stat.st_size;
+ char *buffer = xmalloc ((size_t) (size + 1));
+ char *copy = buffer;
+ char *cursor = buffer;
+
+ if (size != (size_t) size || size == (size_t) -1)
+ xalloc_die ();
+
+ buffer[size] = '\0';
+
+ while (size > 0)
+ {
+ union block *block = find_next_block ();
+ size_t available;
+
+ if (!block)
+ {
+ ERROR ((0, 0, _("Unexpected EOF in mangled names")));
+ return;
+ }
+ available = available_space_after (block);
+ if (available > size)
+ available = size;
+ memcpy (copy, block->buffer, available);
+ copy += available;
+ size -= available;
+ set_next_block_after ((union block *) (block->buffer + available - 1));
+ }
+
+ while (*cursor)
+ {
+ char *next_cursor;
+ char *name;
+ char *name_end;
+
+ next_cursor = strchr (cursor, '\n');
+ *next_cursor++ = '\0';
+
+ if (!strncmp (cursor, "Rename ", 7))
+ {
+
+ name = cursor + 7;
+ name_end = strchr (name, ' ');
+ while (strncmp (name_end, " to ", 4))
+ {
+ name_end++;
+ name_end = strchr (name_end, ' ');
+ }
+ *name_end = '\0';
+ if (next_cursor[-2] == '/')
+ next_cursor[-2] = '\0';
+ unquote_string (name_end + 4);
+ if (rename (name, name_end + 4))
+ ERROR ((0, errno, _("%s: Cannot rename to %s"),
+ quotearg_colon (name), quote_n (1, name_end + 4)));
+ else if (verbose_option)
+ WARN ((0, 0, _("Renamed %s to %s"), name, name_end + 4));
+ }
+#ifdef HAVE_SYMLINK
+ else if (!strncmp (cursor, "Symlink ", 8))
+ {
+ name = cursor + 8;
+ name_end = strchr (name, ' ');
+ while (strncmp (name_end, " to ", 4))
+ {
+ name_end++;
+ name_end = strchr (name_end, ' ');
+ }
+ *name_end = '\0';
+ unquote_string (name);
+ unquote_string (name_end + 4);
+ if (symlink (name, name_end + 4)
+ && (unlink (name_end + 4) || symlink (name, name_end + 4)))
+ ERROR ((0, errno, _("%s: Cannot symlink to %s"),
+ quotearg_colon (name), quote_n (1, name_end + 4)));
+ else if (verbose_option)
+ WARN ((0, 0, _("Symlinked %s to %s"), name, name_end + 4));
+ }
+#endif
+ else
+ ERROR ((0, 0, _("Unknown demangling command %s"), cursor));
+
+ cursor = next_cursor;
+ }
+}
diff --git a/contrib/tar/src/misc.c b/contrib/tar/src/misc.c
new file mode 100644
index 0000000..e90c248
--- /dev/null
+++ b/contrib/tar/src/misc.c
@@ -0,0 +1,847 @@
+/* Miscellaneous functions, not really specific to GNU tar.
+
+ Copyright 1988, 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001 Free
+ Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include "rmt.h"
+#include "common.h"
+#include <quotearg.h>
+#include <save-cwd.h>
+
+static void call_arg_fatal PARAMS ((char const *, char const *))
+ __attribute__ ((noreturn));
+
+/* Handling strings. */
+
+/* Assign STRING to a copy of VALUE if not zero, or to zero. If
+ STRING was nonzero, it is freed first. */
+void
+assign_string (char **string, const char *value)
+{
+ if (*string)
+ free (*string);
+ *string = value ? xstrdup (value) : 0;
+}
+
+/* Allocate a copy of the string quoted as in C, and returns that. If
+ the string does not have to be quoted, it returns a null pointer.
+ The allocated copy should normally be freed with free() after the
+ caller is done with it.
+
+ This is used in one context only: generating the directory file in
+ incremental dumps. The quoted string is not intended for human
+ consumption; it is intended only for unquote_string. The quoting
+ is locale-independent, so that users needn't worry about locale
+ when reading directory files. This means that we can't use
+ quotearg, as quotearg is locale-dependent and is meant for human
+ consumption. */
+char *
+quote_copy_string (const char *string)
+{
+ const char *source = string;
+ char *destination = 0;
+ char *buffer = 0;
+ int copying = 0;
+
+ while (*source)
+ {
+ int character = *source++;
+
+ switch (character)
+ {
+ case '\n': case '\\':
+ if (!copying)
+ {
+ size_t length = (source - string) - 1;
+
+ copying = 1;
+ buffer = xmalloc (length + 2 + 2 * strlen (source) + 1);
+ memcpy (buffer, string, length);
+ destination = buffer + length;
+ }
+ *destination++ = '\\';
+ *destination++ = character == '\\' ? '\\' : 'n';
+ break;
+
+ default:
+ if (copying)
+ *destination++ = character;
+ break;
+ }
+ }
+ if (copying)
+ {
+ *destination = '\0';
+ return buffer;
+ }
+ return 0;
+}
+
+/* Takes a quoted C string (like those produced by quote_copy_string)
+ and turns it back into the un-quoted original. This is done in
+ place. Returns 0 only if the string was not properly quoted, but
+ completes the unquoting anyway.
+
+ This is used for reading the saved directory file in incremental
+ dumps. It is used for decoding old `N' records (demangling names).
+ But also, it is used for decoding file arguments, would they come
+ from the shell or a -T file, and for decoding the --exclude
+ argument. */
+int
+unquote_string (char *string)
+{
+ int result = 1;
+ char *source = string;
+ char *destination = string;
+
+ /* Escape sequences other than \\ and \n are no longer generated by
+ quote_copy_string, but accept them for backwards compatibility,
+ and also because unquote_string is used for purposes other than
+ parsing the output of quote_copy_string. */
+
+ while (*source)
+ if (*source == '\\')
+ switch (*++source)
+ {
+ case '\\':
+ *destination++ = '\\';
+ source++;
+ break;
+
+ case 'n':
+ *destination++ = '\n';
+ source++;
+ break;
+
+ case 't':
+ *destination++ = '\t';
+ source++;
+ break;
+
+ case 'f':
+ *destination++ = '\f';
+ source++;
+ break;
+
+ case 'b':
+ *destination++ = '\b';
+ source++;
+ break;
+
+ case 'r':
+ *destination++ = '\r';
+ source++;
+ break;
+
+ case '?':
+ *destination++ = 0177;
+ source++;
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int value = *source++ - '0';
+
+ if (*source < '0' || *source > '7')
+ {
+ *destination++ = value;
+ break;
+ }
+ value = value * 8 + *source++ - '0';
+ if (*source < '0' || *source > '7')
+ {
+ *destination++ = value;
+ break;
+ }
+ value = value * 8 + *source++ - '0';
+ *destination++ = value;
+ break;
+ }
+
+ default:
+ result = 0;
+ *destination++ = '\\';
+ if (*source)
+ *destination++ = *source++;
+ break;
+ }
+ else if (source != destination)
+ *destination++ = *source++;
+ else
+ source++, destination++;
+
+ if (source != destination)
+ *destination = '\0';
+ return result;
+}
+
+/* Return nonzero if NAME contains ".." as a path name component. */
+int
+contains_dot_dot (char const *name)
+{
+ char const *p = name + FILESYSTEM_PREFIX_LEN (name);
+
+ for (;;)
+ {
+ if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
+ return 1;
+
+ do
+ {
+ if (! *p++)
+ return 0;
+ }
+ while (! ISSLASH (*p));
+ }
+}
+
+/* File handling. */
+
+/* Saved names in case backup needs to be undone. */
+static char *before_backup_name;
+static char *after_backup_name;
+
+/* Some implementations of rmdir let you remove the working directory.
+ Report an error with errno set to zero for obvious cases of this;
+ otherwise call rmdir. */
+static int
+safer_rmdir (const char *path)
+{
+ while (path[0] == '.' && ISSLASH (path[1]))
+ {
+ path++;
+
+ do path++;
+ while (ISSLASH (*path));
+ }
+
+ if (! path[0] || (path[0] == '.' && ! path[1]))
+ {
+ errno = 0;
+ return -1;
+ }
+
+ return rmdir (path);
+}
+
+/* Remove PATH. If PATH is a directory, then if RECURSE is set remove
+ it recursively; otherwise, remove it only if it is empty. Return 0
+ on error, with errno set; if PATH is obviously the working
+ directory return zero with errno set to zero. */
+int
+remove_any_file (const char *path, int recurse)
+{
+ /* Try unlink first if we are not root, as this saves us a system
+ call in the common case where we're removing a non-directory. */
+ if (! we_are_root)
+ {
+ if (unlink (path) == 0)
+ return 1;
+ if (errno != EPERM)
+ return 0;
+ }
+
+ if (safer_rmdir (path) == 0)
+ return 1;
+
+ switch (errno)
+ {
+ case ENOTDIR:
+ return we_are_root && unlink (path) == 0;
+
+ case 0:
+ case EEXIST:
+#if defined ENOTEMPTY && ENOTEMPTY != EEXIST
+ case ENOTEMPTY:
+#endif
+ if (recurse)
+ {
+ char *directory = savedir (path);
+ char const *entry;
+ size_t entrylen;
+
+ if (! directory)
+ return 0;
+
+ for (entry = directory;
+ (entrylen = strlen (entry)) != 0;
+ entry += entrylen + 1)
+ {
+ char *path_buffer = new_name (path, entry);
+ int r = remove_any_file (path_buffer, 1);
+ int e = errno;
+ free (path_buffer);
+
+ if (! r)
+ {
+ free (directory);
+ errno = e;
+ return 0;
+ }
+ }
+
+ free (directory);
+ return safer_rmdir (path) == 0;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/* Check if PATH already exists and make a backup of it right now.
+ Return success (nonzero) only if the backup in either unneeded, or
+ successful. For now, directories are considered to never need
+ backup. If ARCHIVE is nonzero, this is the archive and so, we do
+ not have to backup block or character devices, nor remote entities. */
+int
+maybe_backup_file (const char *path, int archive)
+{
+ struct stat file_stat;
+
+ /* Check if we really need to backup the file. */
+
+ if (archive && _remdev (path))
+ return 1;
+
+ if (stat (path, &file_stat))
+ {
+ if (errno == ENOENT)
+ return 1;
+
+ stat_error (path);
+ return 0;
+ }
+
+ if (S_ISDIR (file_stat.st_mode))
+ return 1;
+
+ if (archive && (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode)))
+ return 1;
+
+ assign_string (&before_backup_name, path);
+
+ /* A run situation may exist between Emacs or other GNU programs trying to
+ make a backup for the same file simultaneously. If theoretically
+ possible, real problems are unlikely. Doing any better would require a
+ convention, GNU-wide, for all programs doing backups. */
+
+ assign_string (&after_backup_name, 0);
+ after_backup_name = find_backup_file_name (path, backup_type);
+ if (! after_backup_name)
+ xalloc_die ();
+
+ if (rename (before_backup_name, after_backup_name) == 0)
+ {
+ if (verbose_option)
+ fprintf (stdlis, _("Renaming %s to %s\n"),
+ quote_n (0, before_backup_name),
+ quote_n (1, after_backup_name));
+ return 1;
+ }
+ else
+ {
+ /* The backup operation failed. */
+ int e = errno;
+ ERROR ((0, e, _("%s: Cannot rename to %s"),
+ quotearg_colon (before_backup_name),
+ quote_n (1, after_backup_name)));
+ assign_string (&after_backup_name, 0);
+ return 0;
+ }
+}
+
+/* Try to restore the recently backed up file to its original name.
+ This is usually only needed after a failed extraction. */
+void
+undo_last_backup (void)
+{
+ if (after_backup_name)
+ {
+ if (rename (after_backup_name, before_backup_name) != 0)
+ {
+ int e = errno;
+ ERROR ((0, e, _("%s: Cannot rename to %s"),
+ quotearg_colon (after_backup_name),
+ quote_n (1, before_backup_name)));
+ }
+ if (verbose_option)
+ fprintf (stdlis, _("Renaming %s back to %s\n"),
+ quote_n (0, after_backup_name),
+ quote_n (1, before_backup_name));
+ assign_string (&after_backup_name, 0);
+ }
+}
+
+/* Depending on DEREF, apply either stat or lstat to (NAME, BUF). */
+int
+deref_stat (int deref, char const *name, struct stat *buf)
+{
+ return deref ? stat (name, buf) : lstat (name, buf);
+}
+
+/* A description of a working directory. */
+struct wd
+{
+ char const *name;
+ int saved;
+ struct saved_cwd saved_cwd;
+};
+
+/* A vector of chdir targets. wd[0] is the initial working directory. */
+static struct wd *wd;
+
+/* The number of working directories in the vector. */
+static size_t wds;
+
+/* The allocated size of the vector. */
+static size_t wd_alloc;
+
+/* DIR is the operand of a -C option; add it to vector of chdir targets,
+ and return the index of its location. */
+int
+chdir_arg (char const *dir)
+{
+ if (wds == wd_alloc)
+ {
+ wd_alloc = 2 * (wd_alloc + 1);
+ wd = xrealloc (wd, sizeof *wd * wd_alloc);
+ if (! wds)
+ {
+ wd[wds].name = ".";
+ wd[wds].saved = 0;
+ wds++;
+ }
+ }
+
+ /* Optimize the common special case of the working directory,
+ or the working directory as a prefix. */
+ if (dir[0])
+ {
+ while (dir[0] == '.' && ISSLASH (dir[1]))
+ for (dir += 2; ISSLASH (*dir); dir++)
+ continue;
+ if (! dir[dir[0] == '.'])
+ return wds - 1;
+ }
+
+ wd[wds].name = dir;
+ wd[wds].saved = 0;
+ return wds++;
+}
+
+/* Change to directory I. If I is 0, change to the initial working
+ directory; otherwise, I must be a value returned by chdir_arg. */
+void
+chdir_do (int i)
+{
+ static int previous;
+
+ if (previous != i)
+ {
+ struct wd *prev = &wd[previous];
+ struct wd *curr = &wd[i];
+
+ if (! prev->saved)
+ {
+ prev->saved = 1;
+ if (save_cwd (&prev->saved_cwd) != 0)
+ FATAL_ERROR ((0, 0, _("Cannot save working directory")));
+ }
+
+ if (curr->saved)
+ {
+ if (restore_cwd (&curr->saved_cwd, curr->name, prev->name))
+ FATAL_ERROR ((0, 0, _("Cannot change working directory")));
+ }
+ else
+ {
+ if (i && ! ISSLASH (curr->name[0]))
+ chdir_do (i - 1);
+ if (chdir (curr->name) != 0)
+ chdir_fatal (curr->name);
+ }
+
+ previous = i;
+ }
+}
+
+/* Decode MODE from its binary form in a stat structure, and encode it
+ into a 9-byte string STRING, terminated with a NUL. */
+
+void
+decode_mode (mode_t mode, char *string)
+{
+ *string++ = mode & S_IRUSR ? 'r' : '-';
+ *string++ = mode & S_IWUSR ? 'w' : '-';
+ *string++ = (mode & S_ISUID
+ ? (mode & S_IXUSR ? 's' : 'S')
+ : (mode & S_IXUSR ? 'x' : '-'));
+ *string++ = mode & S_IRGRP ? 'r' : '-';
+ *string++ = mode & S_IWGRP ? 'w' : '-';
+ *string++ = (mode & S_ISGID
+ ? (mode & S_IXGRP ? 's' : 'S')
+ : (mode & S_IXGRP ? 'x' : '-'));
+ *string++ = mode & S_IROTH ? 'r' : '-';
+ *string++ = mode & S_IWOTH ? 'w' : '-';
+ *string++ = (mode & S_ISVTX
+ ? (mode & S_IXOTH ? 't' : 'T')
+ : (mode & S_IXOTH ? 'x' : '-'));
+ *string = '\0';
+}
+
+/* Report an error associated with the system call CALL and the
+ optional name NAME. */
+static void
+call_arg_error (char const *call, char const *name)
+{
+ int e = errno;
+ ERROR ((0, e, _("%s: Cannot %s"), quotearg_colon (name), call));
+}
+
+/* Report a fatal error associated with the system call CALL and
+ the optional file name NAME. */
+static void
+call_arg_fatal (char const *call, char const *name)
+{
+ int e = errno;
+ FATAL_ERROR ((0, e, _("%s: Cannot %s"), quotearg_colon (name), call));
+}
+
+/* Report a warning associated with the system call CALL and
+ the optional file name NAME. */
+static void
+call_arg_warn (char const *call, char const *name)
+{
+ int e = errno;
+ WARN ((0, e, _("%s: Warning: Cannot %s"), quotearg_colon (name), call));
+}
+
+void
+chdir_fatal (char const *name)
+{
+ call_arg_fatal ("chdir", name);
+}
+
+void
+chmod_error_details (char const *name, mode_t mode)
+{
+ int e = errno;
+ char buf[10];
+ decode_mode (mode, buf);
+ ERROR ((0, e, _("%s: Cannot change mode to %s"),
+ quotearg_colon (name), buf));
+}
+
+void
+chown_error_details (char const *name, uid_t uid, gid_t gid)
+{
+ int e = errno;
+ ERROR ((0, e, _("%s: Cannot change ownership to uid %lu, gid %lu"),
+ quotearg_colon (name), (unsigned long) uid, (unsigned long) gid));
+}
+
+void
+close_error (char const *name)
+{
+ call_arg_error ("close", name);
+}
+
+void
+close_fatal (char const *name)
+{
+ call_arg_fatal ("close", name);
+}
+
+void
+close_warn (char const *name)
+{
+ call_arg_warn ("close", name);
+}
+
+void
+exec_fatal (char const *name)
+{
+ call_arg_fatal ("exec", name);
+}
+
+void
+link_error (char const *target, char const *source)
+{
+ int e = errno;
+ ERROR ((0, e, _("%s: Cannot hard link to %s"),
+ quotearg_colon (source), quote_n (1, target)));
+}
+
+void
+mkdir_error (char const *name)
+{
+ call_arg_error ("mkdir", name);
+}
+
+void
+mkfifo_error (char const *name)
+{
+ call_arg_error ("mkfifo", name);
+}
+
+void
+mknod_error (char const *name)
+{
+ call_arg_error ("mknod", name);
+}
+
+void
+open_error (char const *name)
+{
+ call_arg_error ("open", name);
+}
+
+void
+open_fatal (char const *name)
+{
+ call_arg_fatal ("open", name);
+}
+
+void
+open_warn (char const *name)
+{
+ call_arg_warn ("open", name);
+}
+
+void
+read_error (char const *name)
+{
+ call_arg_error ("read", name);
+}
+
+void
+read_error_details (char const *name, off_t offset, size_t size)
+{
+ char buf[UINTMAX_STRSIZE_BOUND];
+ int e = errno;
+ ERROR ((0, e,
+ _("%s: Read error at byte %s, reading %lu bytes"),
+ quotearg_colon (name), STRINGIFY_BIGINT (offset, buf),
+ (unsigned long) size));
+}
+
+void
+read_warn_details (char const *name, off_t offset, size_t size)
+{
+ char buf[UINTMAX_STRSIZE_BOUND];
+ int e = errno;
+ WARN ((0, e,
+ _("%s: Warning: Read error at byte %s, reading %lu bytes"),
+ quotearg_colon (name), STRINGIFY_BIGINT (offset, buf),
+ (unsigned long) size));
+}
+
+void
+read_fatal (char const *name)
+{
+ call_arg_fatal ("read", name);
+}
+
+void
+read_fatal_details (char const *name, off_t offset, size_t size)
+{
+ char buf[UINTMAX_STRSIZE_BOUND];
+ int e = errno;
+ FATAL_ERROR ((0, e,
+ _("%s: Read error at byte %s, reading %lu bytes"),
+ quotearg_colon (name), STRINGIFY_BIGINT (offset, buf),
+ (unsigned long) size));
+}
+
+void
+readlink_error (char const *name)
+{
+ call_arg_error ("readlink", name);
+}
+
+void
+readlink_warn (char const *name)
+{
+ call_arg_warn ("readlink", name);
+}
+
+void
+savedir_error (char const *name)
+{
+ call_arg_error ("savedir", name);
+}
+
+void
+savedir_warn (char const *name)
+{
+ call_arg_warn ("savedir", name);
+}
+
+void
+seek_error (char const *name)
+{
+ call_arg_error ("seek", name);
+}
+
+void
+seek_error_details (char const *name, off_t offset)
+{
+ char buf[UINTMAX_STRSIZE_BOUND];
+ int e = errno;
+ ERROR ((0, e, _("%s: Cannot seek to %s"),
+ quotearg_colon (name),
+ STRINGIFY_BIGINT (offset, buf)));
+}
+
+void
+seek_warn (char const *name)
+{
+ call_arg_warn ("seek", name);
+}
+
+void
+seek_warn_details (char const *name, off_t offset)
+{
+ char buf[UINTMAX_STRSIZE_BOUND];
+ int e = errno;
+ WARN ((0, e, _("%s: Warning: Cannot seek to %s"),
+ quotearg_colon (name),
+ STRINGIFY_BIGINT (offset, buf)));
+}
+
+void
+symlink_error (char const *contents, char const *name)
+{
+ int e = errno;
+ ERROR ((0, e, _("%s: Cannot create symlink to %s"),
+ quotearg_colon (name), quote_n (1, contents)));
+}
+
+void
+stat_error (char const *name)
+{
+ call_arg_error ("stat", name);
+}
+
+void
+stat_warn (char const *name)
+{
+ call_arg_warn ("stat", name);
+}
+
+void
+truncate_error (char const *name)
+{
+ call_arg_error ("truncate", name);
+}
+
+void
+truncate_warn (char const *name)
+{
+ call_arg_warn ("truncate", name);
+}
+
+void
+unlink_error (char const *name)
+{
+ call_arg_error ("unlink", name);
+}
+
+void
+utime_error (char const *name)
+{
+ call_arg_error ("utime", name);
+}
+
+void
+waitpid_error (char const *name)
+{
+ call_arg_error ("waitpid", name);
+}
+
+void
+write_error (char const *name)
+{
+ call_arg_error ("write", name);
+}
+
+void
+write_error_details (char const *name, ssize_t status, size_t size)
+{
+ if (status < 0)
+ write_error (name);
+ else
+ ERROR ((0, 0, _("%s: Wrote only %lu of %lu bytes"),
+ name, (unsigned long) status, (unsigned long) record_size));
+}
+
+void
+write_fatal (char const *name)
+{
+ call_arg_fatal ("write", name);
+}
+
+void
+write_fatal_details (char const *name, ssize_t status, size_t size)
+{
+ write_error_details (name, status, size);
+ fatal_exit ();
+}
+
+
+/* Fork, aborting if unsuccessful. */
+pid_t
+xfork (void)
+{
+ pid_t p = fork ();
+ if (p == (pid_t) -1)
+ call_arg_fatal ("fork", _("child process"));
+ return p;
+}
+
+/* Create a pipe, aborting if unsuccessful. */
+void
+xpipe (int fd[2])
+{
+ if (pipe (fd) < 0)
+ call_arg_fatal ("pipe", _("interprocess channel"));
+}
+
+/* Return an unambiguous printable representation, allocated in slot N,
+ for NAME, suitable for diagnostics. */
+char const *
+quote_n (int n, char const *name)
+{
+ return quotearg_n_style (n, locale_quoting_style, name);
+}
+
+/* Return an unambiguous printable representation of NAME, suitable
+ for diagnostics. */
+char const *
+quote (char const *name)
+{
+ return quote_n (0, name);
+}
diff --git a/contrib/tar/src/names.c b/contrib/tar/src/names.c
new file mode 100644
index 0000000..eb17636
--- /dev/null
+++ b/contrib/tar/src/names.c
@@ -0,0 +1,941 @@
+/* Various processing of names.
+
+ Copyright 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001 Free
+ Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+
+#include <fnmatch.h>
+#include <grp.h>
+#include <hash.h>
+#include <pwd.h>
+#include <quotearg.h>
+
+#include "common.h"
+
+/* User and group names. */
+
+struct group *getgrnam ();
+struct passwd *getpwnam ();
+#if ! HAVE_DECL_GETPWUID
+struct passwd *getpwuid ();
+#endif
+#if ! HAVE_DECL_GETGRGID
+struct group *getgrgid ();
+#endif
+
+/* Make sure you link with the proper libraries if you are running the
+ Yellow Peril (thanks for the good laugh, Ian J.!), or, euh... NIS.
+ This code should also be modified for non-UNIX systems to do something
+ reasonable. */
+
+static char cached_uname[UNAME_FIELD_SIZE];
+static char cached_gname[GNAME_FIELD_SIZE];
+
+static uid_t cached_uid; /* valid only if cached_uname is not empty */
+static gid_t cached_gid; /* valid only if cached_gname is not empty */
+
+/* These variables are valid only if nonempty. */
+static char cached_no_such_uname[UNAME_FIELD_SIZE];
+static char cached_no_such_gname[GNAME_FIELD_SIZE];
+
+/* These variables are valid only if nonzero. It's not worth optimizing
+ the case for weird systems where 0 is not a valid uid or gid. */
+static uid_t cached_no_such_uid;
+static gid_t cached_no_such_gid;
+
+/* Given UID, find the corresponding UNAME. */
+void
+uid_to_uname (uid_t uid, char uname[UNAME_FIELD_SIZE])
+{
+ struct passwd *passwd;
+
+ if (uid != 0 && uid == cached_no_such_uid)
+ {
+ *uname = '\0';
+ return;
+ }
+
+ if (!cached_uname[0] || uid != cached_uid)
+ {
+ passwd = getpwuid (uid);
+ if (passwd)
+ {
+ cached_uid = uid;
+ strncpy (cached_uname, passwd->pw_name, UNAME_FIELD_SIZE);
+ }
+ else
+ {
+ cached_no_such_uid = uid;
+ *uname = '\0';
+ return;
+ }
+ }
+ strncpy (uname, cached_uname, UNAME_FIELD_SIZE);
+}
+
+/* Given GID, find the corresponding GNAME. */
+void
+gid_to_gname (gid_t gid, char gname[GNAME_FIELD_SIZE])
+{
+ struct group *group;
+
+ if (gid != 0 && gid == cached_no_such_gid)
+ {
+ *gname = '\0';
+ return;
+ }
+
+ if (!cached_gname[0] || gid != cached_gid)
+ {
+ group = getgrgid (gid);
+ if (group)
+ {
+ cached_gid = gid;
+ strncpy (cached_gname, group->gr_name, GNAME_FIELD_SIZE);
+ }
+ else
+ {
+ cached_no_such_gid = gid;
+ *gname = '\0';
+ return;
+ }
+ }
+ strncpy (gname, cached_gname, GNAME_FIELD_SIZE);
+}
+
+/* Given UNAME, set the corresponding UID and return 1, or else, return 0. */
+int
+uname_to_uid (char uname[UNAME_FIELD_SIZE], uid_t *uidp)
+{
+ struct passwd *passwd;
+
+ if (cached_no_such_uname[0]
+ && strncmp (uname, cached_no_such_uname, UNAME_FIELD_SIZE) == 0)
+ return 0;
+
+ if (!cached_uname[0]
+ || uname[0] != cached_uname[0]
+ || strncmp (uname, cached_uname, UNAME_FIELD_SIZE) != 0)
+ {
+ passwd = getpwnam (uname);
+ if (passwd)
+ {
+ cached_uid = passwd->pw_uid;
+ strncpy (cached_uname, uname, UNAME_FIELD_SIZE);
+ }
+ else
+ {
+ strncpy (cached_no_such_uname, uname, UNAME_FIELD_SIZE);
+ return 0;
+ }
+ }
+ *uidp = cached_uid;
+ return 1;
+}
+
+/* Given GNAME, set the corresponding GID and return 1, or else, return 0. */
+int
+gname_to_gid (char gname[GNAME_FIELD_SIZE], gid_t *gidp)
+{
+ struct group *group;
+
+ if (cached_no_such_gname[0]
+ && strncmp (gname, cached_no_such_gname, GNAME_FIELD_SIZE) == 0)
+ return 0;
+
+ if (!cached_gname[0]
+ || gname[0] != cached_gname[0]
+ || strncmp (gname, cached_gname, GNAME_FIELD_SIZE) != 0)
+ {
+ group = getgrnam (gname);
+ if (group)
+ {
+ cached_gid = group->gr_gid;
+ strncpy (cached_gname, gname, GNAME_FIELD_SIZE);
+ }
+ else
+ {
+ strncpy (cached_no_such_gname, gname, GNAME_FIELD_SIZE);
+ return 0;
+ }
+ }
+ *gidp = cached_gid;
+ return 1;
+}
+
+/* Names from the command call. */
+
+static struct name *namelist; /* first name in list, if any */
+static struct name **nametail = &namelist; /* end of name list */
+static const char **name_array; /* store an array of names */
+static int allocated_names; /* how big is the array? */
+static int names; /* how many entries does it have? */
+static int name_index; /* how many of the entries have we scanned? */
+
+/* Initialize structures. */
+void
+init_names (void)
+{
+ allocated_names = 10;
+ name_array = xmalloc (sizeof (const char *) * allocated_names);
+ names = 0;
+}
+
+/* Add NAME at end of name_array, reallocating it as necessary. */
+void
+name_add (const char *name)
+{
+ if (names == allocated_names)
+ {
+ allocated_names *= 2;
+ name_array =
+ xrealloc (name_array, sizeof (const char *) * allocated_names);
+ }
+ name_array[names++] = name;
+}
+
+/* Names from external name file. */
+
+static FILE *name_file; /* file to read names from */
+static char *name_buffer; /* buffer to hold the current file name */
+static size_t name_buffer_length; /* allocated length of name_buffer */
+
+/* FIXME: I should better check more closely. It seems at first glance that
+ is_pattern is only used when reading a file, and ignored for all
+ command line arguments. */
+
+static inline int
+is_pattern (const char *string)
+{
+ return strchr (string, '*') || strchr (string, '[') || strchr (string, '?');
+}
+
+/* Set up to gather file names for tar. They can either come from a
+ file or were saved from decoding arguments. */
+void
+name_init (int argc, char *const *argv)
+{
+ name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
+ name_buffer_length = NAME_FIELD_SIZE;
+
+ if (files_from_option)
+ {
+ if (!strcmp (files_from_option, "-"))
+ {
+ request_stdin ("-T");
+ name_file = stdin;
+ }
+ else if (name_file = fopen (files_from_option, "r"), !name_file)
+ open_fatal (files_from_option);
+ }
+}
+
+void
+name_term (void)
+{
+ free (name_buffer);
+ free (name_array);
+}
+
+/* Read the next filename from name_file and null-terminate it. Put
+ it into name_buffer, reallocating and adjusting name_buffer_length
+ if necessary. Return 0 at end of file, 1 otherwise. */
+static int
+read_name_from_file (void)
+{
+ int character;
+ size_t counter = 0;
+
+ /* FIXME: getc may be called even if character was EOF the last time here. */
+
+ /* FIXME: This + 2 allocation might serve no purpose. */
+
+ while (character = getc (name_file),
+ character != EOF && character != filename_terminator)
+ {
+ if (counter == name_buffer_length)
+ {
+ if (name_buffer_length * 2 < name_buffer_length)
+ xalloc_die ();
+ name_buffer_length *= 2;
+ name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
+ }
+ name_buffer[counter++] = character;
+ }
+
+ if (counter == 0 && character == EOF)
+ return 0;
+
+ if (counter == name_buffer_length)
+ {
+ if (name_buffer_length * 2 < name_buffer_length)
+ xalloc_die ();
+ name_buffer_length *= 2;
+ name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
+ }
+ name_buffer[counter] = '\0';
+
+ return 1;
+}
+
+/* Get the next name from ARGV or the file of names. Result is in
+ static storage and can't be relied upon across two calls.
+
+ If CHANGE_DIRS is true, treat a filename of the form "-C" as
+ meaning that the next filename is the name of a directory to change
+ to. If filename_terminator is NUL, CHANGE_DIRS is effectively
+ always false. */
+char *
+name_next (int change_dirs)
+{
+ const char *source;
+ char *cursor;
+ int chdir_flag = 0;
+
+ if (filename_terminator == '\0')
+ change_dirs = 0;
+
+ while (1)
+ {
+ /* Get a name, either from file or from saved arguments. */
+
+ if (name_index == names)
+ {
+ if (! name_file)
+ break;
+ if (! read_name_from_file ())
+ break;
+ }
+ else
+ {
+ size_t source_len;
+ source = name_array[name_index++];
+ source_len = strlen (source);
+ if (name_buffer_length < source_len)
+ {
+ do
+ {
+ name_buffer_length *= 2;
+ if (! name_buffer_length)
+ xalloc_die ();
+ }
+ while (name_buffer_length < source_len);
+
+ free (name_buffer);
+ name_buffer = xmalloc (name_buffer_length + 2);
+ }
+ strcpy (name_buffer, source);
+ }
+
+ /* Zap trailing slashes. */
+
+ cursor = name_buffer + strlen (name_buffer) - 1;
+ while (cursor > name_buffer && ISSLASH (*cursor))
+ *cursor-- = '\0';
+
+ if (chdir_flag)
+ {
+ if (chdir (name_buffer) < 0)
+ chdir_fatal (name_buffer);
+ chdir_flag = 0;
+ }
+ else if (change_dirs && strcmp (name_buffer, "-C") == 0)
+ chdir_flag = 1;
+ else
+ {
+ unquote_string (name_buffer);
+ return name_buffer;
+ }
+ }
+
+ /* No more names in file. */
+
+ if (name_file && chdir_flag)
+ FATAL_ERROR ((0, 0, _("Missing file name after -C")));
+
+ return 0;
+}
+
+/* Close the name file, if any. */
+void
+name_close (void)
+{
+ if (name_file && name_file != stdin)
+ if (fclose (name_file) != 0)
+ close_error (name_buffer);
+}
+
+/* Gather names in a list for scanning. Could hash them later if we
+ really care.
+
+ If the names are already sorted to match the archive, we just read
+ them one by one. name_gather reads the first one, and it is called
+ by name_match as appropriate to read the next ones. At EOF, the
+ last name read is just left in the buffer. This option lets users
+ of small machines extract an arbitrary number of files by doing
+ "tar t" and editing down the list of files. */
+
+void
+name_gather (void)
+{
+ /* Buffer able to hold a single name. */
+ static struct name *buffer;
+ static size_t allocated_size;
+
+ char const *name;
+
+ if (same_order_option)
+ {
+ static int change_dir;
+
+ if (allocated_size == 0)
+ {
+ allocated_size = offsetof (struct name, name) + NAME_FIELD_SIZE + 1;
+ buffer = xmalloc (allocated_size);
+ /* FIXME: This memset is overkill, and ugly... */
+ memset (buffer, 0, allocated_size);
+ }
+
+ while ((name = name_next (0)) && strcmp (name, "-C") == 0)
+ {
+ char const *dir = name_next (0);
+ if (! dir)
+ FATAL_ERROR ((0, 0, _("Missing file name after -C")));
+ change_dir = chdir_arg (xstrdup (dir));
+ }
+
+ if (name)
+ {
+ size_t needed_size;
+ buffer->length = strlen (name);
+ needed_size = offsetof (struct name, name) + buffer->length + 1;
+ if (allocated_size < needed_size)
+ {
+ do
+ {
+ allocated_size *= 2;
+ if (! allocated_size)
+ xalloc_die ();
+ }
+ while (allocated_size < needed_size);
+
+ buffer = xrealloc (buffer, allocated_size);
+ }
+ buffer->change_dir = change_dir;
+ strcpy (buffer->name, name);
+ buffer->next = 0;
+ buffer->found = 0;
+
+ namelist = buffer;
+ nametail = &namelist->next;
+ }
+ }
+ else
+ {
+ /* Non sorted names -- read them all in. */
+ int change_dir = 0;
+
+ for (;;)
+ {
+ int change_dir0 = change_dir;
+ while ((name = name_next (0)) && strcmp (name, "-C") == 0)
+ {
+ char const *dir = name_next (0);
+ if (! dir)
+ FATAL_ERROR ((0, 0, _("Missing file name after -C")));
+ change_dir = chdir_arg (xstrdup (dir));
+ }
+ if (name)
+ addname (name, change_dir);
+ else
+ {
+ if (change_dir != change_dir0)
+ addname (0, change_dir);
+ break;
+ }
+ }
+ }
+}
+
+/* Add a name to the namelist. */
+struct name *
+addname (char const *string, int change_dir)
+{
+ size_t length = string ? strlen (string) : 0;
+ struct name *name = xmalloc (offsetof (struct name, name) + length + 1);
+
+ if (string)
+ {
+ name->fake = 0;
+ strcpy (name->name, string);
+ }
+ else
+ {
+ name->fake = 1;
+
+ /* FIXME: This initialization (and the byte of memory that it
+ initializes) is probably not needed, but we are currently in
+ bug-fix mode so we'll leave it in for now. */
+ name->name[0] = 0;
+ }
+
+ name->next = 0;
+ name->length = length;
+ name->found = 0;
+ name->regexp = 0; /* assume not a regular expression */
+ name->firstch = 1; /* assume first char is literal */
+ name->change_dir = change_dir;
+ name->dir_contents = 0;
+
+ if (string && is_pattern (string))
+ {
+ name->regexp = 1;
+ if (string[0] == '*' || string[0] == '[' || string[0] == '?')
+ name->firstch = 0;
+ }
+
+ *nametail = name;
+ nametail = &name->next;
+ return name;
+}
+
+/* Find a match for PATH (whose string length is LENGTH) in the name
+ list. */
+static struct name *
+namelist_match (char const *path, size_t length)
+{
+ struct name *p;
+
+ for (p = namelist; p; p = p->next)
+ {
+ /* If first chars don't match, quick skip. */
+
+ if (p->firstch && p->name[0] != path[0])
+ continue;
+
+ if (p->regexp
+ ? fnmatch (p->name, path, recursion_option) == 0
+ : (p->length <= length
+ && (path[p->length] == '\0' || ISSLASH (path[p->length]))
+ && memcmp (path, p->name, p->length) == 0))
+ return p;
+ }
+
+ return 0;
+}
+
+/* Return true if and only if name PATH (from an archive) matches any
+ name from the namelist. */
+int
+name_match (const char *path)
+{
+ size_t length = strlen (path);
+
+ while (1)
+ {
+ struct name *cursor = namelist;
+
+ if (!cursor)
+ return ! files_from_option;
+
+ if (cursor->fake)
+ {
+ chdir_do (cursor->change_dir);
+ namelist = 0;
+ nametail = &namelist;
+ return ! files_from_option;
+ }
+
+ cursor = namelist_match (path, length);
+ if (cursor)
+ {
+ cursor->found = 1; /* remember it matched */
+ if (starting_file_option)
+ {
+ free (namelist);
+ namelist = 0;
+ nametail = &namelist;
+ }
+ chdir_do (cursor->change_dir);
+
+ /* We got a match. */
+ return 1;
+ }
+
+ /* Filename from archive not found in namelist. If we have the whole
+ namelist here, just return 0. Otherwise, read the next name in and
+ compare it. If this was the last name, namelist->found will remain
+ on. If not, we loop to compare the newly read name. */
+
+ if (same_order_option && namelist->found)
+ {
+ name_gather (); /* read one more */
+ if (namelist->found)
+ return 0;
+ }
+ else
+ return 0;
+ }
+}
+
+/* Print the names of things in the namelist that were not matched. */
+void
+names_notfound (void)
+{
+ struct name const *cursor;
+
+ for (cursor = namelist; cursor; cursor = cursor->next)
+ if (!cursor->found && !cursor->fake)
+ ERROR ((0, 0, _("%s: Not found in archive"),
+ quotearg_colon (cursor->name)));
+
+ /* Don't bother freeing the name list; we're about to exit. */
+ namelist = 0;
+ nametail = &namelist;
+
+ if (same_order_option)
+ {
+ char *name;
+
+ while (name = name_next (1), name)
+ ERROR ((0, 0, _("%s: Not found in archive"),
+ quotearg_colon (name)));
+ }
+}
+
+/* Sorting name lists. */
+
+/* Sort linked LIST of names, of given LENGTH, using COMPARE to order
+ names. Return the sorted list. Apart from the type `struct name'
+ and the definition of SUCCESSOR, this is a generic list-sorting
+ function, but it's too painful to make it both generic and portable
+ in C. */
+
+static struct name *
+merge_sort (struct name *list, int length,
+ int (*compare) (struct name const*, struct name const*))
+{
+ struct name *first_list;
+ struct name *second_list;
+ int first_length;
+ int second_length;
+ struct name *result;
+ struct name **merge_point;
+ struct name *cursor;
+ int counter;
+
+# define SUCCESSOR(name) ((name)->next)
+
+ if (length == 1)
+ return list;
+
+ if (length == 2)
+ {
+ if ((*compare) (list, SUCCESSOR (list)) > 0)
+ {
+ result = SUCCESSOR (list);
+ SUCCESSOR (result) = list;
+ SUCCESSOR (list) = 0;
+ return result;
+ }
+ return list;
+ }
+
+ first_list = list;
+ first_length = (length + 1) / 2;
+ second_length = length / 2;
+ for (cursor = list, counter = first_length - 1;
+ counter;
+ cursor = SUCCESSOR (cursor), counter--)
+ continue;
+ second_list = SUCCESSOR (cursor);
+ SUCCESSOR (cursor) = 0;
+
+ first_list = merge_sort (first_list, first_length, compare);
+ second_list = merge_sort (second_list, second_length, compare);
+
+ merge_point = &result;
+ while (first_list && second_list)
+ if ((*compare) (first_list, second_list) < 0)
+ {
+ cursor = SUCCESSOR (first_list);
+ *merge_point = first_list;
+ merge_point = &SUCCESSOR (first_list);
+ first_list = cursor;
+ }
+ else
+ {
+ cursor = SUCCESSOR (second_list);
+ *merge_point = second_list;
+ merge_point = &SUCCESSOR (second_list);
+ second_list = cursor;
+ }
+ if (first_list)
+ *merge_point = first_list;
+ else
+ *merge_point = second_list;
+
+ return result;
+
+#undef SUCCESSOR
+}
+
+/* A comparison function for sorting names. Put found names last;
+ break ties by string comparison. */
+
+static int
+compare_names (struct name const *n1, struct name const *n2)
+{
+ int found_diff = n2->found - n1->found;
+ return found_diff ? found_diff : strcmp (n1->name, n2->name);
+}
+
+/* Add all the dirs under NAME, which names a directory, to the namelist.
+ If any of the files is a directory, recurse on the subdirectory.
+ DEVICE is the device not to leave, if the -l option is specified. */
+
+static void
+add_hierarchy_to_namelist (struct name *name, dev_t device)
+{
+ char *path = name->name;
+ char *buffer = get_directory_contents (path, device);
+
+ if (! buffer)
+ name->dir_contents = "\0\0\0\0";
+ else
+ {
+ size_t name_length = name->length;
+ size_t allocated_length = (name_length >= NAME_FIELD_SIZE
+ ? name_length + NAME_FIELD_SIZE
+ : NAME_FIELD_SIZE);
+ char *name_buffer = xmalloc (allocated_length + 1);
+ /* FIXME: + 2 above? */
+ char *string;
+ size_t string_length;
+ int change_dir = name->change_dir;
+
+ name->dir_contents = buffer;
+ strcpy (name_buffer, path);
+ if (! ISSLASH (name_buffer[name_length - 1]))
+ {
+ name_buffer[name_length++] = '/';
+ name_buffer[name_length] = '\0';
+ }
+
+ for (string = buffer; *string; string += string_length + 1)
+ {
+ string_length = strlen (string);
+ if (*string == 'D')
+ {
+ if (allocated_length <= name_length + string_length)
+ {
+ do
+ {
+ allocated_length *= 2;
+ if (! allocated_length)
+ xalloc_die ();
+ }
+ while (allocated_length <= name_length + string_length);
+
+ name_buffer = xrealloc (name_buffer, allocated_length + 1);
+ }
+ strcpy (name_buffer + name_length, string + 1);
+ add_hierarchy_to_namelist (addname (name_buffer, change_dir),
+ device);
+ }
+ }
+
+ free (name_buffer);
+ }
+}
+
+/* Collect all the names from argv[] (or whatever), expand them into a
+ directory tree, and sort them. This gets only subdirectories, not
+ all files. */
+
+void
+collect_and_sort_names (void)
+{
+ struct name *name;
+ struct name *next_name;
+ int num_names;
+ struct stat statbuf;
+
+ name_gather ();
+
+ if (listed_incremental_option)
+ read_directory_file ();
+
+ if (!namelist)
+ addname (".", 0);
+
+ for (name = namelist; name; name = next_name)
+ {
+ next_name = name->next;
+ if (name->found || name->dir_contents)
+ continue;
+ if (name->regexp) /* FIXME: just skip regexps for now */
+ continue;
+ chdir_do (name->change_dir);
+ if (name->fake)
+ continue;
+
+ if (deref_stat (dereference_option, name->name, &statbuf) != 0)
+ {
+ if (ignore_failed_read_option)
+ stat_warn (name->name);
+ else
+ stat_error (name->name);
+ continue;
+ }
+ if (S_ISDIR (statbuf.st_mode))
+ {
+ name->found = 1;
+ add_hierarchy_to_namelist (name, statbuf.st_dev);
+ }
+ }
+
+ num_names = 0;
+ for (name = namelist; name; name = name->next)
+ num_names++;
+ namelist = merge_sort (namelist, num_names, compare_names);
+
+ for (name = namelist; name; name = name->next)
+ name->found = 0;
+}
+
+/* This is like name_match, except that it returns a pointer to the
+ name it matched, and doesn't set FOUND in structure. The caller
+ will have to do that if it wants to. Oh, and if the namelist is
+ empty, it returns null, unlike name_match, which returns TRUE. */
+struct name *
+name_scan (const char *path)
+{
+ size_t length = strlen (path);
+
+ while (1)
+ {
+ struct name *cursor = namelist_match (path, length);
+ if (cursor)
+ return cursor;
+
+ /* Filename from archive not found in namelist. If we have the whole
+ namelist here, just return 0. Otherwise, read the next name in and
+ compare it. If this was the last name, namelist->found will remain
+ on. If not, we loop to compare the newly read name. */
+
+ if (same_order_option && namelist && namelist->found)
+ {
+ name_gather (); /* read one more */
+ if (namelist->found)
+ return 0;
+ }
+ else
+ return 0;
+ }
+}
+
+/* This returns a name from the namelist which doesn't have ->found
+ set. It sets ->found before returning, so successive calls will
+ find and return all the non-found names in the namelist. */
+struct name *gnu_list_name;
+
+char *
+name_from_list (void)
+{
+ if (!gnu_list_name)
+ gnu_list_name = namelist;
+ while (gnu_list_name && (gnu_list_name->found | gnu_list_name->fake))
+ gnu_list_name = gnu_list_name->next;
+ if (gnu_list_name)
+ {
+ gnu_list_name->found = 1;
+ chdir_do (gnu_list_name->change_dir);
+ return gnu_list_name->name;
+ }
+ return 0;
+}
+
+void
+blank_name_list (void)
+{
+ struct name *name;
+
+ gnu_list_name = 0;
+ for (name = namelist; name; name = name->next)
+ name->found = 0;
+}
+
+/* Yield a newly allocated file name consisting of PATH concatenated to
+ NAME, with an intervening slash if PATH does not already end in one. */
+char *
+new_name (const char *path, const char *name)
+{
+ size_t pathlen = strlen (path);
+ size_t namesize = strlen (name) + 1;
+ int slash = pathlen && ! ISSLASH (path[pathlen - 1]);
+ char *buffer = xmalloc (pathlen + slash + namesize);
+ memcpy (buffer, path, pathlen);
+ buffer[pathlen] = '/';
+ memcpy (buffer + pathlen + slash, name, namesize);
+ return buffer;
+}
+
+/* Return nonzero if file NAME is excluded. Exclude a name if its
+ prefix matches a pattern that contains slashes, or if one of its
+ components matches a pattern that contains no slashes. */
+bool
+excluded_name (char const *name)
+{
+ return excluded_filename (excluded, name + FILESYSTEM_PREFIX_LEN (name));
+}
+
+/* Names to avoid dumping. */
+static Hash_table *avoided_name_table;
+
+/* Calculate the hash of an avoided name. */
+static unsigned
+hash_avoided_name (void const *name, unsigned n_buckets)
+{
+ return hash_string (name, n_buckets);
+}
+
+/* Compare two avoided names for equality. */
+static bool
+compare_avoided_names (void const *name1, void const *name2)
+{
+ return strcmp (name1, name2) == 0;
+}
+
+/* Remember to not archive NAME. */
+void
+add_avoided_name (char const *name)
+{
+ if (! ((avoided_name_table
+ || (avoided_name_table = hash_initialize (0, 0, hash_avoided_name,
+ compare_avoided_names, 0)))
+ && hash_insert (avoided_name_table, xstrdup (name))))
+ xalloc_die ();
+}
+
+/* Should NAME be avoided when archiving? */
+int
+is_avoided_name (char const *name)
+{
+ return avoided_name_table && hash_lookup (avoided_name_table, name);
+}
diff --git a/contrib/tar/src/rmt.c b/contrib/tar/src/rmt.c
new file mode 100644
index 0000000..0fe166b
--- /dev/null
+++ b/contrib/tar/src/rmt.c
@@ -0,0 +1,576 @@
+/* Remote connection server.
+
+ Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Copyright (C) 1983 Regents of the University of California.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms are permitted provided
+ that the above copyright notice and this paragraph are duplicated in all
+ such forms and that any documentation, advertising materials, and other
+ materials related to such distribution and use acknowledge that the
+ software was developed by the University of California, Berkeley. The
+ name of the University may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
+
+#include "system.h"
+#include <print-copyr.h>
+#include <localedir.h>
+#include <safe-read.h>
+#include <full-write.h>
+
+#include <getopt.h>
+#include <sys/socket.h>
+
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+#ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+#endif
+
+/* Maximum size of a string from the requesting program. */
+#define STRING_SIZE 64
+
+/* Name of executing program. */
+const char *program_name;
+
+/* File descriptor of the tape device, or negative if none open. */
+static int tape = -1;
+
+/* Buffer containing transferred data, and its allocated size. */
+static char *record_buffer;
+static size_t allocated_size;
+
+/* Buffer for constructing the reply. */
+static char reply_buffer[BUFSIZ];
+
+/* Debugging tools. */
+
+static FILE *debug_file;
+
+#define DEBUG(File) \
+ if (debug_file) fprintf(debug_file, File)
+
+#define DEBUG1(File, Arg) \
+ if (debug_file) fprintf(debug_file, File, Arg)
+
+#define DEBUG2(File, Arg1, Arg2) \
+ if (debug_file) fprintf(debug_file, File, Arg1, Arg2)
+
+/* Return an error string, given an error number. */
+#if HAVE_STRERROR
+# ifndef strerror
+char *strerror ();
+# endif
+#else
+static char *
+private_strerror (int errnum)
+{
+ extern char *sys_errlist[];
+ extern int sys_nerr;
+
+ if (errnum > 0 && errnum <= sys_nerr)
+ return _(sys_errlist[errnum]);
+ return _("Unknown system error");
+}
+# define strerror private_strerror
+#endif
+
+static void
+report_error_message (const char *string)
+{
+ DEBUG1 ("rmtd: E 0 (%s)\n", string);
+
+ sprintf (reply_buffer, "E0\n%s\n", string);
+ full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
+}
+
+static void
+report_numbered_error (int num)
+{
+ DEBUG2 ("rmtd: E %d (%s)\n", num, strerror (num));
+
+ sprintf (reply_buffer, "E%d\n%s\n", num, strerror (num));
+ full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
+}
+
+static void
+get_string (char *string)
+{
+ int counter;
+
+ for (counter = 0; counter < STRING_SIZE; counter++)
+ {
+ if (safe_read (STDIN_FILENO, string + counter, 1) != 1)
+ exit (EXIT_SUCCESS);
+
+ if (string[counter] == '\n')
+ break;
+ }
+ string[counter] = '\0';
+}
+
+static void
+prepare_record_buffer (size_t size)
+{
+ if (size <= allocated_size)
+ return;
+
+ if (record_buffer)
+ free (record_buffer);
+
+ record_buffer = malloc (size);
+
+ if (! record_buffer)
+ {
+ DEBUG (_("rmtd: Cannot allocate buffer space\n"));
+
+ report_error_message (N_("Cannot allocate buffer space"));
+ exit (EXIT_FAILURE); /* exit status used to be 4 */
+ }
+
+ allocated_size = size;
+
+#ifdef SO_RCVBUF
+ while (size > 1024 &&
+ (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_RCVBUF,
+ (char *) &size, sizeof size)
+ < 0))
+ size -= 1024;
+#else
+ /* FIXME: I do not see any purpose to the following line... Sigh! */
+ size = 1 + ((size - 1) % 1024);
+#endif
+}
+
+/* Decode OFLAG_STRING, which represents the 2nd argument to `open'.
+ OFLAG_STRING should contain an optional integer, followed by an optional
+ symbolic representation of an open flag using only '|' to separate its
+ components (e.g. "O_WRONLY|O_CREAT|O_TRUNC"). Prefer the symbolic
+ representation if available, falling back on the numeric
+ representation, or to zero if both formats are absent.
+
+ This function should be the inverse of encode_oflag. The numeric
+ representation is not portable from one host to another, but it is
+ for backward compatibility with old-fashioned clients that do not
+ emit symbolic open flags. */
+
+static int
+decode_oflag (char const *oflag_string)
+{
+ char *oflag_num_end;
+ int numeric_oflag = strtol (oflag_string, &oflag_num_end, 10);
+ int symbolic_oflag = 0;
+
+ oflag_string = oflag_num_end;
+ while (ISSPACE ((unsigned char) *oflag_string))
+ oflag_string++;
+
+ do
+ {
+ struct name_value_pair { char const *name; int value; };
+ static struct name_value_pair const table[] =
+ {
+#ifdef O_APPEND
+ {"APPEND", O_APPEND},
+#endif
+ {"CREAT", O_CREAT},
+#ifdef O_DSYNC
+ {"DSYNC", O_DSYNC},
+#endif
+ {"EXCL", O_EXCL},
+#ifdef O_LARGEFILE
+ {"LARGEFILE", O_LARGEFILE}, /* LFS extension for opening large files */
+#endif
+#ifdef O_NOCTTY
+ {"NOCTTY", O_NOCTTY},
+#endif
+#ifdef O_NONBLOCK
+ {"NONBLOCK", O_NONBLOCK},
+#endif
+ {"RDONLY", O_RDONLY},
+ {"RDWR", O_RDWR},
+#ifdef O_RSYNC
+ {"RSYNC", O_RSYNC},
+#endif
+#ifdef O_SYNC
+ {"SYNC", O_SYNC},
+#endif
+ {"TRUNC", O_TRUNC},
+ {"WRONLY", O_WRONLY}
+ };
+ struct name_value_pair const *t;
+ size_t s;
+
+ if (*oflag_string++ != 'O' || *oflag_string++ != '_')
+ return numeric_oflag;
+
+ for (t = table;
+ (strncmp (oflag_string, t->name, s = strlen (t->name)) != 0
+ || (oflag_string[s]
+ && strchr ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789",
+ oflag_string[s])));
+ t++)
+ if (t == table + sizeof table / sizeof *table - 1)
+ return numeric_oflag;
+
+ symbolic_oflag |= t->value;
+ oflag_string += s;
+ }
+ while (*oflag_string++ == '|');
+
+ return symbolic_oflag;
+}
+
+static struct option const long_opts[] =
+{
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+};
+
+static void
+usage (int status)
+{
+ if (status != EXIT_SUCCESS)
+ fprintf (stderr, _("Try `%s --help' for more information.\n"),
+ program_name);
+ else
+ {
+ printf (_("\
+Usage: %s [OPTION]\n\
+Manipulate a tape drive, accepting commands from a remote process.\n\
+\n\
+ --version Output version info.\n\
+ --help Output this help.\n"),
+ program_name);
+ fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout);
+ }
+
+ exit (status);
+}
+
+int
+main (int argc, char *const *argv)
+{
+ char command;
+ ssize_t status;
+
+ /* FIXME: Localization is meaningless, unless --help and --version are
+ locally used. Localization would be best accomplished by the calling
+ tar, on messages found within error packets. */
+
+ program_name = argv[0];
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ switch (getopt_long (argc, argv, "", long_opts, NULL))
+ {
+ default:
+ usage (EXIT_FAILURE);
+
+ case 'h':
+ usage (EXIT_SUCCESS);
+
+ case 'v':
+ {
+ printf ("rmt (GNU %s) %s\n", PACKAGE, VERSION);
+ print_copyright ("2001 Free Software Foundation, Inc.");
+ puts (_("\
+This program comes with NO WARRANTY, to the extent permitted by law.\n\
+You may redistribute it under the terms of the GNU General Public License;\n\
+see the file named COPYING for details."));
+ }
+ return EXIT_SUCCESS;
+
+ case -1:
+ break;
+ }
+
+ if (optind < argc)
+ {
+ if (optind != argc - 1)
+ usage (EXIT_FAILURE);
+ debug_file = fopen (argv[optind], "w");
+ if (debug_file == 0)
+ {
+ report_numbered_error (errno);
+ exit (EXIT_FAILURE);
+ }
+ setbuf (debug_file, 0);
+ }
+
+top:
+ errno = 0;
+ status = 0;
+ if (safe_read (STDIN_FILENO, &command, 1) != 1)
+ return EXIT_SUCCESS;
+
+ switch (command)
+ {
+ /* FIXME: Maybe 'H' and 'V' for --help and --version output? */
+
+ case 'O':
+ {
+ char device_string[STRING_SIZE];
+ char oflag_string[STRING_SIZE];
+
+ get_string (device_string);
+ get_string (oflag_string);
+ DEBUG2 ("rmtd: O %s %s\n", device_string, oflag_string);
+
+ if (tape >= 0)
+ close (tape);
+
+ tape = open (device_string, decode_oflag (oflag_string), MODE_RW);
+ if (tape < 0)
+ goto ioerror;
+ goto respond;
+ }
+
+ case 'C':
+ {
+ char device_string[STRING_SIZE];
+
+ get_string (device_string); /* discard */
+ DEBUG ("rmtd: C\n");
+
+ if (close (tape) < 0)
+ goto ioerror;
+ tape = -1;
+ goto respond;
+ }
+
+ case 'L':
+ {
+ char count_string[STRING_SIZE];
+ char position_string[STRING_SIZE];
+ off_t count = 0;
+ int negative;
+ int whence;
+ char *p;
+
+ get_string (count_string);
+ get_string (position_string);
+ DEBUG2 ("rmtd: L %s %s\n", count_string, position_string);
+
+ /* Parse count_string, taking care to check for overflow.
+ We can't use standard functions,
+ since off_t might be longer than long. */
+
+ for (p = count_string; *p == ' ' || *p == '\t'; p++)
+ continue;
+
+ negative = *p == '-';
+ p += negative || *p == '+';
+
+ for (;;)
+ {
+ int digit = *p++ - '0';
+ if (9 < (unsigned) digit)
+ break;
+ else
+ {
+ off_t c10 = 10 * count;
+ off_t nc = negative ? c10 - digit : c10 + digit;
+ if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
+ {
+ report_error_message (N_("Seek offset out of range"));
+ exit (EXIT_FAILURE);
+ }
+ count = nc;
+ }
+ }
+
+ switch (atoi (position_string))
+ {
+ case 0: whence = SEEK_SET; break;
+ case 1: whence = SEEK_CUR; break;
+ case 2: whence = SEEK_END; break;
+ default:
+ report_error_message (N_("Seek direction out of range"));
+ exit (EXIT_FAILURE);
+ }
+ count = lseek (tape, count, whence);
+ if (count < 0)
+ goto ioerror;
+
+ /* Convert count back to string for reply.
+ We can't use sprintf, since off_t might be longer than long. */
+ p = count_string + sizeof count_string;
+ *--p = '\0';
+ do
+ *--p = '0' + (int) (count % 10);
+ while ((count /= 10) != 0);
+
+ DEBUG1 ("rmtd: A %s\n", p);
+
+ sprintf (reply_buffer, "A%s\n", p);
+ full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
+ goto top;
+ }
+
+ case 'W':
+ {
+ char count_string[STRING_SIZE];
+ size_t size;
+ size_t counter;
+
+ get_string (count_string);
+ size = atol (count_string);
+ DEBUG1 ("rmtd: W %s\n", count_string);
+
+ prepare_record_buffer (size);
+ for (counter = 0; counter < size; counter += status)
+ {
+ status = safe_read (STDIN_FILENO, &record_buffer[counter],
+ size - counter);
+ if (status <= 0)
+ {
+ DEBUG (_("rmtd: Premature eof\n"));
+
+ report_error_message (N_("Premature end of file"));
+ exit (EXIT_FAILURE); /* exit status used to be 2 */
+ }
+ }
+ status = full_write (tape, record_buffer, size);
+ if (status < 0)
+ goto ioerror;
+ goto respond;
+ }
+
+ case 'R':
+ {
+ char count_string[STRING_SIZE];
+ size_t size;
+
+ get_string (count_string);
+ DEBUG1 ("rmtd: R %s\n", count_string);
+
+ size = atol (count_string);
+ prepare_record_buffer (size);
+ status = safe_read (tape, record_buffer, size);
+ if (status < 0)
+ goto ioerror;
+ sprintf (reply_buffer, "A%ld\n", (long) status);
+ full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
+ full_write (STDOUT_FILENO, record_buffer, status);
+ goto top;
+ }
+
+ case 'I':
+ {
+ char operation_string[STRING_SIZE];
+ char count_string[STRING_SIZE];
+
+ get_string (operation_string);
+ get_string (count_string);
+ DEBUG2 ("rmtd: I %s %s\n", operation_string, count_string);
+
+#ifdef MTIOCTOP
+ {
+ struct mtop mtop;
+ const char *p;
+ off_t count = 0;
+ int negative;
+
+ /* Parse count_string, taking care to check for overflow.
+ We can't use standard functions,
+ since off_t might be longer than long. */
+
+ for (p = count_string; *p == ' ' || *p == '\t'; p++)
+ continue;
+
+ negative = *p == '-';
+ p += negative || *p == '+';
+
+ for (;;)
+ {
+ int digit = *p++ - '0';
+ if (9 < (unsigned) digit)
+ break;
+ else
+ {
+ off_t c10 = 10 * count;
+ off_t nc = negative ? c10 - digit : c10 + digit;
+ if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
+ {
+ report_error_message (N_("Seek offset out of range"));
+ exit (EXIT_FAILURE);
+ }
+ count = nc;
+ }
+ }
+
+ mtop.mt_count = count;
+ if (mtop.mt_count != count)
+ {
+ report_error_message (N_("Seek offset out of range"));
+ exit (EXIT_FAILURE);
+ }
+ mtop.mt_op = atoi (operation_string);
+
+ if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0)
+ goto ioerror;
+ }
+#endif
+ goto respond;
+ }
+
+ case 'S': /* status */
+ {
+ DEBUG ("rmtd: S\n");
+
+#ifdef MTIOCGET
+ {
+ struct mtget operation;
+
+ if (ioctl (tape, MTIOCGET, (char *) &operation) < 0)
+ goto ioerror;
+ status = sizeof operation;
+ sprintf (reply_buffer, "A%ld\n", (long) status);
+ full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
+ full_write (STDOUT_FILENO, (char *) &operation, sizeof operation);
+ }
+#endif
+ goto top;
+ }
+
+ default:
+ DEBUG1 (_("rmtd: Garbage command %c\n"), command);
+
+ report_error_message (N_("Garbage command"));
+ exit (EXIT_FAILURE); /* exit status used to be 3 */
+ }
+
+respond:
+ DEBUG1 ("rmtd: A %ld\n", (long) status);
+
+ sprintf (reply_buffer, "A%ld\n", (long) status);
+ full_write (STDOUT_FILENO, reply_buffer, strlen (reply_buffer));
+ goto top;
+
+ioerror:
+ report_numbered_error (errno);
+ goto top;
+}
diff --git a/contrib/tar/src/rmt.h b/contrib/tar/src/rmt.h
new file mode 100644
index 0000000..b851045
--- /dev/null
+++ b/contrib/tar/src/rmt.h
@@ -0,0 +1,93 @@
+/* Definitions for communicating with a remote tape drive.
+ Copyright 1988, 1992, 1996, 1997, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+extern char *rmt_path__;
+
+int rmt_open__ PARAMS ((const char *, int, int, const char *));
+int rmt_close__ PARAMS ((int));
+ssize_t rmt_read__ PARAMS ((int, char *, size_t));
+ssize_t rmt_write__ PARAMS ((int, char *, size_t));
+off_t rmt_lseek__ PARAMS ((int, off_t, int));
+int rmt_ioctl__ PARAMS ((int, int, char *));
+
+/* A filename is remote if it contains a colon not preceded by a slash,
+ to take care of `/:/' which is a shorthand for `/.../<CELL-NAME>/fs'
+ on machines running OSF's Distributing Computing Environment (DCE) and
+ Distributed File System (DFS). However, when --force-local, a
+ filename is never remote. */
+
+#define _remdev(Path) \
+ (!force_local_option && (rmt_path__ = strchr (Path, ':')) \
+ && rmt_path__ > (Path) && ! memchr (Path, rmt_path__ - (Path), '/'))
+
+#define _isrmt(Fd) \
+ ((Fd) >= __REM_BIAS)
+
+#define __REM_BIAS (1 << 30)
+
+#ifndef O_CREAT
+# define O_CREAT 01000
+#endif
+
+#define rmtopen(Path, Oflag, Mode, Command) \
+ (_remdev (Path) ? rmt_open__ (Path, Oflag, __REM_BIAS, Command) \
+ : open (Path, Oflag, Mode))
+
+#define rmtaccess(Path, Amode) \
+ (_remdev (Path) ? 0 : access (Path, Amode))
+
+#define rmtstat(Path, Buffer) \
+ (_remdev (Path) ? (errno = EOPNOTSUPP), -1 : stat (Path, Buffer))
+
+#define rmtcreat(Path, Mode, Command) \
+ (_remdev (Path) \
+ ? rmt_open__ (Path, 1 | O_CREAT, __REM_BIAS, Command) \
+ : creat (Path, Mode))
+
+#define rmtlstat(Path, Buffer) \
+ (_remdev (Path) ? (errno = EOPNOTSUPP), -1 : lstat (Path, Buffer))
+
+#define rmtread(Fd, Buffer, Length) \
+ (_isrmt (Fd) ? rmt_read__ (Fd - __REM_BIAS, Buffer, Length) \
+ : safe_read (Fd, Buffer, Length))
+
+#define rmtwrite(Fd, Buffer, Length) \
+ (_isrmt (Fd) ? rmt_write__ (Fd - __REM_BIAS, Buffer, Length) \
+ : full_write (Fd, Buffer, Length))
+
+#define rmtlseek(Fd, Offset, Where) \
+ (_isrmt (Fd) ? rmt_lseek__ (Fd - __REM_BIAS, Offset, Where) \
+ : lseek (Fd, Offset, Where))
+
+#define rmtclose(Fd) \
+ (_isrmt (Fd) ? rmt_close__ (Fd - __REM_BIAS) : close (Fd))
+
+#define rmtioctl(Fd, Request, Argument) \
+ (_isrmt (Fd) ? rmt_ioctl__ (Fd - __REM_BIAS, Request, Argument) \
+ : ioctl (Fd, Request, Argument))
+
+#define rmtdup(Fd) \
+ (_isrmt (Fd) ? (errno = EOPNOTSUPP), -1 : dup (Fd))
+
+#define rmtfstat(Fd, Buffer) \
+ (_isrmt (Fd) ? (errno = EOPNOTSUPP), -1 : fstat (Fd, Buffer))
+
+#define rmtfcntl(Fd, Command, Argument) \
+ (_isrmt (Fd) ? (errno = EOPNOTSUPP), -1 : fcntl (Fd, Command, Argument))
+
+#define rmtisatty(Fd) \
+ (_isrmt (Fd) ? 0 : isatty (Fd))
diff --git a/contrib/tar/src/rtapelib.c b/contrib/tar/src/rtapelib.c
new file mode 100644
index 0000000..ce141b4
--- /dev/null
+++ b/contrib/tar/src/rtapelib.c
@@ -0,0 +1,718 @@
+/* Functions for communicating with a remote tape drive.
+
+ Copyright 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* The man page rmt(8) for /etc/rmt documents the remote mag tape protocol
+ which rdump and rrestore use. Unfortunately, the man page is *WRONG*.
+ The author of the routines I'm including originally wrote his code just
+ based on the man page, and it didn't work, so he went to the rdump source
+ to figure out why. The only thing he had to change was to check for the
+ 'F' return code in addition to the 'E', and to separate the various
+ arguments with \n instead of a space. I personally don't think that this
+ is much of a problem, but I wanted to point it out. -- Arnold Robbins
+
+ Originally written by Jeff Lee, modified some by Arnold Robbins. Redone
+ as a library that can replace open, read, write, etc., by Fred Fish, with
+ some additional work by Arnold Robbins. Modified to make all rmt* calls
+ into macros for speed by Jay Fenlason. Use -DWITH_REXEC for rexec
+ code, courtesy of Dan Kegel. */
+
+#include "system.h"
+
+#include <safe-read.h>
+#include <full-write.h>
+
+/* Try hard to get EOPNOTSUPP defined. 486/ISC has it in net/errno.h,
+ 3B2/SVR3 has it in sys/inet.h. Otherwise, like on MSDOS, use EINVAL. */
+
+#ifndef EOPNOTSUPP
+# if HAVE_NET_ERRNO_H
+# include <net/errno.h>
+# endif
+# if HAVE_SYS_INET_H
+# include <sys/inet.h>
+# endif
+# ifndef EOPNOTSUPP
+# define EOPNOTSUPP EINVAL
+# endif
+#endif
+
+#include <signal.h>
+
+#if HAVE_NETDB_H
+# include <netdb.h>
+#endif
+
+#include "rmt.h"
+
+/* Exit status if exec errors. */
+#define EXIT_ON_EXEC_ERROR 128
+
+/* FIXME: Size of buffers for reading and writing commands to rmt. */
+#define COMMAND_BUFFER_SIZE 64
+
+#ifndef RETSIGTYPE
+# define RETSIGTYPE void
+#endif
+
+/* FIXME: Maximum number of simultaneous remote tape connections. */
+#define MAXUNIT 4
+
+#define PREAD 0 /* read file descriptor from pipe() */
+#define PWRITE 1 /* write file descriptor from pipe() */
+
+/* Return the parent's read side of remote tape connection Fd. */
+#define READ_SIDE(Fd) (from_remote[Fd][PREAD])
+
+/* Return the parent's write side of remote tape connection Fd. */
+#define WRITE_SIDE(Fd) (to_remote[Fd][PWRITE])
+
+/* The pipes for receiving data from remote tape drives. */
+static int from_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
+
+/* The pipes for sending data to remote tape drives. */
+static int to_remote[MAXUNIT][2] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
+
+/* Temporary variable used by macros in rmt.h. */
+char *rmt_path__;
+
+
+/* Close remote tape connection HANDLE, and reset errno to ERRNO_VALUE. */
+static void
+_rmt_shutdown (int handle, int errno_value)
+{
+ close (READ_SIDE (handle));
+ close (WRITE_SIDE (handle));
+ READ_SIDE (handle) = -1;
+ WRITE_SIDE (handle) = -1;
+ errno = errno_value;
+}
+
+/* Attempt to perform the remote tape command specified in BUFFER on
+ remote tape connection HANDLE. Return 0 if successful, -1 on
+ error. */
+static int
+do_command (int handle, const char *buffer)
+{
+ /* Save the current pipe handler and try to make the request. */
+
+ size_t length = strlen (buffer);
+ RETSIGTYPE (*pipe_handler) () = signal (SIGPIPE, SIG_IGN);
+ ssize_t written = full_write (WRITE_SIDE (handle), buffer, length);
+ signal (SIGPIPE, pipe_handler);
+
+ if (written == length)
+ return 0;
+
+ /* Something went wrong. Close down and go home. */
+
+ _rmt_shutdown (handle, EIO);
+ return -1;
+}
+
+static char *
+get_status_string (int handle, char *command_buffer)
+{
+ char *cursor;
+ int counter;
+
+ /* Read the reply command line. */
+
+ for (counter = 0, cursor = command_buffer;
+ counter < COMMAND_BUFFER_SIZE;
+ counter++, cursor++)
+ {
+ if (safe_read (READ_SIDE (handle), cursor, 1) != 1)
+ {
+ _rmt_shutdown (handle, EIO);
+ return 0;
+ }
+ if (*cursor == '\n')
+ {
+ *cursor = '\0';
+ break;
+ }
+ }
+
+ if (counter == COMMAND_BUFFER_SIZE)
+ {
+ _rmt_shutdown (handle, EIO);
+ return 0;
+ }
+
+ /* Check the return status. */
+
+ for (cursor = command_buffer; *cursor; cursor++)
+ if (*cursor != ' ')
+ break;
+
+ if (*cursor == 'E' || *cursor == 'F')
+ {
+ errno = atoi (cursor + 1);
+
+ /* Skip the error message line. */
+
+ /* FIXME: there is better to do than merely ignoring error messages
+ coming from the remote end. Translate them, too... */
+
+ {
+ char character;
+
+ while (safe_read (READ_SIDE (handle), &character, 1) == 1)
+ if (character == '\n')
+ break;
+ }
+
+ if (*cursor == 'F')
+ _rmt_shutdown (handle, errno);
+
+ return 0;
+ }
+
+ /* Check for mis-synced pipes. */
+
+ if (*cursor != 'A')
+ {
+ _rmt_shutdown (handle, EIO);
+ return 0;
+ }
+
+ /* Got an `A' (success) response. */
+
+ return cursor + 1;
+}
+
+/* Read and return the status from remote tape connection HANDLE. If
+ an error occurred, return -1 and set errno. */
+static long
+get_status (int handle)
+{
+ char command_buffer[COMMAND_BUFFER_SIZE];
+ const char *status = get_status_string (handle, command_buffer);
+ return status ? atol (status) : -1L;
+}
+
+static off_t
+get_status_off (int handle)
+{
+ char command_buffer[COMMAND_BUFFER_SIZE];
+ const char *status = get_status_string (handle, command_buffer);
+
+ if (! status)
+ return -1;
+ else
+ {
+ /* Parse status, taking care to check for overflow.
+ We can't use standard functions,
+ since off_t might be longer than long. */
+
+ off_t count = 0;
+ int negative;
+
+ for (; *status == ' ' || *status == '\t'; status++)
+ continue;
+
+ negative = *status == '-';
+ status += negative || *status == '+';
+
+ for (;;)
+ {
+ int digit = *status++ - '0';
+ if (9 < (unsigned) digit)
+ break;
+ else
+ {
+ off_t c10 = 10 * count;
+ off_t nc = negative ? c10 - digit : c10 + digit;
+ if (c10 / 10 != count || (negative ? c10 < nc : nc < c10))
+ return -1;
+ count = nc;
+ }
+ }
+
+ return count;
+ }
+}
+
+#if WITH_REXEC
+
+/* Execute /etc/rmt as user USER on remote system HOST using rexec.
+ Return a file descriptor of a bidirectional socket for stdin and
+ stdout. If USER is zero, use the current username.
+
+ By default, this code is not used, since it requires that the user
+ have a .netrc file in his/her home directory, or that the
+ application designer be willing to have rexec prompt for login and
+ password info. This may be unacceptable, and .rhosts files for use
+ with rsh are much more common on BSD systems. */
+static int
+_rmt_rexec (char *host, char *user)
+{
+ int saved_stdin = dup (STDIN_FILENO);
+ int saved_stdout = dup (STDOUT_FILENO);
+ struct servent *rexecserv;
+ int result;
+
+ /* When using cpio -o < filename, stdin is no longer the tty. But the
+ rexec subroutine reads the login and the passwd on stdin, to allow
+ remote execution of the command. So, reopen stdin and stdout on
+ /dev/tty before the rexec and give them back their original value
+ after. */
+
+ if (! freopen ("/dev/tty", "r", stdin))
+ freopen ("/dev/null", "r", stdin);
+ if (! freopen ("/dev/tty", "w", stdout))
+ freopen ("/dev/null", "w", stdout);
+
+ if (rexecserv = getservbyname ("exec", "tcp"), !rexecserv)
+ error (EXIT_ON_EXEC_ERROR, 0, _("exec/tcp: Service not available"));
+
+ result = rexec (&host, rexecserv->s_port, user, 0, "/etc/rmt", 0);
+ if (fclose (stdin) == EOF)
+ error (0, errno, _("stdin"));
+ fdopen (saved_stdin, "r");
+ if (fclose (stdout) == EOF)
+ error (0, errno, _("stdout"));
+ fdopen (saved_stdout, "w");
+
+ return result;
+}
+
+#endif /* WITH_REXEC */
+
+/* Place into BUF a string representing OFLAG, which must be suitable
+ as argument 2 of `open'. BUF must be large enough to hold the
+ result. This function should generate a string that decode_oflag
+ can parse. */
+static void
+encode_oflag (char *buf, int oflag)
+{
+ sprintf (buf, "%d ", oflag);
+
+ switch (oflag & O_ACCMODE)
+ {
+ case O_RDONLY: strcat (buf, "O_RDONLY"); break;
+ case O_RDWR: strcat (buf, "O_RDWR"); break;
+ case O_WRONLY: strcat (buf, "O_WRONLY"); break;
+ default: abort ();
+ }
+
+#ifdef O_APPEND
+ if (oflag & O_APPEND) strcat (buf, "|O_APPEND");
+#endif
+ if (oflag & O_CREAT) strcat (buf, "|O_CREAT");
+#ifdef O_DSYNC
+ if (oflag & O_DSYNC) strcat (buf, "|O_DSYNC");
+#endif
+ if (oflag & O_EXCL) strcat (buf, "|O_EXCL");
+#ifdef O_LARGEFILE
+ if (oflag & O_LARGEFILE) strcat (buf, "|O_LARGEFILE");
+#endif
+#ifdef O_NOCTTY
+ if (oflag & O_NOCTTY) strcat (buf, "|O_NOCTTY");
+#endif
+#ifdef O_NONBLOCK
+ if (oflag & O_NONBLOCK) strcat (buf, "|O_NONBLOCK");
+#endif
+#ifdef O_RSYNC
+ if (oflag & O_RSYNC) strcat (buf, "|O_RSYNC");
+#endif
+#ifdef O_SYNC
+ if (oflag & O_SYNC) strcat (buf, "|O_SYNC");
+#endif
+ if (oflag & O_TRUNC) strcat (buf, "|O_TRUNC");
+}
+
+/* Open a file (a magnetic tape device?) on the system specified in
+ PATH, as the given user. PATH has the form `[USER@]HOST:FILE'.
+ OPEN_MODE is O_RDONLY, O_WRONLY, etc. If successful, return the
+ remote pipe number plus BIAS. REMOTE_SHELL may be overridden. On
+ error, return -1. */
+int
+rmt_open__ (const char *path, int open_mode, int bias, const char *remote_shell)
+{
+ int remote_pipe_number; /* pseudo, biased file descriptor */
+ char *path_copy ; /* copy of path string */
+ char *remote_host; /* remote host name */
+ char *remote_file; /* remote file name (often a device) */
+ char *remote_user; /* remote user name */
+
+ /* Find an unused pair of file descriptors. */
+
+ for (remote_pipe_number = 0;
+ remote_pipe_number < MAXUNIT;
+ remote_pipe_number++)
+ if (READ_SIDE (remote_pipe_number) == -1
+ && WRITE_SIDE (remote_pipe_number) == -1)
+ break;
+
+ if (remote_pipe_number == MAXUNIT)
+ {
+ errno = EMFILE;
+ return -1;
+ }
+
+ /* Pull apart the system and device, and optional user. */
+
+ {
+ char *cursor;
+
+ path_copy = xstrdup (path);
+ remote_host = path_copy;
+ remote_user = 0;
+ remote_file = 0;
+
+ for (cursor = path_copy; *cursor; cursor++)
+ switch (*cursor)
+ {
+ default:
+ break;
+
+ case '\n':
+ /* Do not allow newlines in the path, since the protocol
+ uses newline delimiters. */
+ free (path_copy);
+ errno = ENOENT;
+ return -1;
+
+ case '@':
+ if (!remote_user)
+ {
+ remote_user = remote_host;
+ *cursor = '\0';
+ remote_host = cursor + 1;
+ }
+ break;
+
+ case ':':
+ if (!remote_file)
+ {
+ *cursor = '\0';
+ remote_file = cursor + 1;
+ }
+ break;
+ }
+ }
+
+ /* FIXME: Should somewhat validate the decoding, here. */
+
+ if (remote_user && *remote_user == '\0')
+ remote_user = 0;
+
+#if WITH_REXEC
+
+ /* Execute the remote command using rexec. */
+
+ READ_SIDE (remote_pipe_number) = _rmt_rexec (remote_host, remote_user);
+ if (READ_SIDE (remote_pipe_number) < 0)
+ {
+ int e = errno;
+ free (path_copy);
+ errno = e;
+ return -1;
+ }
+
+ WRITE_SIDE (remote_pipe_number) = READ_SIDE (remote_pipe_number);
+
+#else /* not WITH_REXEC */
+ {
+ const char *remote_shell_basename;
+ pid_t status;
+
+ /* Identify the remote command to be executed. */
+
+ if (!remote_shell)
+ {
+#ifdef REMOTE_SHELL
+ remote_shell = REMOTE_SHELL;
+#else
+ free (path_copy);
+ errno = EIO;
+ return -1;
+#endif
+ }
+ remote_shell_basename = base_name (remote_shell);
+
+ /* Set up the pipes for the `rsh' command, and fork. */
+
+ if (pipe (to_remote[remote_pipe_number]) == -1
+ || pipe (from_remote[remote_pipe_number]) == -1)
+ {
+ int e = errno;
+ free (path_copy);
+ errno = e;
+ return -1;
+ }
+
+ status = fork ();
+ if (status == -1)
+ {
+ int e = errno;
+ free (path_copy);
+ errno = e;
+ return -1;
+ }
+
+ if (status == 0)
+ {
+ /* Child. */
+
+ close (STDIN_FILENO);
+ dup (to_remote[remote_pipe_number][PREAD]);
+ close (to_remote[remote_pipe_number][PREAD]);
+ close (to_remote[remote_pipe_number][PWRITE]);
+
+ close (STDOUT_FILENO);
+ dup (from_remote[remote_pipe_number][PWRITE]);
+ close (from_remote[remote_pipe_number][PREAD]);
+ close (from_remote[remote_pipe_number][PWRITE]);
+
+#if !MSDOS
+ setuid (getuid ());
+ setgid (getgid ());
+#endif
+
+ if (remote_user)
+ execl (remote_shell, remote_shell_basename, remote_host,
+ "-l", remote_user, "/etc/rmt", (char *) 0);
+ else
+ execl (remote_shell, remote_shell_basename, remote_host,
+ "/etc/rmt", (char *) 0);
+
+ /* Bad problems if we get here. */
+
+ /* In a previous version, _exit was used here instead of exit. */
+ error (EXIT_ON_EXEC_ERROR, errno, _("Cannot execute remote shell"));
+ }
+
+ /* Parent. */
+
+ close (from_remote[remote_pipe_number][PWRITE]);
+ close (to_remote[remote_pipe_number][PREAD]);
+ }
+#endif /* not WITH_REXEC */
+
+ /* Attempt to open the tape device. */
+
+ {
+ size_t remote_file_len = strlen (remote_file);
+ char *command_buffer = xmalloc (remote_file_len + 1000);
+ sprintf (command_buffer, "O%s\n", remote_file);
+ encode_oflag (command_buffer + remote_file_len + 2, open_mode);
+ strcat (command_buffer, "\n");
+ if (do_command (remote_pipe_number, command_buffer) == -1
+ || get_status (remote_pipe_number) == -1)
+ {
+ int e = errno;
+ free (command_buffer);
+ free (path_copy);
+ _rmt_shutdown (remote_pipe_number, e);
+ return -1;
+ }
+ free (command_buffer);
+ }
+
+ free (path_copy);
+ return remote_pipe_number + bias;
+}
+
+/* Close remote tape connection HANDLE and shut down. Return 0 if
+ successful, -1 on error. */
+int
+rmt_close__ (int handle)
+{
+ int status;
+
+ if (do_command (handle, "C\n") == -1)
+ return -1;
+
+ status = get_status (handle);
+ _rmt_shutdown (handle, errno);
+ return status;
+}
+
+/* Read up to LENGTH bytes into BUFFER from remote tape connection HANDLE.
+ Return the number of bytes read on success, -1 on error. */
+ssize_t
+rmt_read__ (int handle, char *buffer, size_t length)
+{
+ char command_buffer[COMMAND_BUFFER_SIZE];
+ ssize_t status, rlen;
+ size_t counter;
+
+ sprintf (command_buffer, "R%lu\n", (unsigned long) length);
+ if (do_command (handle, command_buffer) == -1
+ || (status = get_status (handle)) == -1)
+ return -1;
+
+ for (counter = 0; counter < status; counter += rlen, buffer += rlen)
+ {
+ rlen = safe_read (READ_SIDE (handle), buffer, status - counter);
+ if (rlen <= 0)
+ {
+ _rmt_shutdown (handle, EIO);
+ return -1;
+ }
+ }
+
+ return status;
+}
+
+/* Write LENGTH bytes from BUFFER to remote tape connection HANDLE.
+ Return the number of bytes written on success, -1 on error. */
+ssize_t
+rmt_write__ (int handle, char *buffer, size_t length)
+{
+ char command_buffer[COMMAND_BUFFER_SIZE];
+ RETSIGTYPE (*pipe_handler) ();
+ size_t written;
+
+ sprintf (command_buffer, "W%lu\n", (unsigned long) length);
+ if (do_command (handle, command_buffer) == -1)
+ return -1;
+
+ pipe_handler = signal (SIGPIPE, SIG_IGN);
+ written = full_write (WRITE_SIDE (handle), buffer, length);
+ signal (SIGPIPE, pipe_handler);
+ if (written == length)
+ return get_status (handle);
+
+ /* Write error. */
+
+ _rmt_shutdown (handle, EIO);
+ return -1;
+}
+
+/* Perform an imitation lseek operation on remote tape connection
+ HANDLE. Return the new file offset if successful, -1 if on error. */
+off_t
+rmt_lseek__ (int handle, off_t offset, int whence)
+{
+ char command_buffer[COMMAND_BUFFER_SIZE];
+ char operand_buffer[UINTMAX_STRSIZE_BOUND];
+ uintmax_t u = offset < 0 ? - (uintmax_t) offset : (uintmax_t) offset;
+ char *p = operand_buffer + sizeof operand_buffer;
+
+ do
+ *--p = '0' + (int) (u % 10);
+ while ((u /= 10) != 0);
+ if (offset < 0)
+ *--p = '-';
+
+ switch (whence)
+ {
+ case SEEK_SET: whence = 0; break;
+ case SEEK_CUR: whence = 1; break;
+ case SEEK_END: whence = 2; break;
+ default: abort ();
+ }
+
+ sprintf (command_buffer, "L%s\n%d\n", p, whence);
+
+ if (do_command (handle, command_buffer) == -1)
+ return -1;
+
+ return get_status_off (handle);
+}
+
+/* Perform a raw tape operation on remote tape connection HANDLE.
+ Return the results of the ioctl, or -1 on error. */
+int
+rmt_ioctl__ (int handle, int operation, char *argument)
+{
+ switch (operation)
+ {
+ default:
+ errno = EOPNOTSUPP;
+ return -1;
+
+#ifdef MTIOCTOP
+ case MTIOCTOP:
+ {
+ char command_buffer[COMMAND_BUFFER_SIZE];
+ char operand_buffer[UINTMAX_STRSIZE_BOUND];
+ uintmax_t u = (((struct mtop *) argument)->mt_count < 0
+ ? - (uintmax_t) ((struct mtop *) argument)->mt_count
+ : (uintmax_t) ((struct mtop *) argument)->mt_count);
+ char *p = operand_buffer + sizeof operand_buffer;
+
+ do
+ *--p = '0' + (int) (u % 10);
+ while ((u /= 10) != 0);
+ if (((struct mtop *) argument)->mt_count < 0)
+ *--p = '-';
+
+ /* MTIOCTOP is the easy one. Nothing is transferred in binary. */
+
+ sprintf (command_buffer, "I%d\n%s\n",
+ ((struct mtop *) argument)->mt_op, p);
+ if (do_command (handle, command_buffer) == -1)
+ return -1;
+
+ return get_status (handle);
+ }
+#endif /* MTIOCTOP */
+
+#ifdef MTIOCGET
+ case MTIOCGET:
+ {
+ ssize_t status;
+ ssize_t counter;
+
+ /* Grab the status and read it directly into the structure. This
+ assumes that the status buffer is not padded and that 2 shorts
+ fit in a long without any word alignment problems; i.e., the
+ whole struct is contiguous. NOTE - this is probably NOT a good
+ assumption. */
+
+ if (do_command (handle, "S") == -1
+ || (status = get_status (handle), status == -1))
+ return -1;
+
+ for (; status > 0; status -= counter, argument += counter)
+ {
+ counter = safe_read (READ_SIDE (handle), argument, status);
+ if (counter <= 0)
+ {
+ _rmt_shutdown (handle, EIO);
+ return -1;
+ }
+ }
+
+ /* Check for byte position. mt_type (or mt_model) is a small integer
+ field (normally) so we will check its magnitude. If it is larger
+ than 256, we will assume that the bytes are swapped and go through
+ and reverse all the bytes. */
+
+ if (((struct mtget *) argument)->MTIO_CHECK_FIELD < 256)
+ return 0;
+
+ for (counter = 0; counter < status; counter += 2)
+ {
+ char copy = argument[counter];
+
+ argument[counter] = argument[counter + 1];
+ argument[counter + 1] = copy;
+ }
+
+ return 0;
+ }
+#endif /* MTIOCGET */
+
+ }
+}
diff --git a/contrib/tar/src/system.h b/contrib/tar/src/system.h
new file mode 100644
index 0000000..8e88159
--- /dev/null
+++ b/contrib/tar/src/system.h
@@ -0,0 +1,587 @@
+/* System dependent definitions for GNU tar.
+
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Declare alloca. AIX requires this to be the first thing in the file. */
+
+#if __GNUC__
+# define alloca __builtin_alloca
+#else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca
+char *alloca ();
+# endif
+# endif
+# endif
+#endif
+
+#ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later. */
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
+# define __attribute__(Spec) /* empty */
+# endif
+#endif
+
+#include <sys/types.h>
+#include <ctype.h>
+
+#if HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+#ifndef offsetof
+# define offsetof(type, ident) ((size_t) &((type *) 0)->ident)
+#endif
+
+/* IN_CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given
+ as an argument to <ctype.h> macros like `isspace'. */
+#if STDC_HEADERS
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177)
+#endif
+
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+#define ISODIGIT(c) ((unsigned) (c) - '0' <= 7)
+#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+
+/* Declare string and memory handling routines. Take care that an ANSI
+ string.h and pre-ANSI memory.h might conflict, and that memory.h and
+ strings.h conflict on some systems. */
+
+#if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+#else
+# include <strings.h>
+# ifndef strchr
+# define strchr index
+# endif
+# ifndef strrchr
+# define strrchr rindex
+# endif
+# ifndef memcpy
+# define memcpy(d, s, n) bcopy ((char const *) (s), (char *) (d), n)
+# endif
+# ifndef memcmp
+# define memcmp(a, b, n) bcmp ((char const *) (a), (char const *) (b), n)
+# endif
+#endif
+
+/* Declare errno. */
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+/* Declare open parameters. */
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#else
+# include <sys/file.h>
+#endif
+ /* Pick only one of the next three: */
+#ifndef O_RDONLY
+# define O_RDONLY 0 /* only allow read */
+#endif
+#ifndef O_WRONLY
+# define O_WRONLY 1 /* only allow write */
+#endif
+#ifndef O_RDWR
+# define O_RDWR 2 /* both are allowed */
+#endif
+#ifndef O_ACCMODE
+# define O_ACCMODE (O_RDONLY | O_RDWR | O_WRONLY)
+#endif
+ /* The rest can be OR-ed in to the above: */
+#ifndef O_CREAT
+# define O_CREAT 8 /* create file if needed */
+#endif
+#ifndef O_EXCL
+# define O_EXCL 16 /* file cannot already exist */
+#endif
+#ifndef O_TRUNC
+# define O_TRUNC 32 /* truncate file on open */
+#endif
+ /* MS-DOG forever, with my love! */
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+/* Declare file status routines and bits. */
+
+#include <sys/stat.h>
+
+#if !HAVE_LSTAT && !defined lstat
+# define lstat stat
+#endif
+
+#if STX_HIDDEN && !_LARGE_FILES /* AIX */
+# ifdef stat
+# undef stat
+# endif
+# define stat(path, buf) statx (path, buf, STATSIZE, STX_HIDDEN)
+# ifdef lstat
+# undef lstat
+# endif
+# define lstat(path, buf) statx (path, buf, STATSIZE, STX_HIDDEN | STX_LINK)
+#endif
+
+#if STAT_MACROS_BROKEN
+# undef S_ISBLK
+# undef S_ISCHR
+# undef S_ISCTG
+# undef S_ISDIR
+# undef S_ISFIFO
+# undef S_ISLNK
+# undef S_ISREG
+# undef S_ISSOCK
+#endif
+
+/* On MSDOS, there are missing things from <sys/stat.h>. */
+#if MSDOS
+# define S_ISUID 0
+# define S_ISGID 0
+# define S_ISVTX 0
+#endif
+
+#ifndef S_ISDIR
+# define S_ISDIR(Mode) (((Mode) & S_IFMT) == S_IFDIR)
+#endif
+#ifndef S_ISREG
+# define S_ISREG(Mode) (((Mode) & S_IFMT) == S_IFREG)
+#endif
+
+#ifndef S_ISBLK
+# ifdef S_IFBLK
+# define S_ISBLK(Mode) (((Mode) & S_IFMT) == S_IFBLK)
+# else
+# define S_ISBLK(Mode) 0
+# endif
+#endif
+#ifndef S_ISCHR
+# ifdef S_IFCHR
+# define S_ISCHR(Mode) (((Mode) & S_IFMT) == S_IFCHR)
+# else
+# define S_ISCHR(Mode) 0
+# endif
+#endif
+#ifndef S_ISCTG
+# ifdef S_IFCTG
+# define S_ISCTG(Mode) (((Mode) & S_IFMT) == S_IFCTG)
+# else
+# define S_ISCTG(Mode) 0
+# endif
+#endif
+#ifndef S_ISDOOR
+# define S_ISDOOR(Mode) 0
+#endif
+#ifndef S_ISFIFO
+# ifdef S_IFIFO
+# define S_ISFIFO(Mode) (((Mode) & S_IFMT) == S_IFIFO)
+# else
+# define S_ISFIFO(Mode) 0
+# endif
+#endif
+#ifndef S_ISLNK
+# ifdef S_IFLNK
+# define S_ISLNK(Mode) (((Mode) & S_IFMT) == S_IFLNK)
+# else
+# define S_ISLNK(Mode) 0
+# endif
+#endif
+#ifndef S_ISSOCK
+# ifdef S_IFSOCK
+# define S_ISSOCK(Mode) (((Mode) & S_IFMT) == S_IFSOCK)
+# else
+# define S_ISSOCK(Mode) 0
+# endif
+#endif
+
+#if !HAVE_MKFIFO && !defined mkfifo && defined S_IFIFO
+# define mkfifo(Path, Mode) (mknod (Path, (Mode) | S_IFIFO, 0))
+#endif
+
+#ifndef S_ISUID
+# define S_ISUID 0004000
+#endif
+#ifndef S_ISGID
+# define S_ISGID 0002000
+#endif
+#ifndef S_ISVTX
+# define S_ISVTX 0001000
+#endif
+#ifndef S_IRUSR
+# define S_IRUSR 0000400
+#endif
+#ifndef S_IWUSR
+# define S_IWUSR 0000200
+#endif
+#ifndef S_IXUSR
+# define S_IXUSR 0000100
+#endif
+#ifndef S_IRGRP
+# define S_IRGRP 0000040
+#endif
+#ifndef S_IWGRP
+# define S_IWGRP 0000020
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0000010
+#endif
+#ifndef S_IROTH
+# define S_IROTH 0000004
+#endif
+#ifndef S_IWOTH
+# define S_IWOTH 0000002
+#endif
+#ifndef S_IXOTH
+# define S_IXOTH 0000001
+#endif
+
+#define MODE_WXUSR (S_IWUSR | S_IXUSR)
+#define MODE_R (S_IRUSR | S_IRGRP | S_IROTH)
+#define MODE_RW (S_IWUSR | S_IWGRP | S_IWOTH | MODE_R)
+#define MODE_RWX (S_IXUSR | S_IXGRP | S_IXOTH | MODE_RW)
+#define MODE_ALL (S_ISUID | S_ISGID | S_ISVTX | MODE_RWX)
+
+#ifndef _POSIX_SOURCE
+# include <sys/param.h>
+#endif
+
+/* Include <unistd.h> before any preprocessor test of _POSIX_VERSION. */
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+#ifndef SEEK_CUR
+# define SEEK_CUR 1
+#endif
+#ifndef SEEK_END
+# define SEEK_END 2
+#endif
+
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif
+#ifndef STDERR_FILENO
+# define STDERR_FILENO 2
+#endif
+
+/* Declare make device, major and minor. Since major is a function on
+ SVR4, we have to resort to GOT_MAJOR instead of just testing if
+ major is #define'd. */
+
+#if MAJOR_IN_MKDEV
+# include <sys/mkdev.h>
+# define GOT_MAJOR
+#endif
+
+#if MAJOR_IN_SYSMACROS
+# include <sys/sysmacros.h>
+# define GOT_MAJOR
+#endif
+
+/* Some <sys/types.h> defines the macros. */
+#ifdef major
+# define GOT_MAJOR
+#endif
+
+#ifndef GOT_MAJOR
+# if MSDOS
+# define major(Device) (Device)
+# define minor(Device) (Device)
+# define makedev(Major, Minor) (((Major) << 8) | (Minor))
+# define GOT_MAJOR
+# endif
+#endif
+
+/* For HP-UX before HP-UX 8, major/minor are not in <sys/sysmacros.h>. */
+#ifndef GOT_MAJOR
+# if defined(hpux) || defined(__hpux__) || defined(__hpux)
+# include <sys/mknod.h>
+# define GOT_MAJOR
+# endif
+#endif
+
+#ifndef GOT_MAJOR
+# define major(Device) (((Device) >> 8) & 0xff)
+# define minor(Device) ((Device) & 0xff)
+# define makedev(Major, Minor) (((Major) << 8) | (Minor))
+#endif
+
+#undef GOT_MAJOR
+
+/* Declare wait status. */
+
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(s) (((s) >> 8) & 0xff)
+#endif
+#ifndef WIFSIGNALED
+# define WIFSIGNALED(s) (((s) & 0xffff) - 1 < (unsigned) 0xff)
+#endif
+#ifndef WTERMSIG
+# define WTERMSIG(s) ((s) & 0x7f)
+#endif
+
+/* FIXME: It is wrong to use BLOCKSIZE for buffers when the logical block
+ size is greater than 512 bytes; so ST_BLKSIZE code below, in preparation
+ for some cleanup in this area, later. */
+
+/* Get or fake the disk device blocksize. Usually defined by sys/param.h
+ (if at all). */
+
+#if !defined(DEV_BSIZE) && defined(BSIZE)
+# define DEV_BSIZE BSIZE
+#endif
+#if !defined(DEV_BSIZE) && defined(BBSIZE) /* SGI */
+# define DEV_BSIZE BBSIZE
+#endif
+#ifndef DEV_BSIZE
+# define DEV_BSIZE 4096
+#endif
+
+/* Extract or fake data from a `struct stat'. ST_BLKSIZE gives the
+ optimal I/O blocksize for the file, in bytes. Some systems, like
+ Sequents, return st_blksize of 0 on pipes. */
+
+#if !HAVE_ST_BLKSIZE
+# define ST_BLKSIZE(Statbuf) DEV_BSIZE
+#else
+# define ST_BLKSIZE(Statbuf) \
+ ((Statbuf).st_blksize > 0 ? (Statbuf).st_blksize : DEV_BSIZE)
+#endif
+
+/* Extract or fake data from a `struct stat'. ST_NBLOCKS gives the
+ number of ST_NBLOCKSIZE-byte blocks in the file (including indirect blocks).
+ HP-UX counts st_blocks in 1024-byte units,
+ this loses when mixing HP-UX and BSD filesystems with NFS. AIX PS/2
+ counts st_blocks in 4K units. */
+
+#if !HAVE_ST_BLOCKS
+# if defined(_POSIX_SOURCE) || !defined(BSIZE)
+# define ST_NBLOCKS(Statbuf) ((Statbuf).st_size / ST_NBLOCKSIZE + ((Statbuf).st_size % ST_NBLOCKSIZE != 0))
+# else
+ off_t st_blocks ();
+# define ST_NBLOCKS(Statbuf) (st_blocks ((Statbuf).st_size))
+# endif
+#else
+# define ST_NBLOCKS(Statbuf) ((Statbuf).st_blocks)
+# if defined(hpux) || defined(__hpux__) || defined(__hpux)
+# define ST_NBLOCKSIZE 1024
+# else
+# if defined(_AIX) && defined(_I386)
+# define ST_NBLOCKSIZE (4 * 1024)
+# endif
+# endif
+#endif
+
+#ifndef ST_NBLOCKSIZE
+#define ST_NBLOCKSIZE 512
+#endif
+
+/* This is a real challenge to properly get MTIO* symbols :-(. ISC uses
+ <sys/gentape.h>. SCO and BSDi uses <sys/tape.h>; BSDi also requires
+ <sys/tprintf.h> and <sys/device.h> for defining tp_dev and tpr_t. It
+ seems that the rest use <sys/mtio.h>, which itself requires other files,
+ depending on systems. Pyramid defines _IOW in <sgtty.h>, for example. */
+
+#if HAVE_SYS_GENTAPE_H
+# include <sys/gentape.h>
+#else
+# if HAVE_SYS_TAPE_H
+# if HAVE_SYS_DEVICE_H
+# include <sys/device.h>
+# endif
+# if HAVE_SYS_BUF_H
+# include <sys/buf.h>
+# endif
+# if HAVE_SYS_TPRINTF_H
+# include <sys/tprintf.h>
+# endif
+# include <sys/tape.h>
+# else
+# if HAVE_SYS_MTIO_H
+# include <sys/ioctl.h>
+# if HAVE_SGTTY_H
+# include <sgtty.h>
+# endif
+# if HAVE_SYS_IO_TRIOCTL_H
+# include <sys/io/trioctl.h>
+# endif
+# include <sys/mtio.h>
+# endif
+# endif
+#endif
+
+/* Declare standard functions. */
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+void *malloc ();
+void *realloc ();
+char *getenv ();
+#endif
+
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+typedef enum {false = 0, true = 1} bool;
+#endif
+
+#include <stdio.h>
+
+#ifndef _POSIX_VERSION
+# if MSDOS
+# include <io.h>
+# else
+off_t lseek ();
+# endif
+#endif
+
+#if WITH_DMALLOC
+# undef HAVE_VALLOC
+# define DMALLOC_FUNC_CHECK
+# include <dmalloc.h>
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#ifndef CHAR_BIT
+# define CHAR_BIT 8
+#endif
+
+#ifndef CHAR_MAX
+# define CHAR_MAX TYPE_MAXIMUM (char)
+#endif
+
+#ifndef UCHAR_MAX
+# define UCHAR_MAX TYPE_MAXIMUM (unsigned char)
+#endif
+
+#ifndef LONG_MAX
+# define LONG_MAX TYPE_MAXIMUM (long)
+#endif
+
+#ifndef MB_LEN_MAX
+# define MB_LEN_MAX 1
+#endif
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+/* These macros work even on ones'-complement hosts (!).
+ The extra casts work around common compiler bugs. */
+#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+#define TYPE_MINIMUM(t) (TYPE_SIGNED (t) \
+ ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \
+ : (t) 0)
+#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
+
+/* Bound on length of the string representing an integer value of type t.
+ Subtract one for the sign bit if t is signed;
+ 302 / 1000 is log10 (2) rounded up;
+ add one for integer division truncation;
+ add one more for a minus sign if t is signed. */
+#define INT_STRLEN_BOUND(t) \
+ ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 \
+ + 1 + TYPE_SIGNED (t))
+
+#define UINTMAX_STRSIZE_BOUND (INT_STRLEN_BOUND (uintmax_t) + 1)
+
+/* Prototypes for external functions. */
+
+#ifndef PARAMS
+# if PROTOTYPES
+# define PARAMS(Args) Args
+# else
+# define PARAMS(Args) ()
+# endif
+#endif
+
+#if HAVE_LOCALE_H
+# include <locale.h>
+#endif
+#if !HAVE_SETLOCALE
+# define setlocale(Category, Locale) /* empty */
+#endif
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# undef bindtextdomain
+# define bindtextdomain(Domain, Directory) /* empty */
+# undef textdomain
+# define textdomain(Domain) /* empty */
+# define _(Text) Text
+#endif
+#define N_(Text) Text
+
+#include <time.h>
+#ifndef time
+time_t time ();
+#endif
+
+/* Library modules. */
+
+#include <dirname.h>
+#include <error.h>
+#include <savedir.h>
+#include <xalloc.h>
+
+#if !HAVE_STRSTR
+char *strstr PARAMS ((const char *, const char *));
+#endif
+
+#if HAVE_VALLOC
+# ifndef valloc
+void *valloc ();
+# endif
+#else
+# define valloc(Size) malloc (Size)
+#endif
+
+char *xstrdup PARAMS ((char const *));
diff --git a/contrib/tar/src/tar.c b/contrib/tar/src/tar.c
new file mode 100644
index 0000000..7d87f80
--- /dev/null
+++ b/contrib/tar/src/tar.c
@@ -0,0 +1,1354 @@
+/* A tar (tape archiver) program.
+
+ Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001
+ Free Software Foundation, Inc.
+
+ Written by John Gilmore, starting 1985-08-25.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+
+#include <fnmatch.h>
+#include <getopt.h>
+
+#include <signal.h>
+#if ! defined SIGCHLD && defined SIGCLD
+# define SIGCHLD SIGCLD
+#endif
+
+/* The following causes "common.h" to produce definitions of all the global
+ variables, rather than just "extern" declarations of them. GNU tar does
+ depend on the system loader to preset all GLOBAL variables to neutral (or
+ zero) values; explicit initialization is usually not done. */
+#define GLOBAL
+#include "common.h"
+
+#include <print-copyr.h>
+#include <localedir.h>
+#include <prepargs.h>
+#include <quotearg.h>
+#include <xstrtol.h>
+
+time_t get_date ();
+
+/* Local declarations. */
+
+#ifndef DEFAULT_ARCHIVE
+# define DEFAULT_ARCHIVE "tar.out"
+#endif
+
+#ifndef DEFAULT_BLOCKING
+# define DEFAULT_BLOCKING 20
+#endif
+
+static void usage PARAMS ((int)) __attribute__ ((noreturn));
+
+/* Miscellaneous. */
+
+/* Name of option using stdin. */
+static const char *stdin_used_by;
+
+/* Doesn't return if stdin already requested. */
+void
+request_stdin (const char *option)
+{
+ if (stdin_used_by)
+ USAGE_ERROR ((0, 0, _("Options `-%s' and `-%s' both want standard input"),
+ stdin_used_by, option));
+
+ stdin_used_by = option;
+}
+
+/* Returns true if and only if the user typed 'y' or 'Y'. */
+int
+confirm (const char *message_action, const char *message_name)
+{
+ static FILE *confirm_file;
+ static int confirm_file_EOF;
+
+ if (!confirm_file)
+ {
+ if (archive == 0 || stdin_used_by)
+ {
+ confirm_file = fopen (TTY_NAME, "r");
+ if (! confirm_file)
+ open_fatal (TTY_NAME);
+ }
+ else
+ {
+ request_stdin ("-w");
+ confirm_file = stdin;
+ }
+ }
+
+ fprintf (stdlis, "%s %s?", message_action, quote (message_name));
+ fflush (stdlis);
+
+ {
+ int reply = confirm_file_EOF ? EOF : getc (confirm_file);
+ int character;
+
+ for (character = reply;
+ character != '\n';
+ character = getc (confirm_file))
+ if (character == EOF)
+ {
+ confirm_file_EOF = 1;
+ fputc ('\n', stdlis);
+ fflush (stdlis);
+ break;
+ }
+ return reply == 'y' || reply == 'Y';
+ }
+}
+
+/* Options. */
+
+/* For long options that unconditionally set a single flag, we have getopt
+ do it. For the others, we share the code for the equivalent short
+ named option, the name of which is stored in the otherwise-unused `val'
+ field of the `struct option'; for long options that have no equivalent
+ short option, we use non-characters as pseudo short options,
+ starting at CHAR_MAX + 1 and going upwards. */
+
+enum
+{
+ ANCHORED_OPTION = CHAR_MAX + 1,
+ BACKUP_OPTION,
+ DELETE_OPTION,
+ EXCLUDE_OPTION,
+ GROUP_OPTION,
+ IGNORE_CASE_OPTION,
+ MODE_OPTION,
+ NEWER_MTIME_OPTION,
+ NO_ANCHORED_OPTION,
+ NO_IGNORE_CASE_OPTION,
+ NO_WILDCARDS_OPTION,
+ NO_WILDCARDS_MATCH_SLASH_OPTION,
+ NULL_OPTION,
+ OVERWRITE_OPTION,
+ OVERWRITE_DIR_OPTION,
+ OWNER_OPTION,
+ POSIX_OPTION,
+ PRESERVE_OPTION,
+ RECORD_SIZE_OPTION,
+ RSH_COMMAND_OPTION,
+ SUFFIX_OPTION,
+ USE_COMPRESS_PROGRAM_OPTION,
+ VOLNO_FILE_OPTION,
+ WILDCARDS_OPTION,
+ WILDCARDS_MATCH_SLASH_OPTION,
+
+ /* Some cleanup is being made in GNU tar long options. Using old names is
+ allowed for a while, but will also send a warning to stderr. Take old
+ names out in 1.14, or in summer 1997, whichever happens last. */
+
+ OBSOLETE_ABSOLUTE_NAMES,
+ OBSOLETE_BLOCK_COMPRESS,
+ OBSOLETE_BLOCKING_FACTOR,
+ OBSOLETE_BLOCK_NUMBER,
+ OBSOLETE_READ_FULL_RECORDS,
+ OBSOLETE_TOUCH,
+ OBSOLETE_VERSION_CONTROL
+};
+
+/* If nonzero, display usage information and exit. */
+static int show_help;
+
+/* If nonzero, print the version on standard output and exit. */
+static int show_version;
+
+static struct option long_options[] =
+{
+ {"absolute-names", no_argument, 0, 'P'},
+ {"absolute-paths", no_argument, 0, OBSOLETE_ABSOLUTE_NAMES},
+ {"after-date", required_argument, 0, 'N'},
+ {"anchored", no_argument, 0, ANCHORED_OPTION},
+ {"append", no_argument, 0, 'r'},
+ {"atime-preserve", no_argument, &atime_preserve_option, 1},
+ {"backup", optional_argument, 0, BACKUP_OPTION},
+ {"block-compress", no_argument, 0, OBSOLETE_BLOCK_COMPRESS},
+ {"block-number", no_argument, 0, 'R'},
+ {"block-size", required_argument, 0, OBSOLETE_BLOCKING_FACTOR},
+ {"blocking-factor", required_argument, 0, 'b'},
+ {"bzip2", no_argument, 0, 'j'},
+ {"catenate", no_argument, 0, 'A'},
+ {"checkpoint", no_argument, &checkpoint_option, 1},
+ {"compare", no_argument, 0, 'd'},
+ {"compress", no_argument, 0, 'Z'},
+ {"concatenate", no_argument, 0, 'A'},
+ {"confirmation", no_argument, 0, 'w'},
+ /* FIXME: --selective as a synonym for --confirmation? */
+ {"create", no_argument, 0, 'c'},
+ {"delete", no_argument, 0, DELETE_OPTION},
+ {"dereference", no_argument, 0, 'h'},
+ {"diff", no_argument, 0, 'd'},
+ {"directory", required_argument, 0, 'C'},
+ {"exclude", required_argument, 0, EXCLUDE_OPTION},
+ {"exclude-from", required_argument, 0, 'X'},
+ {"extract", no_argument, 0, 'x'},
+ {"file", required_argument, 0, 'f'},
+ {"files-from", required_argument, 0, 'T'},
+ {"force-local", no_argument, &force_local_option, 1},
+ {"get", no_argument, 0, 'x'},
+ {"group", required_argument, 0, GROUP_OPTION},
+ {"gunzip", no_argument, 0, 'z'},
+ {"gzip", no_argument, 0, 'z'},
+ {"help", no_argument, &show_help, 1},
+ {"ignore-case", no_argument, 0, IGNORE_CASE_OPTION},
+ {"ignore-failed-read", no_argument, &ignore_failed_read_option, 1},
+ {"ignore-zeros", no_argument, 0, 'i'},
+ /* FIXME: --ignore-end as a new name for --ignore-zeros? */
+ {"incremental", no_argument, 0, 'G'},
+ {"info-script", required_argument, 0, 'F'},
+ {"interactive", no_argument, 0, 'w'},
+ {"keep-old-files", no_argument, 0, 'k'},
+ {"label", required_argument, 0, 'V'},
+ {"list", no_argument, 0, 't'},
+ {"listed-incremental", required_argument, 0, 'g'},
+ {"mode", required_argument, 0, MODE_OPTION},
+ {"modification-time", no_argument, 0, OBSOLETE_TOUCH},
+ {"multi-volume", no_argument, 0, 'M'},
+ {"new-volume-script", required_argument, 0, 'F'},
+ {"newer", required_argument, 0, 'N'},
+ {"newer-mtime", required_argument, 0, NEWER_MTIME_OPTION},
+ {"null", no_argument, 0, NULL_OPTION},
+ {"no-anchored", no_argument, 0, NO_ANCHORED_OPTION},
+ {"no-ignore-case", no_argument, 0, NO_IGNORE_CASE_OPTION},
+ {"no-wildcards", no_argument, 0, NO_WILDCARDS_OPTION},
+ {"no-wildcards-match-slash", no_argument, 0, NO_WILDCARDS_MATCH_SLASH_OPTION},
+ {"no-recursion", no_argument, &recursion_option, 0},
+ {"no-same-owner", no_argument, &same_owner_option, -1},
+ {"no-same-permissions", no_argument, &same_permissions_option, -1},
+ {"numeric-owner", no_argument, &numeric_owner_option, 1},
+ {"old-archive", no_argument, 0, 'o'},
+ {"one-file-system", no_argument, 0, 'l'},
+ {"overwrite", no_argument, 0, OVERWRITE_OPTION},
+ {"overwrite-dir", no_argument, 0, OVERWRITE_DIR_OPTION},
+ {"owner", required_argument, 0, OWNER_OPTION},
+ {"portability", no_argument, 0, 'o'},
+ {"posix", no_argument, 0, POSIX_OPTION},
+ {"preserve", no_argument, 0, PRESERVE_OPTION},
+ {"preserve-order", no_argument, 0, 's'},
+ {"preserve-permissions", no_argument, 0, 'p'},
+ {"recursion", no_argument, &recursion_option, FNM_LEADING_DIR},
+ {"recursive-unlink", no_argument, &recursive_unlink_option, 1},
+ {"read-full-blocks", no_argument, 0, OBSOLETE_READ_FULL_RECORDS},
+ {"read-full-records", no_argument, 0, 'B'},
+ /* FIXME: --partial-blocks might be a synonym for --read-full-records? */
+ {"record-number", no_argument, 0, OBSOLETE_BLOCK_NUMBER},
+ {"record-size", required_argument, 0, RECORD_SIZE_OPTION},
+ {"remove-files", no_argument, &remove_files_option, 1},
+ {"rsh-command", required_argument, 0, RSH_COMMAND_OPTION},
+ {"same-order", no_argument, 0, 's'},
+ {"same-owner", no_argument, &same_owner_option, 1},
+ {"same-permissions", no_argument, 0, 'p'},
+ {"show-omitted-dirs", no_argument, &show_omitted_dirs_option, 1},
+ {"sparse", no_argument, 0, 'S'},
+ {"starting-file", required_argument, 0, 'K'},
+ {"suffix", required_argument, 0, SUFFIX_OPTION},
+ {"tape-length", required_argument, 0, 'L'},
+ {"to-stdout", no_argument, 0, 'O'},
+ {"totals", no_argument, &totals_option, 1},
+ {"touch", no_argument, 0, 'm'},
+ {"uncompress", no_argument, 0, 'Z'},
+ {"ungzip", no_argument, 0, 'z'},
+ {"unlink-first", no_argument, 0, 'U'},
+ {"update", no_argument, 0, 'u'},
+ {"use-compress-program", required_argument, 0, USE_COMPRESS_PROGRAM_OPTION},
+ {"verbose", no_argument, 0, 'v'},
+ {"verify", no_argument, 0, 'W'},
+ {"version", no_argument, &show_version, 1},
+ {"version-control", required_argument, 0, OBSOLETE_VERSION_CONTROL},
+ {"volno-file", required_argument, 0, VOLNO_FILE_OPTION},
+ {"wildcards", no_argument, 0, WILDCARDS_OPTION},
+ {"wildcards-match-slash", no_argument, 0, WILDCARDS_MATCH_SLASH_OPTION},
+
+ {0, 0, 0, 0}
+};
+
+/* Print a usage message and exit with STATUS. */
+static void
+usage (int status)
+{
+ if (status != TAREXIT_SUCCESS)
+ fprintf (stderr, _("Try `%s --help' for more information.\n"),
+ program_name);
+ else
+ {
+ fputs (_("\
+GNU `tar' saves many files together into a single tape or disk archive, and\n\
+can restore individual files from the archive.\n"),
+ stdout);
+ printf (_("\nUsage: %s [OPTION]... [FILE]...\n\
+\n\
+Examples:\n\
+ %s -cf archive.tar foo bar # Create archive.tar from files foo and bar.\n\
+ %s -tvf archive.tar # List all files in archive.tar verbosely.\n\
+ %s -xf archive.tar # Extract all files from archive.tar.\n"),
+ program_name, program_name, program_name, program_name);
+ fputs (_("\
+\n\
+If a long option shows an argument as mandatory, then it is mandatory\n\
+for the equivalent short option also. Similarly for optional arguments.\n"),
+ stdout);
+ fputs(_("\
+\n\
+Main operation mode:\n\
+ -t, --list list the contents of an archive\n\
+ -x, --extract, --get extract files from an archive\n\
+ -c, --create create a new archive\n\
+ -d, --diff, --compare find differences between archive and file system\n\
+ -r, --append append files to the end of an archive\n\
+ -u, --update only append files newer than copy in archive\n\
+ -A, --catenate append tar files to an archive\n\
+ --concatenate same as -A\n\
+ --delete delete from the archive (not on mag tapes!)\n"),
+ stdout);
+ fputs (_("\
+\n\
+Operation modifiers:\n\
+ -W, --verify attempt to verify the archive after writing it\n\
+ --remove-files remove files after adding them to the archive\n\
+ -k, --keep-old-files don't replace existing files when extracting\n\
+ --overwrite overwrite existing files when extracting\n\
+ --overwrite-dir overwrite directory metadata when extracting\n\
+ -U, --unlink-first remove each file prior to extracting over it\n\
+ --recursive-unlink empty hierarchies prior to extracting directory\n\
+ -S, --sparse handle sparse files efficiently\n\
+ -O, --to-stdout extract files to standard output\n\
+ -G, --incremental handle old GNU-format incremental backup\n\
+ -g, --listed-incremental=FILE\n\
+ handle new GNU-format incremental backup\n\
+ --ignore-failed-read do not exit with nonzero on unreadable files\n"),
+ stdout);
+ fputs (_("\
+\n\
+Handling of file attributes:\n\
+ --owner=NAME force NAME as owner for added files\n\
+ --group=NAME force NAME as group for added files\n\
+ --mode=CHANGES force (symbolic) mode CHANGES for added files\n\
+ --atime-preserve don't change access times on dumped files\n\
+ -m, --modification-time don't extract file modified time\n\
+ --same-owner try extracting files with the same ownership\n\
+ --no-same-owner extract files as yourself\n\
+ --numeric-owner always use numbers for user/group names\n\
+ -p, --same-permissions extract permissions information\n\
+ --no-same-permissions do not extract permissions information\n\
+ --preserve-permissions same as -p\n\
+ -s, --same-order sort names to extract to match archive\n\
+ --preserve-order same as -s\n\
+ --preserve same as both -p and -s\n"),
+ stdout);
+ fputs (_("\
+\n\
+Device selection and switching:\n\
+ -f, --file=ARCHIVE use archive file or device ARCHIVE\n\
+ --force-local archive file is local even if has a colon\n\
+ --rsh-command=COMMAND use remote COMMAND instead of rsh\n\
+ -[0-7][lmh] specify drive and density\n\
+ -M, --multi-volume create/list/extract multi-volume archive\n\
+ -L, --tape-length=NUM change tape after writing NUM x 1024 bytes\n\
+ -F, --info-script=FILE run script at end of each tape (implies -M)\n\
+ --new-volume-script=FILE same as -F FILE\n\
+ --volno-file=FILE use/update the volume number in FILE\n"),
+ stdout);
+ fputs (_("\
+\n\
+Device blocking:\n\
+ -b, --blocking-factor=BLOCKS BLOCKS x 512 bytes per record\n\
+ --record-size=SIZE SIZE bytes per record, multiple of 512\n\
+ -i, --ignore-zeros ignore zeroed blocks in archive (means EOF)\n\
+ -B, --read-full-records reblock as we read (for 4.2BSD pipes)\n"),
+ stdout);
+ fputs (_("\
+\n\
+Archive format selection:\n\
+ -V, --label=NAME create archive with volume name NAME\n\
+ PATTERN at list/extract time, a globbing PATTERN\n\
+ -o, --old-archive, --portability write a V7 format archive\n\
+ --posix write a POSIX format archive\n\
+ -j, --bzip2 filter the archive through bzip2\n\
+ -z, --gzip, --ungzip filter the archive through gzip\n\
+ -Z, --compress, --uncompress filter the archive through compress\n\
+ --use-compress-program=PROG filter through PROG (must accept -d)\n"),
+ stdout);
+ fputs (_("\
+\n\
+Local file selection:\n\
+ -C, --directory=DIR change to directory DIR\n\
+ -T, --files-from=NAME get names to extract or create from file NAME\n\
+ --null -T reads null-terminated names, disable -C\n\
+ --exclude=PATTERN exclude files, given as a PATTERN\n\
+ -X, --exclude-from=FILE exclude patterns listed in FILE\n\
+ --anchored exclude patterns match file name start (default)\n\
+ --no-anchored exclude patterns match after any /\n\
+ --ignore-case exclusion ignores case\n\
+ --no-ignore-case exclusion is case sensitive (default)\n\
+ --wildcards exclude patterns use wildcards (default)\n\
+ --no-wildcards exclude patterns are plain strings\n\
+ --wildcards-match-slash exclude pattern wildcards match '/' (default)\n\
+ --no-wildcards-match-slash exclude pattern wildcards do not match '/'\n\
+ -P, --absolute-names don't strip leading `/'s from file names\n\
+ -h, --dereference dump instead the files symlinks point to\n\
+ --no-recursion avoid descending automatically in directories\n\
+ -l, --one-file-system stay in local file system when creating archive\n\
+ -K, --starting-file=NAME begin at file NAME in the archive\n"),
+ stdout);
+#if !MSDOS
+ fputs (_("\
+ -N, --newer=DATE only store files newer than DATE\n\
+ --newer-mtime=DATE compare date and time when data changed only\n\
+ --after-date=DATE same as -N\n"),
+ stdout);
+#endif
+ fputs (_("\
+ --backup[=CONTROL] backup before removal, choose version control\n\
+ --suffix=SUFFIX backup before removal, override usual suffix\n"),
+ stdout);
+ fputs (_("\
+\n\
+Informative output:\n\
+ --help print this help, then exit\n\
+ --version print tar program version number, then exit\n\
+ -v, --verbose verbosely list files processed\n\
+ --checkpoint print directory names while reading the archive\n\
+ --totals print total bytes written while creating archive\n\
+ -R, --block-number show block number within archive with each message\n\
+ -w, --interactive ask for confirmation for every action\n\
+ --confirmation same as -w\n"),
+ stdout);
+ fputs (_("\
+\n\
+The backup suffix is `~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
+The version control may be set with --backup or VERSION_CONTROL, values are:\n\
+\n\
+ t, numbered make numbered backups\n\
+ nil, existing numbered if numbered backups exist, simple otherwise\n\
+ never, simple always make simple backups\n"),
+ stdout);
+ printf (_("\
+\n\
+GNU tar cannot read nor produce `--posix' archives. If POSIXLY_CORRECT\n\
+is set in the environment, GNU extensions are disallowed with `--posix'.\n\
+Support for POSIX is only partially implemented, don't count on it yet.\n\
+ARCHIVE may be FILE, HOST:FILE or USER@HOST:FILE; DATE may be a textual date\n\
+or a file name starting with `/' or `.', in which case the file's date is used.\n\
+*This* `tar' defaults to `-f%s -b%d'.\n"),
+ DEFAULT_ARCHIVE, DEFAULT_BLOCKING);
+ fputs (_("\nReport bugs to <bug-tar@gnu.org>.\n"), stdout);
+ }
+ exit (status);
+}
+
+/* Parse the options for tar. */
+
+/* Available option letters are DEHIJQY and aenqy. Some are reserved:
+
+ e exit immediately with a nonzero exit status if unexpected errors occur
+ E use extended headers (draft POSIX headers, that is)
+ I same as T (for compatibility with Solaris tar)
+ n the archive is quickly seekable, so don't worry about random seeks
+ q stop after extracting the first occurrence of the named file
+ y per-file gzip compression
+ Y per-block gzip compression */
+
+#define OPTION_STRING \
+ "-01234567ABC:F:GIK:L:MN:OPRST:UV:WX:Zb:cdf:g:hijklmoprstuvwxyz"
+
+static void
+set_subcommand_option (enum subcommand subcommand)
+{
+ if (subcommand_option != UNKNOWN_SUBCOMMAND
+ && subcommand_option != subcommand)
+ USAGE_ERROR ((0, 0,
+ _("You may not specify more than one `-Acdtrux' option")));
+
+ subcommand_option = subcommand;
+}
+
+static void
+set_use_compress_program_option (const char *string)
+{
+ if (use_compress_program_option && strcmp (use_compress_program_option, string) != 0)
+ USAGE_ERROR ((0, 0, _("Conflicting compression options")));
+
+ use_compress_program_option = string;
+}
+
+static void
+decode_options (int argc, char **argv)
+{
+ int optchar; /* option letter */
+ int input_files; /* number of input files */
+ const char *backup_suffix_string;
+ const char *version_control_string = 0;
+ int exclude_options = EXCLUDE_WILDCARDS;
+
+ /* Set some default option values. */
+
+ subcommand_option = UNKNOWN_SUBCOMMAND;
+ archive_format = DEFAULT_FORMAT;
+ blocking_factor = DEFAULT_BLOCKING;
+ record_size = DEFAULT_BLOCKING * BLOCKSIZE;
+ excluded = new_exclude ();
+ newer_mtime_option = TYPE_MINIMUM (time_t);
+ recursion_option = FNM_LEADING_DIR;
+
+ owner_option = -1;
+ group_option = -1;
+
+ backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
+
+ /* Convert old-style tar call by exploding option element and rearranging
+ options accordingly. */
+
+ if (argc > 1 && argv[1][0] != '-')
+ {
+ int new_argc; /* argc value for rearranged arguments */
+ char **new_argv; /* argv value for rearranged arguments */
+ char *const *in; /* cursor into original argv */
+ char **out; /* cursor into rearranged argv */
+ const char *letter; /* cursor into old option letters */
+ char buffer[3]; /* constructed option buffer */
+ const char *cursor; /* cursor in OPTION_STRING */
+
+ /* Initialize a constructed option. */
+
+ buffer[0] = '-';
+ buffer[2] = '\0';
+
+ /* Allocate a new argument array, and copy program name in it. */
+
+ new_argc = argc - 1 + strlen (argv[1]);
+ new_argv = xmalloc (new_argc * sizeof (char *));
+ in = argv;
+ out = new_argv;
+ *out++ = *in++;
+
+ /* Copy each old letter option as a separate option, and have the
+ corresponding argument moved next to it. */
+
+ for (letter = *in++; *letter; letter++)
+ {
+ buffer[1] = *letter;
+ *out++ = xstrdup (buffer);
+ cursor = strchr (OPTION_STRING, *letter);
+ if (cursor && cursor[1] == ':')
+ {
+ if (in < argv + argc)
+ *out++ = *in++;
+ else
+ USAGE_ERROR ((0, 0, _("Old option `%c' requires an argument."),
+ *letter));
+ }
+ }
+
+ /* Copy all remaining options. */
+
+ while (in < argv + argc)
+ *out++ = *in++;
+
+ /* Replace the old option list by the new one. */
+
+ argc = new_argc;
+ argv = new_argv;
+ }
+
+ /* Parse all options and non-options as they appear. */
+
+ input_files = 0;
+
+ prepend_default_options (getenv ("TAR_OPTIONS"), &argc, &argv);
+
+ while (optchar = getopt_long (argc, argv, OPTION_STRING, long_options, 0),
+ optchar != -1)
+ switch (optchar)
+ {
+ case '?':
+ usage (TAREXIT_FAILURE);
+
+ case 0:
+ break;
+
+ case 1:
+ /* File name or non-parsed option, because of RETURN_IN_ORDER
+ ordering triggered by the leading dash in OPTION_STRING. */
+
+ name_add (optarg);
+ input_files++;
+ break;
+
+ case 'A':
+ set_subcommand_option (CAT_SUBCOMMAND);
+ break;
+
+ case OBSOLETE_BLOCK_COMPRESS:
+ WARN ((0, 0, _("Obsolete option, now implied by --blocking-factor")));
+ break;
+
+ case OBSOLETE_BLOCKING_FACTOR:
+ WARN ((0, 0, _("Obsolete option name replaced by --blocking-factor")));
+ /* Fall through. */
+
+ case 'b':
+ {
+ uintmax_t u;
+ if (! (xstrtoumax (optarg, 0, 10, &u, "") == LONGINT_OK
+ && u == (blocking_factor = u)
+ && 0 < blocking_factor
+ && u == (record_size = u * BLOCKSIZE) / BLOCKSIZE))
+ USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+ _("Invalid blocking factor")));
+ }
+ break;
+
+ case OBSOLETE_READ_FULL_RECORDS:
+ WARN ((0, 0,
+ _("Obsolete option name replaced by --read-full-records")));
+ /* Fall through. */
+
+ case 'B':
+ /* Try to reblock input records. For reading 4.2BSD pipes. */
+
+ /* It would surely make sense to exchange -B and -R, but it seems
+ that -B has been used for a long while in Sun tar ans most
+ BSD-derived systems. This is a consequence of the block/record
+ terminology confusion. */
+
+ read_full_records_option = 1;
+ break;
+
+ case 'c':
+ set_subcommand_option (CREATE_SUBCOMMAND);
+ break;
+
+ case 'C':
+ name_add ("-C");
+ name_add (optarg);
+ break;
+
+ case 'd':
+ set_subcommand_option (DIFF_SUBCOMMAND);
+ break;
+
+ case 'f':
+ if (archive_names == allocated_archive_names)
+ {
+ allocated_archive_names *= 2;
+ archive_name_array =
+ xrealloc (archive_name_array,
+ sizeof (const char *) * allocated_archive_names);
+ }
+ archive_name_array[archive_names++] = optarg;
+ break;
+
+ case 'F':
+ /* Since -F is only useful with -M, make it implied. Run this
+ script at the end of each tape. */
+
+ info_script_option = optarg;
+ multi_volume_option = 1;
+ break;
+
+ case 'g':
+ listed_incremental_option = optarg;
+ after_date_option = 1;
+ /* Fall through. */
+
+ case 'G':
+ /* We are making an incremental dump (FIXME: are we?); save
+ directories at the beginning of the archive, and include in each
+ directory its contents. */
+
+ incremental_option = 1;
+ break;
+
+ case 'h':
+ /* Follow symbolic links. */
+
+ dereference_option = 1;
+ break;
+
+ case 'i':
+ /* Ignore zero blocks (eofs). This can't be the default,
+ because Unix tar writes two blocks of zeros, then pads out
+ the record with garbage. */
+
+ ignore_zeros_option = 1;
+ break;
+
+ case 'I':
+ USAGE_ERROR ((0, 0,
+ _("Warning: the -I option is not supported;"
+ " perhaps you meant -j or -T?")));
+ break;
+
+ case 'j':
+ set_use_compress_program_option ("bzip2");
+ break;
+
+ case 'k':
+ /* Don't replace existing files. */
+ old_files_option = KEEP_OLD_FILES;
+ break;
+
+ case 'K':
+ starting_file_option = 1;
+ addname (optarg, 0);
+ break;
+
+ case 'l':
+ /* When dumping directories, don't dump files/subdirectories
+ that are on other filesystems. */
+
+ one_file_system_option = 1;
+ break;
+
+ case 'L':
+ {
+ uintmax_t u;
+ if (xstrtoumax (optarg, 0, 10, &u, "") != LONGINT_OK)
+ USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+ _("Invalid tape length")));
+ tape_length_option = 1024 * (tarlong) u;
+ multi_volume_option = 1;
+ }
+ break;
+
+ case OBSOLETE_TOUCH:
+ WARN ((0, 0, _("Obsolete option name replaced by --touch")));
+ /* Fall through. */
+
+ case 'm':
+ touch_option = 1;
+ break;
+
+ case 'M':
+ /* Make multivolume archive: when we can't write any more into
+ the archive, re-open it, and continue writing. */
+
+ multi_volume_option = 1;
+ break;
+
+#if !MSDOS
+ case 'N':
+ after_date_option = 1;
+ /* Fall through. */
+
+ case NEWER_MTIME_OPTION:
+ if (newer_mtime_option != TYPE_MINIMUM (time_t))
+ USAGE_ERROR ((0, 0, _("More than one threshold date")));
+
+ if (FILESYSTEM_PREFIX_LEN (optarg) != 0
+ || ISSLASH (*optarg)
+ || *optarg == '.')
+ {
+ struct stat st;
+ if (deref_stat (dereference_option, optarg, &st) != 0)
+ {
+ stat_error (optarg);
+ USAGE_ERROR ((0, 0, _("Date file not found")));
+ }
+ newer_mtime_option = st.st_mtime;
+ }
+ else
+ {
+ newer_mtime_option = get_date (optarg, 0);
+ if (newer_mtime_option == (time_t) -1)
+ WARN ((0, 0, _("Substituting %s for unknown date format %s"),
+ tartime (newer_mtime_option), quote (optarg)));
+ }
+
+ break;
+#endif /* not MSDOS */
+
+ case 'o':
+ if (archive_format == DEFAULT_FORMAT)
+ archive_format = V7_FORMAT;
+ else if (archive_format != V7_FORMAT)
+ USAGE_ERROR ((0, 0, _("Conflicting archive format options")));
+ break;
+
+ case 'O':
+ to_stdout_option = 1;
+ break;
+
+ case 'p':
+ same_permissions_option = 1;
+ break;
+
+ case OBSOLETE_ABSOLUTE_NAMES:
+ WARN ((0, 0, _("Obsolete option name replaced by --absolute-names")));
+ /* Fall through. */
+
+ case 'P':
+ absolute_names_option = 1;
+ break;
+
+ case 'r':
+ set_subcommand_option (APPEND_SUBCOMMAND);
+ break;
+
+ case OBSOLETE_BLOCK_NUMBER:
+ WARN ((0, 0, _("Obsolete option name replaced by --block-number")));
+ /* Fall through. */
+
+ case 'R':
+ /* Print block numbers for debugging bad tar archives. */
+
+ /* It would surely make sense to exchange -B and -R, but it seems
+ that -B has been used for a long while in Sun tar ans most
+ BSD-derived systems. This is a consequence of the block/record
+ terminology confusion. */
+
+ block_number_option = 1;
+ break;
+
+ case 's':
+ /* Names to extr are sorted. */
+
+ same_order_option = 1;
+ break;
+
+ case 'S':
+ sparse_option = 1;
+ break;
+
+ case 't':
+ set_subcommand_option (LIST_SUBCOMMAND);
+ verbose_option++;
+ break;
+
+ case 'T':
+ files_from_option = optarg;
+ break;
+
+ case 'u':
+ set_subcommand_option (UPDATE_SUBCOMMAND);
+ break;
+
+ case 'U':
+ old_files_option = UNLINK_FIRST_OLD_FILES;
+ break;
+
+ case 'v':
+ verbose_option++;
+ break;
+
+ case 'V':
+ volume_label_option = optarg;
+ break;
+
+ case 'w':
+ interactive_option = 1;
+ break;
+
+ case 'W':
+ verify_option = 1;
+ break;
+
+ case 'x':
+ set_subcommand_option (EXTRACT_SUBCOMMAND);
+ break;
+
+ case 'X':
+ if (add_exclude_file (add_exclude, excluded, optarg,
+ exclude_options | recursion_option, '\n')
+ != 0)
+ {
+ int e = errno;
+ FATAL_ERROR ((0, e, "%s", quotearg_colon (optarg)));
+ }
+ break;
+
+ case 'y':
+ USAGE_ERROR ((0, 0,
+ _("Warning: the -y option is not supported;"
+ " perhaps you meant -j?")));
+ break;
+
+ case 'z':
+ set_use_compress_program_option ("gzip");
+ break;
+
+ case 'Z':
+ set_use_compress_program_option ("compress");
+ break;
+
+ case OBSOLETE_VERSION_CONTROL:
+ WARN ((0, 0, _("Obsolete option name replaced by --backup")));
+ /* Fall through. */
+
+ case ANCHORED_OPTION:
+ exclude_options |= EXCLUDE_ANCHORED;
+ break;
+
+ case BACKUP_OPTION:
+ backup_option = 1;
+ if (optarg)
+ version_control_string = optarg;
+ break;
+
+ case DELETE_OPTION:
+ set_subcommand_option (DELETE_SUBCOMMAND);
+ break;
+
+ case EXCLUDE_OPTION:
+ add_exclude (excluded, optarg, exclude_options | recursion_option);
+ break;
+
+ case IGNORE_CASE_OPTION:
+ exclude_options |= FNM_CASEFOLD;
+ break;
+
+ case GROUP_OPTION:
+ if (! (strlen (optarg) < GNAME_FIELD_SIZE
+ && gname_to_gid (optarg, &group_option)))
+ {
+ uintmax_t g;
+ if (xstrtoumax (optarg, 0, 10, &g, "") == LONGINT_OK
+ && g == (gid_t) g)
+ group_option = g;
+ else
+ FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+ _("%s: Invalid group")));
+ }
+ break;
+
+ case MODE_OPTION:
+ mode_option
+ = mode_compile (optarg,
+ MODE_MASK_EQUALS | MODE_MASK_PLUS | MODE_MASK_MINUS);
+ if (mode_option == MODE_INVALID)
+ FATAL_ERROR ((0, 0, _("Invalid mode given on option")));
+ if (mode_option == MODE_MEMORY_EXHAUSTED)
+ xalloc_die ();
+ break;
+
+ case NO_ANCHORED_OPTION:
+ exclude_options &= ~ EXCLUDE_ANCHORED;
+ break;
+
+ case NO_IGNORE_CASE_OPTION:
+ exclude_options &= ~ FNM_CASEFOLD;
+ break;
+
+ case NO_WILDCARDS_OPTION:
+ exclude_options &= ~ EXCLUDE_WILDCARDS;
+ break;
+
+ case NO_WILDCARDS_MATCH_SLASH_OPTION:
+ exclude_options |= FNM_FILE_NAME;
+ break;
+
+ case NULL_OPTION:
+ filename_terminator = '\0';
+ break;
+
+ case OVERWRITE_OPTION:
+ old_files_option = OVERWRITE_OLD_FILES;
+ break;
+
+ case OVERWRITE_DIR_OPTION:
+ old_files_option = OVERWRITE_OLD_DIRS;
+ break;
+
+ case OWNER_OPTION:
+ if (! (strlen (optarg) < UNAME_FIELD_SIZE
+ && uname_to_uid (optarg, &owner_option)))
+ {
+ uintmax_t u;
+ if (xstrtoumax (optarg, 0, 10, &u, "") == LONGINT_OK
+ && u == (uid_t) u)
+ owner_option = u;
+ else
+ FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+ _("Invalid owner")));
+ }
+ break;
+
+ case POSIX_OPTION:
+#if OLDGNU_COMPATIBILITY
+ if (archive_format == DEFAULT_FORMAT)
+ archive_format = GNU_FORMAT;
+ else if (archive_format != GNU_FORMAT)
+ USAGE_ERROR ((0, 0, _("Conflicting archive format options")));
+#else
+ if (archive_format == DEFAULT_FORMAT)
+ archive_format = POSIX_FORMAT;
+ else if (archive_format != POSIX_FORMAT)
+ USAGE_ERROR ((0, 0, _("Conflicting archive format options")));
+#endif
+ break;
+
+ case PRESERVE_OPTION:
+ same_permissions_option = 1;
+ same_order_option = 1;
+ break;
+
+ case RECORD_SIZE_OPTION:
+ {
+ uintmax_t u;
+ if (! (xstrtoumax (optarg, 0, 10, &u, "") == LONGINT_OK
+ && u == (size_t) u))
+ USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+ _("Invalid record size")));
+ record_size = u;
+ if (record_size % BLOCKSIZE != 0)
+ USAGE_ERROR ((0, 0, _("Record size must be a multiple of %d."),
+ BLOCKSIZE));
+ blocking_factor = record_size / BLOCKSIZE;
+ }
+ break;
+
+ case RSH_COMMAND_OPTION:
+ rsh_command_option = optarg;
+ break;
+
+ case SUFFIX_OPTION:
+ backup_option = 1;
+ backup_suffix_string = optarg;
+ break;
+
+ case USE_COMPRESS_PROGRAM_OPTION:
+ set_use_compress_program_option (optarg);
+ break;
+
+ case VOLNO_FILE_OPTION:
+ volno_file_option = optarg;
+ break;
+
+ case WILDCARDS_OPTION:
+ exclude_options |= EXCLUDE_WILDCARDS;
+ break;
+
+ case WILDCARDS_MATCH_SLASH_OPTION:
+ exclude_options &= ~ FNM_FILE_NAME;
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+
+#ifdef DEVICE_PREFIX
+ {
+ int device = optchar - '0';
+ int density;
+ static char buf[sizeof DEVICE_PREFIX + 10];
+ char *cursor;
+
+ density = getopt_long (argc, argv, "lmh", 0, 0);
+ strcpy (buf, DEVICE_PREFIX);
+ cursor = buf + strlen (buf);
+
+#ifdef DENSITY_LETTER
+
+ sprintf (cursor, "%d%c", device, density);
+
+#else /* not DENSITY_LETTER */
+
+ switch (density)
+ {
+ case 'l':
+#ifdef LOW_NUM
+ device += LOW_NUM;
+#endif
+ break;
+
+ case 'm':
+#ifdef MID_NUM
+ device += MID_NUM;
+#else
+ device += 8;
+#endif
+ break;
+
+ case 'h':
+#ifdef HGH_NUM
+ device += HGH_NUM;
+#else
+ device += 16;
+#endif
+ break;
+
+ default:
+ usage (TAREXIT_FAILURE);
+ }
+ sprintf (cursor, "%d", device);
+
+#endif /* not DENSITY_LETTER */
+
+ if (archive_names == allocated_archive_names)
+ {
+ allocated_archive_names *= 2;
+ archive_name_array =
+ xrealloc (archive_name_array,
+ sizeof (const char *) * allocated_archive_names);
+ }
+ archive_name_array[archive_names++] = buf;
+
+ /* FIXME: How comes this works for many archives when buf is
+ not xstrdup'ed? */
+ }
+ break;
+
+#else /* not DEVICE_PREFIX */
+
+ USAGE_ERROR ((0, 0,
+ _("Options `-[0-7][lmh]' not supported by *this* tar")));
+
+#endif /* not DEVICE_PREFIX */
+ }
+
+ /* Handle operands after any "--" argument. */
+ for (; optind < argc; optind++)
+ {
+ name_add (argv[optind]);
+ input_files++;
+ }
+
+ /* Process trivial options. */
+
+ if (show_version)
+ {
+ printf ("tar (GNU %s) %s\n", PACKAGE, VERSION);
+ print_copyright ("2001 Free Software Foundation, Inc.");
+ puts (_("\
+This program comes with NO WARRANTY, to the extent permitted by law.\n\
+You may redistribute it under the terms of the GNU General Public License;\n\
+see the file named COPYING for details."));
+
+ puts (_("Written by John Gilmore and Jay Fenlason."));
+
+ exit (TAREXIT_SUCCESS);
+ }
+
+ if (show_help)
+ usage (TAREXIT_SUCCESS);
+
+ /* Derive option values and check option consistency. */
+
+ if (archive_format == DEFAULT_FORMAT)
+ {
+#if OLDGNU_COMPATIBILITY
+ archive_format = OLDGNU_FORMAT;
+#else
+ archive_format = GNU_FORMAT;
+#endif
+ }
+
+ if (archive_format == GNU_FORMAT && getenv ("POSIXLY_CORRECT"))
+ archive_format = POSIX_FORMAT;
+
+ if ((volume_label_option
+ || incremental_option || multi_volume_option || sparse_option)
+ && archive_format != OLDGNU_FORMAT && archive_format != GNU_FORMAT)
+ USAGE_ERROR ((0, 0,
+ _("GNU features wanted on incompatible archive format")));
+
+ if (archive_names == 0)
+ {
+ /* If no archive file name given, try TAPE from the environment, or
+ else, DEFAULT_ARCHIVE from the configuration process. */
+
+ archive_names = 1;
+ archive_name_array[0] = getenv ("TAPE");
+ if (! archive_name_array[0])
+ archive_name_array[0] = DEFAULT_ARCHIVE;
+ }
+
+ /* Allow multiple archives only with `-M'. */
+
+ if (archive_names > 1 && !multi_volume_option)
+ USAGE_ERROR ((0, 0,
+ _("Multiple archive files requires `-M' option")));
+
+ if (listed_incremental_option
+ && newer_mtime_option != TYPE_MINIMUM (time_t))
+ USAGE_ERROR ((0, 0,
+ _("Cannot combine --listed-incremental with --newer")));
+
+ if (volume_label_option)
+ {
+ size_t volume_label_max_len =
+ (sizeof current_header->header.name
+ - 1 /* for trailing '\0' */
+ - (multi_volume_option
+ ? (sizeof " Volume "
+ - 1 /* for null at end of " Volume " */
+ + INT_STRLEN_BOUND (int) /* for volume number */
+ - 1 /* for sign, as 0 <= volno */)
+ : 0));
+ if (volume_label_max_len < strlen (volume_label_option))
+ USAGE_ERROR ((0, 0,
+ _("%s: Volume label is too long (limit is %lu bytes)"),
+ quotearg_colon (volume_label_option),
+ (unsigned long) volume_label_max_len));
+ }
+
+ /* If ready to unlink hierarchies, so we are for simpler files. */
+ if (recursive_unlink_option)
+ old_files_option = UNLINK_FIRST_OLD_FILES;
+
+ /* Forbid using -c with no input files whatsoever. Check that `-f -',
+ explicit or implied, is used correctly. */
+
+ switch (subcommand_option)
+ {
+ case CREATE_SUBCOMMAND:
+ if (input_files == 0 && !files_from_option)
+ USAGE_ERROR ((0, 0,
+ _("Cowardly refusing to create an empty archive")));
+ break;
+
+ case EXTRACT_SUBCOMMAND:
+ case LIST_SUBCOMMAND:
+ case DIFF_SUBCOMMAND:
+ for (archive_name_cursor = archive_name_array;
+ archive_name_cursor < archive_name_array + archive_names;
+ archive_name_cursor++)
+ if (!strcmp (*archive_name_cursor, "-"))
+ request_stdin ("-f");
+ break;
+
+ case CAT_SUBCOMMAND:
+ case UPDATE_SUBCOMMAND:
+ case APPEND_SUBCOMMAND:
+ for (archive_name_cursor = archive_name_array;
+ archive_name_cursor < archive_name_array + archive_names;
+ archive_name_cursor++)
+ if (!strcmp (*archive_name_cursor, "-"))
+ USAGE_ERROR ((0, 0,
+ _("Options `-Aru' are incompatible with `-f -'")));
+
+ default:
+ break;
+ }
+
+ archive_name_cursor = archive_name_array;
+
+ /* Prepare for generating backup names. */
+
+ if (backup_suffix_string)
+ simple_backup_suffix = xstrdup (backup_suffix_string);
+
+ if (backup_option)
+ backup_type = xget_version ("--backup", version_control_string);
+}
+
+/* Tar proper. */
+
+/* Main routine for tar. */
+int
+main (int argc, char **argv)
+{
+#if HAVE_CLOCK_GETTIME
+ if (clock_gettime (CLOCK_REALTIME, &start_timespec) != 0)
+#endif
+ start_time = time (0);
+ program_name = argv[0];
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ exit_status = TAREXIT_SUCCESS;
+ filename_terminator = '\n';
+ set_quoting_style (0, escape_quoting_style);
+
+ /* Pre-allocate a few structures. */
+
+ allocated_archive_names = 10;
+ archive_name_array =
+ xmalloc (sizeof (const char *) * allocated_archive_names);
+ archive_names = 0;
+
+#ifdef SIGCHLD
+ /* System V fork+wait does not work if SIGCHLD is ignored. */
+ signal (SIGCHLD, SIG_DFL);
+#endif
+
+ init_names ();
+
+ /* Decode options. */
+
+ decode_options (argc, argv);
+ name_init (argc, argv);
+
+ /* Main command execution. */
+
+ if (volno_file_option)
+ init_volume_number ();
+
+ switch (subcommand_option)
+ {
+ case UNKNOWN_SUBCOMMAND:
+ USAGE_ERROR ((0, 0,
+ _("You must specify one of the `-Acdtrux' options")));
+
+ case CAT_SUBCOMMAND:
+ case UPDATE_SUBCOMMAND:
+ case APPEND_SUBCOMMAND:
+ update_archive ();
+ break;
+
+ case DELETE_SUBCOMMAND:
+ delete_archive_members ();
+ break;
+
+ case CREATE_SUBCOMMAND:
+ create_archive ();
+ name_close ();
+
+ if (totals_option)
+ print_total_written ();
+ break;
+
+ case EXTRACT_SUBCOMMAND:
+ extr_init ();
+ read_and (extract_archive);
+ extract_finish ();
+ break;
+
+ case LIST_SUBCOMMAND:
+ read_and (list_archive);
+ break;
+
+ case DIFF_SUBCOMMAND:
+ diff_init ();
+ read_and (diff_archive);
+ break;
+ }
+
+ if (volno_file_option)
+ closeout_volume_number ();
+
+ /* Dispose of allocated memory, and return. */
+
+ free (archive_name_array);
+ name_term ();
+
+ if (stdlis == stdout && (ferror (stdout) || fclose (stdout) != 0))
+ FATAL_ERROR ((0, 0, _("Error in writing to standard output")));
+ if (exit_status == TAREXIT_FAILURE)
+ error (0, 0, _("Error exit delayed from previous errors"));
+ exit (exit_status);
+}
diff --git a/contrib/tar/src/tar.h b/contrib/tar/src/tar.h
new file mode 100644
index 0000000..ff2977b
--- /dev/null
+++ b/contrib/tar/src/tar.h
@@ -0,0 +1,235 @@
+/* GNU tar Archive Format description.
+
+ Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 2000, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* If OLDGNU_COMPATIBILITY is not zero, tar produces archives which, by
+ default, are readable by older versions of GNU tar. This can be
+ overriden by using --posix; in this case, POSIXLY_CORRECT in environment
+ may be set for enforcing stricter conformance. If OLDGNU_COMPATIBILITY
+ is zero or undefined, tar will eventually produces archives which, by
+ default, POSIX compatible; then either using --posix or defining
+ POSIXLY_CORRECT enforces stricter conformance.
+
+ This #define will disappear in a few years. FP, June 1995. */
+#define OLDGNU_COMPATIBILITY 1
+
+/* tar Header Block, from POSIX 1003.1-1990. */
+
+/* POSIX header. */
+
+struct posix_header
+{ /* byte offset */
+ char name[100]; /* 0 */
+ char mode[8]; /* 100 */
+ char uid[8]; /* 108 */
+ char gid[8]; /* 116 */
+ char size[12]; /* 124 */
+ char mtime[12]; /* 136 */
+ char chksum[8]; /* 148 */
+ char typeflag; /* 156 */
+ char linkname[100]; /* 157 */
+ char magic[6]; /* 257 */
+ char version[2]; /* 263 */
+ char uname[32]; /* 265 */
+ char gname[32]; /* 297 */
+ char devmajor[8]; /* 329 */
+ char devminor[8]; /* 337 */
+ char prefix[155]; /* 345 */
+ /* 500 */
+};
+
+#define TMAGIC "ustar" /* ustar and a null */
+#define TMAGLEN 6
+#define TVERSION "00" /* 00 and no null */
+#define TVERSLEN 2
+
+/* Values used in typeflag field. */
+#define REGTYPE '0' /* regular file */
+#define AREGTYPE '\0' /* regular file */
+#define LNKTYPE '1' /* link */
+#define SYMTYPE '2' /* reserved */
+#define CHRTYPE '3' /* character special */
+#define BLKTYPE '4' /* block special */
+#define DIRTYPE '5' /* directory */
+#define FIFOTYPE '6' /* FIFO special */
+#define CONTTYPE '7' /* reserved */
+
+/* Bits used in the mode field, values in octal. */
+#define TSUID 04000 /* set UID on execution */
+#define TSGID 02000 /* set GID on execution */
+#define TSVTX 01000 /* reserved */
+ /* file permissions */
+#define TUREAD 00400 /* read by owner */
+#define TUWRITE 00200 /* write by owner */
+#define TUEXEC 00100 /* execute/search by owner */
+#define TGREAD 00040 /* read by group */
+#define TGWRITE 00020 /* write by group */
+#define TGEXEC 00010 /* execute/search by group */
+#define TOREAD 00004 /* read by other */
+#define TOWRITE 00002 /* write by other */
+#define TOEXEC 00001 /* execute/search by other */
+
+/* tar Header Block, GNU extensions. */
+
+/* In GNU tar, SYMTYPE is for to symbolic links, and CONTTYPE is for
+ contiguous files, so maybe disobeying the `reserved' comment in POSIX
+ header description. I suspect these were meant to be used this way, and
+ should not have really been `reserved' in the published standards. */
+
+/* *BEWARE* *BEWARE* *BEWARE* that the following information is still
+ boiling, and may change. Even if the OLDGNU format description should be
+ accurate, the so-called GNU format is not yet fully decided. It is
+ surely meant to use only extensions allowed by POSIX, but the sketch
+ below repeats some ugliness from the OLDGNU format, which should rather
+ go away. Sparse files should be saved in such a way that they do *not*
+ require two passes at archive creation time. Huge files get some POSIX
+ fields to overflow, alternate solutions have to be sought for this. */
+
+/* Descriptor for a single file hole. */
+
+struct sparse
+{ /* byte offset */
+ char offset[12]; /* 0 */
+ char numbytes[12]; /* 12 */
+ /* 24 */
+};
+
+/* Sparse files are not supported in POSIX ustar format. For sparse files
+ with a POSIX header, a GNU extra header is provided which holds overall
+ sparse information and a few sparse descriptors. When an old GNU header
+ replaces both the POSIX header and the GNU extra header, it holds some
+ sparse descriptors too. Whether POSIX or not, if more sparse descriptors
+ are still needed, they are put into as many successive sparse headers as
+ necessary. The following constants tell how many sparse descriptors fit
+ in each kind of header able to hold them. */
+
+#define SPARSES_IN_EXTRA_HEADER 16
+#define SPARSES_IN_OLDGNU_HEADER 4
+#define SPARSES_IN_SPARSE_HEADER 21
+
+/* The GNU extra header contains some information GNU tar needs, but not
+ foreseen in POSIX header format. It is only used after a POSIX header
+ (and never with old GNU headers), and immediately follows this POSIX
+ header, when typeflag is a letter rather than a digit, so signaling a GNU
+ extension. */
+
+struct extra_header
+{ /* byte offset */
+ char atime[12]; /* 0 */
+ char ctime[12]; /* 12 */
+ char offset[12]; /* 24 */
+ char realsize[12]; /* 36 */
+ char longnames[4]; /* 48 */
+ char unused_pad1[68]; /* 52 */
+ struct sparse sp[SPARSES_IN_EXTRA_HEADER];
+ /* 120 */
+ char isextended; /* 504 */
+ /* 505 */
+};
+
+/* Extension header for sparse files, used immediately after the GNU extra
+ header, and used only if all sparse information cannot fit into that
+ extra header. There might even be many such extension headers, one after
+ the other, until all sparse information has been recorded. */
+
+struct sparse_header
+{ /* byte offset */
+ struct sparse sp[SPARSES_IN_SPARSE_HEADER];
+ /* 0 */
+ char isextended; /* 504 */
+ /* 505 */
+};
+
+/* The old GNU format header conflicts with POSIX format in such a way that
+ POSIX archives may fool old GNU tar's, and POSIX tar's might well be
+ fooled by old GNU tar archives. An old GNU format header uses the space
+ used by the prefix field in a POSIX header, and cumulates information
+ normally found in a GNU extra header. With an old GNU tar header, we
+ never see any POSIX header nor GNU extra header. Supplementary sparse
+ headers are allowed, however. */
+
+struct oldgnu_header
+{ /* byte offset */
+ char unused_pad1[345]; /* 0 */
+ char atime[12]; /* 345 */
+ char ctime[12]; /* 357 */
+ char offset[12]; /* 369 */
+ char longnames[4]; /* 381 */
+ char unused_pad2; /* 385 */
+ struct sparse sp[SPARSES_IN_OLDGNU_HEADER];
+ /* 386 */
+ char isextended; /* 482 */
+ char realsize[12]; /* 483 */
+ /* 495 */
+};
+
+/* OLDGNU_MAGIC uses both magic and version fields, which are contiguous.
+ Found in an archive, it indicates an old GNU header format, which will be
+ hopefully become obsolescent. With OLDGNU_MAGIC, uname and gname are
+ valid, though the header is not truly POSIX conforming. */
+#define OLDGNU_MAGIC "ustar " /* 7 chars and a null */
+
+/* The standards committee allows only capital A through capital Z for
+ user-defined expansion. */
+
+/* This is a dir entry that contains the names of files that were in the
+ dir at the time the dump was made. */
+#define GNUTYPE_DUMPDIR 'D'
+
+/* Identifies the *next* file on the tape as having a long linkname. */
+#define GNUTYPE_LONGLINK 'K'
+
+/* Identifies the *next* file on the tape as having a long name. */
+#define GNUTYPE_LONGNAME 'L'
+
+/* This is the continuation of a file that began on another volume. */
+#define GNUTYPE_MULTIVOL 'M'
+
+/* For storing filenames that do not fit into the main header. */
+#define GNUTYPE_NAMES 'N'
+
+/* This is for sparse files. */
+#define GNUTYPE_SPARSE 'S'
+
+/* This file is a tape/volume header. Ignore it on extraction. */
+#define GNUTYPE_VOLHDR 'V'
+
+/* tar Header Block, overall structure. */
+
+/* tar files are made in basic blocks of this size. */
+#define BLOCKSIZE 512
+
+enum archive_format
+{
+ DEFAULT_FORMAT, /* format to be decided later */
+ V7_FORMAT, /* old V7 tar format */
+ OLDGNU_FORMAT, /* GNU format as per before tar 1.12 */
+ POSIX_FORMAT, /* restricted, pure POSIX format */
+ GNU_FORMAT /* POSIX format with GNU extensions */
+};
+
+union block
+{
+ char buffer[BLOCKSIZE];
+ struct posix_header header;
+ struct extra_header extra_header;
+ struct oldgnu_header oldgnu_header;
+ struct sparse_header sparse_header;
+};
+
+/* End of Format description. */
diff --git a/contrib/tar/src/update.c b/contrib/tar/src/update.c
new file mode 100644
index 0000000..754d321
--- /dev/null
+++ b/contrib/tar/src/update.c
@@ -0,0 +1,195 @@
+/* Update a tar archive.
+
+ Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001 Free
+ Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Implement the 'r', 'u' and 'A' options for tar. 'A' means that the
+ file names are tar files, and they should simply be appended to the end
+ of the archive. No attempt is made to record the reads from the args; if
+ they're on raw tape or something like that, it'll probably lose... */
+
+#include "system.h"
+#include <quotearg.h>
+#include "common.h"
+
+/* FIXME: This module should not directly handle the following variable,
+ instead, this should be done in buffer.c only. */
+extern union block *current_block;
+
+/* We've hit the end of the old stuff, and its time to start writing new
+ stuff to the tape. This involves seeking back one record and
+ re-writing the current record (which has been changed). */
+int time_to_start_writing;
+
+/* Pointer to where we started to write in the first record we write out.
+ This is used if we can't backspace the output and have to null out the
+ first part of the record. */
+char *output_start;
+
+/* Catenate file PATH to the archive without creating a header for it.
+ It had better be a tar file or the archive is screwed. */
+static void
+append_file (char *path)
+{
+ int handle = open (path, O_RDONLY | O_BINARY);
+ struct stat stat_data;
+
+ if (handle < 0)
+ {
+ open_error (path);
+ return;
+ }
+
+ if (fstat (handle, &stat_data) != 0)
+ stat_error (path);
+ else
+ {
+ off_t bytes_left = stat_data.st_size;
+
+ while (bytes_left > 0)
+ {
+ union block *start = find_next_block ();
+ size_t buffer_size = available_space_after (start);
+ ssize_t status;
+ char buf[UINTMAX_STRSIZE_BOUND];
+
+ if (bytes_left < buffer_size)
+ {
+ buffer_size = bytes_left;
+ status = buffer_size % BLOCKSIZE;
+ if (status)
+ memset (start->buffer + bytes_left, 0, BLOCKSIZE - status);
+ }
+
+ status = safe_read (handle, start->buffer, buffer_size);
+ if (status < 0)
+ read_fatal_details (path, stat_data.st_size - bytes_left,
+ buffer_size);
+ if (status == 0)
+ FATAL_ERROR ((0, 0, _("%s: File shrank by %s bytes"),
+ quotearg_colon (path),
+ STRINGIFY_BIGINT (bytes_left, buf)));
+
+ bytes_left -= status;
+
+ set_next_block_after (start + (status - 1) / BLOCKSIZE);
+ }
+ }
+
+ if (close (handle) != 0)
+ close_error (path);
+}
+
+/* Implement the 'r' (add files to end of archive), and 'u' (add files
+ to end of archive if they aren't there, or are more up to date than
+ the version in the archive) commands. */
+void
+update_archive (void)
+{
+ enum read_header previous_status = HEADER_STILL_UNREAD;
+ int found_end = 0;
+
+ name_gather ();
+ open_archive (ACCESS_UPDATE);
+
+ while (!found_end)
+ {
+ enum read_header status = read_header (0);
+
+ switch (status)
+ {
+ case HEADER_STILL_UNREAD:
+ abort ();
+
+ case HEADER_SUCCESS:
+ {
+ struct name *name;
+
+ if (subcommand_option == UPDATE_SUBCOMMAND
+ && (name = name_scan (current_file_name), name))
+ {
+ struct stat s;
+ enum archive_format unused;
+
+ decode_header (current_header, &current_stat, &unused, 0);
+ chdir_do (name->change_dir);
+ if (deref_stat (dereference_option, current_file_name, &s) == 0
+ && s.st_mtime <= current_stat.st_mtime)
+ add_avoided_name (current_file_name);
+ }
+ skip_member ();
+ break;
+ }
+
+ case HEADER_ZERO_BLOCK:
+ current_block = current_header;
+ found_end = 1;
+ break;
+
+ case HEADER_END_OF_FILE:
+ found_end = 1;
+ break;
+
+ case HEADER_FAILURE:
+ set_next_block_after (current_header);
+ switch (previous_status)
+ {
+ case HEADER_STILL_UNREAD:
+ WARN ((0, 0, _("This does not look like a tar archive")));
+ /* Fall through. */
+
+ case HEADER_SUCCESS:
+ case HEADER_ZERO_BLOCK:
+ ERROR ((0, 0, _("Skipping to next header")));
+ /* Fall through. */
+
+ case HEADER_FAILURE:
+ break;
+
+ case HEADER_END_OF_FILE:
+ abort ();
+ }
+ break;
+ }
+
+ previous_status = status;
+ }
+
+ reset_eof ();
+ time_to_start_writing = 1;
+ output_start = current_block->buffer;
+
+ {
+ char *path;
+
+ while (path = name_from_list (), path)
+ {
+ if (excluded_name (path))
+ continue;
+ if (interactive_option && !confirm ("add", path))
+ continue;
+ if (subcommand_option == CAT_SUBCOMMAND)
+ append_file (path);
+ else
+ dump_file (path, 1, (dev_t) 0);
+ }
+ }
+
+ write_eot ();
+ close_archive ();
+ names_notfound ();
+}
OpenPOWER on IntegriCloud