diff options
author | sobomax <sobomax@FreeBSD.org> | 2002-06-04 10:37:47 +0000 |
---|---|---|
committer | sobomax <sobomax@FreeBSD.org> | 2002-06-04 10:37:47 +0000 |
commit | 0f70d6636c8f836f50cc56b9ea9b8dc51cd12dbe (patch) | |
tree | 8e3e6da9ce2dfb3d403e8ed0fab9168ce589ca80 | |
download | FreeBSD-src-0f70d6636c8f836f50cc56b9ea9b8dc51cd12dbe.zip FreeBSD-src-0f70d6636c8f836f50cc56b9ea9b8dc51cd12dbe.tar.gz |
Virgin import (trimmed) of GNU Tar version 1.13.25.
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 (¤t_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, ¤t_stat, ¤t_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 (¤t_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, ¤t_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, ¤t_stat); + + but since they'd interpret DIRTYPE blocks as regular + files, we'd better put the / on the name. */ + + header = start_header (namebuf, ¤t_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 (¤t_link_name, link_name); + + current_stat.st_size = 0; + header = start_header (p, ¤t_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, ¤t_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, ¤t_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 (¤t_link_name, buffer); + + current_stat.st_size = 0; /* force 0 size on symlink */ + header = start_header (p, ¤t_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, ¤t_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, + ¤t_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, ¤t_stat, ¤t_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 = ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_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, ¤t_stat, ¤t_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 = ¤t_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 (¤t_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 (¤t_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, ¤t_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 (); +} |