summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>1997-03-29 22:40:46 +0000
committerobrien <obrien@FreeBSD.org>1997-03-29 22:40:46 +0000
commit070358f751d369b8ebd56d23bc7b721c0722d6c7 (patch)
tree36abc0213e433d23d7498ea0a81ce7e455da6e5c
parent680df75eef352f77ca2d4671b7a7532b9c5bffc0 (diff)
parentb3a30fbfec9a47562eda6d937b13d248785da297 (diff)
downloadFreeBSD-src-070358f751d369b8ebd56d23bc7b721c0722d6c7.zip
FreeBSD-src-070358f751d369b8ebd56d23bc7b721c0722d6c7.tar.gz
This commit was generated by cvs2svn to compensate for changes in r24398,
which included commits to RCS files with non-trunk default branches.
-rw-r--r--contrib/cpio/COPYING339
-rw-r--r--contrib/cpio/COPYING.LIB481
-rw-r--r--contrib/cpio/ChangeLog968
-rw-r--r--contrib/cpio/NEWS64
-rw-r--r--contrib/cpio/README71
-rw-r--r--contrib/cpio/alloca.c495
-rw-r--r--contrib/cpio/copyin.c1352
-rw-r--r--contrib/cpio/copyout.c807
-rw-r--r--contrib/cpio/copypass.c464
-rw-r--r--contrib/cpio/cpio.1326
-rw-r--r--contrib/cpio/cpio.h69
-rw-r--r--contrib/cpio/cpiohdr.h90
-rw-r--r--contrib/cpio/defer.c43
-rw-r--r--contrib/cpio/defer.h8
-rw-r--r--contrib/cpio/dirname.c70
-rw-r--r--contrib/cpio/dstring.c114
-rw-r--r--contrib/cpio/dstring.h49
-rw-r--r--contrib/cpio/error.c130
-rw-r--r--contrib/cpio/extern.h194
-rw-r--r--contrib/cpio/filemode.c255
-rw-r--r--contrib/cpio/filetypes.h84
-rw-r--r--contrib/cpio/getopt.c765
-rw-r--r--contrib/cpio/getopt.h129
-rw-r--r--contrib/cpio/getopt1.c180
-rw-r--r--contrib/cpio/global.c197
-rw-r--r--contrib/cpio/idcache.c210
-rw-r--r--contrib/cpio/main.c521
-rw-r--r--contrib/cpio/makepath.c307
-rw-r--r--contrib/cpio/rmt.h98
-rw-r--r--contrib/cpio/rtapelib.c582
-rw-r--r--contrib/cpio/safe-stat.h1
-rw-r--r--contrib/cpio/stripslash.c43
-rw-r--r--contrib/cpio/system.h142
-rw-r--r--contrib/cpio/tar.c522
-rw-r--r--contrib/cpio/tar.h112
-rw-r--r--contrib/cpio/tarhdr.h62
-rw-r--r--contrib/cpio/tcexparg.c240
-rw-r--r--contrib/cpio/userspec.c277
-rw-r--r--contrib/cpio/util.c1343
-rw-r--r--contrib/cpio/version.c2
-rw-r--r--contrib/cpio/xmalloc.c103
-rw-r--r--contrib/cpio/xstrdup.c36
42 files changed, 12345 insertions, 0 deletions
diff --git a/contrib/cpio/COPYING b/contrib/cpio/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/contrib/cpio/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, 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
+
+ Appendix: 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) 19yy <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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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/cpio/COPYING.LIB b/contrib/cpio/COPYING.LIB
new file mode 100644
index 0000000..bbe3fe1
--- /dev/null
+++ b/contrib/cpio/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, 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 library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, 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 companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, 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 library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+ 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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+ If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. 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.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+ 9. 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 Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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.
+
+ 11. 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 Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. 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 library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/contrib/cpio/ChangeLog b/contrib/cpio/ChangeLog
new file mode 100644
index 0000000..eaf14a9
--- /dev/null
+++ b/contrib/cpio/ChangeLog
@@ -0,0 +1,968 @@
+Tue Jan 16 19:03:05 1996 John Oleynick (juo@wombat.gnu.ai.mit.edu)
+ * util.c: An I/O error reading a file would cause the last byte
+ of the next file to be corrupted in the archive. Thanks to a
+ buggy NT NFS server for pointing out this problem.
+ * Version 2.4.2 released.
+
+Tue Jan 9 23:19:37 1996 John Oleynick (juo@wombat.gnu.ai.mit.edu)
+ * copyout.c: missed 1 part of last bug fix.
+
+Mon Jan 8 16:49:01 1996 John Oleynick (juo@wombat.gnu.ai.mit.edu)
+ * copyout.c, copypass.c: Use result of readlink() as length
+ of link name instead of size from lstat(). On some OS's lstat()
+ doesn't return the true length in size. Bug reported by
+ Robert Joop (rj@rainbow.IN-berlin.DE).
+
+Wed Dec 20 10:52:56 1995 John Oleynick (juo@wombat.gnu.ai.mit.edu)
+ * rmt.c: Added temporary kludge so make rmt will work on Linux.
+ * configure.in: Only define HAVE_UTIME_H if utime.h declares
+ struct utimbuf.
+ * Makefile.in: Change prefix, exec_prefix and bindir to get their
+ values from configure. Added cpio.info to DISTFILES.
+ * cpio.texi: Added INFO-DIR-ENTRY.
+ * Version 2.4.1 released.
+
+Wed Nov 22 19:37:05 1995 John Oleynick (juo@wombat.gnu.ai.mit.edu)
+ * cpio.texi: Updated release date and FSF's address.
+ * NEWS: Listed major new features for 2.4.
+ * mt.c, mt.1: Added seek and fsfm commands.
+ * Version 2.4 released.
+
+Tue Jun 27 19:14:27 1995 John Oleynick (juo@wombat.gnu.ai.mit.edu)
+ * configure.in: fixed for new autoconf. Added check to make
+ sure fnmatch() works.
+ * Makefile.in: changed realclean to maintainer-clean. Added
+ support to handle fnmatch separate from other LIBOBJS.
+ * cpio.texi: More changes for 2.4.
+
+Wed Dec 14 16:14:27 1994 John Oleynick (juo@wombat.gnu.ai.mit.edu)
+ * copypass.h: When given the -a option, set the access time of
+ the copy to be the access time of the original (instead of the
+ modification time of the original). Reported by
+ karney@pppl.gov (Charles Karney).
+ * cpio.texi: Updated with changes for 2.4.
+
+Wed Nov 3 18:18:07 1994 John Oleynick (juo@wombat.gnu.ai.mit.edu)
+ * safe-stat.h, Makefile.in: New file used by mkdir.c. This will go
+ away when we get the real safe-xstat.[ch]in for mkdir.c.
+ * main.c: Don't mention [--null] twice in -p's usage message.
+ Changed --no-absolute-paths to --no-absolute-filenames.
+ * cpio.1: Updated man page with new features.
+ * cpio.texi, texinfo.tex, Makefile.in: Added texi documentation
+ from Robert Carleton (rbc@gnu.ai.mit.edu).
+
+Mon Oct 3 00:46:30 1994 John Oleynick (juo@wombat.gnu.ai.mit.edu)
+ * makefile.pc, system.h: Changes to compile with Borland C++ 4.0.
+
+Thu Sep 29 22:15:50 1994 John Oleynick (juo@wombat.gnu.ai.mit.edu)
+ * makepath.c: Don't #define index if it is already #defined.
+
+ * mt.c: Check for __hpux defined instead of __hpux__. Reported
+ by ericb@lsid.hp.com (Eric Backus).
+
+Thu Sep 29 11:21:31 1994 John Oleynick (juo@wombat.gnu.ai.mit.edu)
+ * extern.h, util.c, copyout.c, copypass.c, main.c, global.c:
+ Never mind --ignore-disk-input-errors flag, we'll just always
+ do that, like tar.
+
+ * global.c, extern.h, main.c, copyin.c, copyout.c, copypass.c:
+ Added --quiet flag to supress printing number of blocks copied.
+
+ * global.c, extern.h: If compiled with gcc, make input_bytes
+ and output_bytes `long long' instead of `long'. We need more
+ than 32 bits to keep track of the number of bytes copied to
+ and from tape drives that hold more than 4Gbytes.
+
+ * util.c, copyin.c, main.c, global.c, extern.h: Added
+ --only-verify-crc flag to read a CRC format archive and verify
+ its contents' CRCs.
+
+ * copyout.c: Fixed problem with creating oldc format archives
+ on machines with 16 bit ints. Reported by mpoole@cix.compulink.co.uk
+ (Martin Poole).
+
+ * mt.c: Need to open tape WR_ONLY for erase command (and probably
+ others?). Reported by robert@hst.e.technik.uni-kl.de (Robert
+ Vogelgesan). Accept `eject' as a synonym for `offline'. Accept
+ `-t' as a synonym for `-f' (to be compatible with HPUX mt, which
+ only accepts `-t').
+
+Wed Sep 28 12:01:55 1994 John Oleynick (juo@wombat.gnu.ai.mit.edu)
+ * extern.h, global.c, main.c, util.c: only write sparse files
+ when given --sparse flag.
+ * extern.h, util.c, copyout.c, copypass.c, main.c, global.c:
+ Added support for --ignore-disk-input-errors flag.
+
+Wed Aug 24 12:55:38 1994 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
+
+ * configure.in: Replace calls to AC_REMOTE_TAPE and AC_RSH
+ with equivalent code, since those macros are going away.
+
+Sun Feb 13 00:56:48 1994 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+ * extern.h, global.c, main.c, util.c: Added code to
+ tape_buffered_peek() to properly handle large, corrutped
+ archives, without overrunning the allocated buffer and
+ dumping core. Also changed the way the input and output
+ buffers are allocated in initialize_buffers().
+
+Tue Jan 25 01:04:32 1994 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+ * copyin.c, copyout.c, copypass.c, extern.h, main.c, tar.c, util.c:
+ Redid i/o buffer code. Previously, the same routines buffered input and
+ output for accessing the archive and the filesystem. Now there are
+ separate routines for buffering input and output and for buffering the
+ archive and the filesystem. This simplifies much of the buffer code
+ (e.g., only input from the archive has to check for end of tape and
+ allow the tape to be changed, only output to the filesystem has to
+ handle byte and word swapping, etc.; previously one routine had to
+ handle all of these special cases) This is how the routines got split
+ and renamed (old name -> new name):
+
+ clear_rest_of_block -> tape_clear_rest_of_block
+ copy_files -> copy_files_tape_to_disk
+ " -> copy_files_disk_to_disk
+ " -> copy_files_disk_to_tape
+ copy_buf_out -> disk_buffered_write
+ " -> tape_buffered_write
+ copy_in_buf -> tape_buffered_read
+ empty_output_buffer -> tape_empty_output_buffer
+ " -> disk_empty_output_buffer
+ fill_input_buffer -> tape_fill_input_buffer
+ " -> disk_fill_input_buffer
+ pad_output -> tape_pad_output
+ peek_in_buf -> tape_buffered_peek
+ skip_padding -> tape_skip_padding
+ toss_input -> tape_toss_input
+
+ * extern.h, global.c, main.c, util.c: Added support for
+ writing sparse files.
+
+Tue Dec 28 23:01:36 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+ * util.c, system.h, makepath.c, extern.h: don't define chown()
+ and don't typedef uid_t and gid_t if we are being compiled
+ by DJGPP.
+
+ * copyin.c, extern.h, global.c, main.c: Added support for
+ --rename-batch-file.
+
+ * copyin.c, copyout.c, extern.h: Cleaned up to pass gcc -Wall.
+
+Wed Dec 22 02:17:44 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * makepath.c, copypass.c, copyin.c: If cpio was creating a
+ directory that contained `.' in the pathname (e.g. `foo/./bar'),
+ it would complain that it could not create `.', since it already
+ exists. From schwab@issan.informatik.uni-dortmund.de (Andreas
+ Schwab).
+
+ * mt.c: Added "eject" as a synonym for "offline".
+
+ * util.c: Slight modification to when we lseek with
+ BROKEN_LONG_TAPE_DRIVER (do it every 1Gb, instead
+ of every 2Gb).
+
+ * copyin.c, global.c, extern.h: Added --no-absolute-paths option,
+ to ignore absolute paths in archives.
+
+Tue Dec 21 01:30:59 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * util.c: Fix for copying new_media_message_after_number. From
+ Christian.Kuehnke@arbi.informatik.uni-oldenburg.de (Christian
+ Kuehnke).
+
+Thu Jul 29 20:35:57 1993 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.
+
+Mon Jul 19 23:01:00 1993 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
+
+ * Makefile.in (libdir): Use standard GNU value --
+ $(exec_prefix)/lib, not /etc.
+ (.c.o): Put CFLAGS last.
+
+Thu Jul 8 19:43:39 1993 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * Makefile.in: Add rules for remaking Makefile, configure,
+ config.status.
+
+Mon Jul 5 14:54:08 1993 John Oleynick (juo@spiff.gnu.ai.mit.edu)
+
+ * cpio.1: Updated man page for 2.3.
+ * Makefile.in: Create distribution with .gz extension, instead of .z.
+
+Tue Jun 29 18:54:37 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * Makefile.in: Added installdirs target (using mkinstalldirs).
+ * Added mkinstalldirs script.
+ * main.c, mt.c: Added --help option. Changed usage() to
+ take a stream and exit value (so --help can print on stdout
+ and return a 0 exit status).
+ * extern.h: Removed usage()'s prototype (it was out of date,
+ and only used in main.c).
+
+Thu May 6 00:22:22 1993 John Oleynick (juo@hal.gnu.ai.mit.edu)
+
+ * cpio.1: Added hpbin and hpodc.
+
+Tue May 4 00:32:29 1993 John Oleynick (juo@hal.gnu.ai.mit.edu)
+
+ * copyin.c (process_copy_in), copypass.c (process_copy_pass): When
+ deleting an existing file, if the file is a directory, use rmdir()
+ instead of unlink().
+
+Thu Apr 29 14:43:56 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * tar.c (read_in_tar_header): Clear non-protection bits from
+ mode, in case tar has left some device bits in there.
+
+Wed Apr 28 10:36:53 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * util.c: Added code to try and work around broken tape drivers
+ that have problems with tapes > 2Gb.
+
+ * copyout.c (process_copy_out): Pass file_hdr to
+ writeout_other_defers() and add_link_defer() by reference,
+ not by value.
+
+ * copyin.c (process_copy_in): Pass file_hdr to defer_copyin()
+ and create_defered_links() by reference, not by value.
+
+ * defer.c: include <sys/types.h> (to build on BSD 4.3 on HP300)
+
+Fri Apr 16 18:01:17 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * mt.c, util.c: Include <sys/mtio.h> if HAVE_SYS_MTIO_H is
+ defined, not HAVE_MTIO_H.
+
+Wed Apr 14 17:37:46 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * util.c: Include <sys/io/trioctl.h> if HAVE_SYS_IO_TRIOCTL_H
+ is defined.
+
+ * mt.c: Only include <sys/mtio.h> if HAVE_SYS_MTIO_H is defined.
+
+Fri Apr 2 13:09:11 1993 John Oleynick (juo@goldman.gnu.ai.mit.edu)
+
+ * configure.in: Added fnmatch to AC_REPLACE_FUNCS. Added
+ sys/io/trioctl.h to AC_HAVE_HEADERS.
+
+ * Makefile.in: Removed fnmatch.o from OBJS.
+
+ * copyin.c: Only include "fnmatch.h" if FNM_PATHNAME isn't
+ defined yet.
+
+ * mt.c: Include <sys/io/trioctl.h> if HAVE_SYS_IO_TRIOCTL_H is
+ defined.
+
+Mon Mar 29 17:04:06 1993 John Oleynick (juo@hal.gnu.ai.mit.edu)
+
+ * Many changes for supporting HPUX Context Dependent Files;
+ also some bug fixes to fix problems with multiply (hard) linked
+ device files; minor changes to support HPUX format archives
+ (slightly broken?) System V.4 posix tar archives and HPUX
+ posix tar archives.
+
+ * Makefile.in: New files defer.o, defer,c and defer.h; added
+ -DSYMLINK_USES_UMASK and -DHPUX_CDF comments; changed dist rule
+ to use gzip with tar, instead of compress.
+
+ * copyin.c: changes for new arf_hpbinary and arf_hpascii formats;
+ HPUX CDF's; DEBUG_CPIO; fixes to properly handle multiple
+ links in newc and crc format archives (new routines defer_copyin(),
+ create_defered_links(), create_final_defers()); move most
+ multiple (hard) link code to new routines link_name() and
+ link_to_maj_min_ino(); use new macro UMASKED_SYMLINK instead of
+ symlink().
+
+ * copyout.c: fixes to properly handle multiple links in newc
+ and crc format archives (new routines last_link(),
+ count_defered_links_to_dev_ino(), add_link_defer(),
+ writeout_other_defers(), writeout_final_defers(),
+ writeout_defered_file()); support for new arf_hpbinary and
+ arf_hpascii formats; support for HPUX CDF's.
+
+ * copypass.c: move most multiple link code to new routines
+ link_name() and link_to_maj_min_ino(); use new macro UMASKED_SYMLINK
+ instead of symlink(); support for HPUX CDF's.
+
+ * extern.h: added arf_hpascii and arf_hpbinary archive enum types;
+ added debug_flag.
+
+ * global.c: added debug_flag.
+
+ * main.c: added debug_flag; support for hpodc and hpbin formats.
+
+ * makepath.c: split from standard makpath.c to add support
+ for HPUX CDF's.
+
+ * mt.c: added !defined(__osf__) (from Andrew Marquis
+ <amarquis@genome.wi.mit.edu>).
+
+ * system.h: new macro UMASKED_SYMLINK
+
+ * tar.c: minor changes to read (slightly broken?) System V.4 posix
+ tar archives and HPUX posix tar archives.
+
+ * util.c: HPUX CDF support (including new routines
+ add_cdf_double_slashes() and islasparentcdf()); new routine
+ umasked_symlink().
+
+Sun Mar 14 23:00:14 1993 Jim Meyering (meyering@comco.com)
+
+ * copypass.c (process_copy_pass): Use <=, not just <, when comparing
+ mtimes. From Pieter Bowman <bowman@math.utah.edu>.
+
+Fri Jan 15 14:35:37 1993 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu)
+
+ * copyin.c: Move include of fnmatch.h to get right FNM* macros.
+
+Tue Nov 24 08:45:32 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * Version 2.2.
+
+ * copyout.c (process_copy_out): Add parens for gcc -Wall.
+ From Jim Meyering.
+
+ * system.h: Use HAVE_FCNTL_H, not USG.
+
+ * dstring.c, mt.c, system.h: Use HAVE_STRING_H, not USG.
+
+Fri Nov 20 22:47:18 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * copyin.c (read_in_binary): Copy the dev and ino that are
+ already in `file_hdr' into `short_hdr'.
+ From dao@abars.att.com (David A Oshinsky).
+
+ * system.h [!_POSIX_VERSION]: Declare lseek as off_t, not long.
+ From Karl Berry.
+
+Wed Oct 14 13:53:41 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * Version 2.1.
+
+Tue Oct 13 22:51:34 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * main.c: Add --swap equivalent to -b.
+
+ * mt.c: Add f_force_local variable and -V --version option.
+
+Fri Oct 2 18:42:27 1992 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu)
+
+ * main.c (long_opts, usage): Add --force-local option.
+
+Thu Oct 1 23:23:43 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * main.c (process_args) [__MSDOS__]: Don't call geteuid.
+
+ * copyin.c (read_in_{old,new}_ascii): Use `l' for sscanf into longs.
+ * copyout.c (write_out_header): Ditto for sprintf.
+ * global.c, extern.h: Make input_size and output_size long.
+
+Thu Sep 10 23:39:30 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * global.c, extern.h: Add new var f_force_local to work with
+ rmt.h change from tar.
+
+Sun Aug 23 00:18:20 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
+
+ * Version 2.0.
+
+ * tar.c (otoa): Compute value in an unsigned long, not an int.
+ * copyout.c (write_out_header) [__MSDOS__]: Don't use dev_t.
+
+ * main.c (process_args): By default, don't chown for non-root users.
+
+Sat Aug 22 14:17:54 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * global.c, extern.h: Use uid_t and gid_t.
+
+ * main.c (main) [__EMX__]: Expand wildcards.
+ * system.h [__EMX__]: Alias some error names. From Kai Uwe Rommel.
+
+ * extern.h [__STDC__]: Use prototypes.
+
+ * copyin.c (process_copy_in), copyout.c (process_copy_out),
+ copypass.c (process_copy_pass): Open all files with O_BINARY.
+ Add cast to chmod call.
+ * util.c: Add cast to bcopy calls. Make hash_insert static.
+ From Kai Uwe Rommel.
+
+Thu Aug 20 22:03:49 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * util.c (peek_in_buf): Don't print "end of file" before
+ getting the next reel of medium.
+
+ * copyin.c (read_in_old_ascii): Allocate space for NUL terminator.
+ Print newline for dot line when done, even if appending.
+
+Thu Jul 23 16:34:53 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * tar.c (write_out_tar_header, read_in_tar_header)
+ [__MSDOS__]: Don't try to get user and group names.
+ * extern.h: Don't declare the functions to do it (need uid_t).
+
+ * main.c [__MSDOS__]: Ignore the -R option.
+
+ * system.h: Define makedev if defining major and minor.
+
+ * copyin.c, copyout.c [__MSDOS__]: setmode on archive_des, not
+ 0 and 1.
+
+Sat Jul 18 14:30:55 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * tar.c, stripslash.c, userspec.c, cpiohdr.h, tar.h, tarhdr.h,
+ system.h: New files.
+ * Move portability stuff from various files to system.h.
+ * cpio.h: Rename header structure and members, and add
+ new structure for SVR4 format.
+ * copyin.c, copyout.c: Use the new structure internally, the
+ old one only for I/O in the old formats.
+ * copyin.c (read_in_header): Recognize the new archive formats.
+ (read_in_new_ascii, read_pattern_file, skip_padding): New functions.
+ (swab_array): Do the swapping using char pointers instead of
+ bitwise arithmetic.
+ (process_copy_in): Handle byte and halfword swapping and new formats.
+ Ok if a directory we want to make already exists, but set its perms.
+ Do chmod after chown to fix any set[ug]id bits.
+ Use `struct utimbuf' instead of a long array.
+ * copyout.c (write_out_header): Handle new formats.
+ (process_copy_out): Use `struct utimbuf'.
+ Handle appending and new formats.
+ Remove any leading `./' from filenames.
+ (read_for_checksum, clear_rest_of_block, pad_output): New functions.
+ * copypass.c (process_copy_pass): Use `struct utimbuf'.
+ Ok if a directory we want to make already exists, but set its perms.
+ Do chmod after chown to fix any set[ug]id bits.
+ Don't change perms of `.'.
+ * extern.h, global.c: Replace the separate format flags with
+ one variable. Add new variables for the new options.
+ * main.c: Add new options -A --append, -H --format, -C --io-size,
+ -M --message, --no-preserve-owner, -R --owner, -E --pattern-file,
+ -V --dot, -s --swap-bytes, -S --swap-halfwords, -b, -I, -k, -O.
+ (usage): Document them.
+ (process_args): Recognize them. Use open_archive.
+ (initialize_buffers): Allow room for tar archives and double buffers.
+ * util.c (empty_output_buffer_swap): New function.
+ (empty_output_buffer): Call it if swapping current file.
+ Check additional end of media indicators.
+ (swahw_array, peek_in_buf, prepare_append, open_archive,
+ set_new_media_message): New functions.
+ (fill_input_buffer): Don't print error message if end of media.
+ (toss_input): Don't seek, always read.
+ (copy_files): Update crc if needed.
+ (find_inode_file, add_inode): Check major and minor numbers as
+ well as dev.
+ (get_next_reel): Prompt user if archive name is unknown.
+ Print fancy messages.
+ Close the archive and reopen it.
+
+ Above primarily from John Oleynick <juo@klinzhai.rutgers.edu>.
+
+ * util.c (find_inode_file): Use modulus when computing initial
+ loop index.
+ (add_inode): Zero out new entry.
+ From scott@sctc.com (Scott Hammond).
+
+ * cpio.h, copyin.c, copyout.c: Rename `struct cpio_header'
+ members from h_foo to c_foo.
+
+Wed May 20 00:09:26 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
+
+ * copyin.c: If we include a header file specifically to get
+ major et al., assume we have them.
+
+Mon Mar 9 19:29:20 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * mt.c (main): rmtclose the tape file descriptor.
+
+ * main.c (main): rmtclose the archive, if not in copy-pass mode.
+
+ * util.c (create_all_directories): Don't print a message when
+ creating a directory, for UNIX compat.
+
+ * copyin.c (process_copy_in), copypass.c (process_copy_pass):
+ Skip file if it has the same timestamp as existing file, not just
+ if it is older than existing file, for UNIX compat.
+
+Tue Mar 3 12:06:58 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
+
+ * main.c, mt.c (usage): Document long options as starting with
+ -- instead of +.
+
+ * extern.h: Only declare lseek if not _POSIX_VERSION.
+
+Tue Dec 24 00:19:45 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * copyin.c: Use MAJOR_IN_MKDEV and MAJOR_IN_SYSMACROS instead
+ of USG and _POSIX_VERSION to find major and minor macros.
+
+ * mt.c: Use unistd.h and stdlib.h if available.
+
+ * copyin.c, copyout.c, copypass.c, util.c, extern.h: Change
+ POSIX ifdefs to HAVE_UNISTD_H and _POSIX_VERSION.
+
+Sun Aug 25 06:31:08 1991 David J. MacKenzie (djm at apple-gunkies)
+
+ * Version 1.5.
+
+ * bcopy.c: New file (moved from util.c).
+
+ * mt.c (print_status): Not all hpux machines have mt_fileno
+ and mt_blkno; rather than trying to track HP's product line,
+ just assume none of them have them.
+
+ * util.c (copy_buf_out, copy_in_buf): Use more efficient
+ copying technique for a big speedup.
+
+Fri Aug 2 04:06:45 1991 David J. MacKenzie (djm at apple-gunkies)
+
+ * configure: Support +srcdir. Create config.status.
+ Remove it and Makefile if interrupted while creating them.
+
+Thu Jul 18 09:43:40 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * Many files: use __MSDOS__ instead of MSDOS.
+
+ * util.c, configure: Use NO_MTIO instead of HAVE_MTIO, to keep
+ up with tar and rtapelib.c.
+
+Mon Jul 15 13:45:30 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * configure: Also look in sys/signal.h for signal decl.
+
+Thu Jul 11 01:50:32 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * Version 1.4.
+
+ * configure: Remove /etc and /usr/etc from PATH to avoid
+ finding /etc/install.
+
+Wed Jul 10 01:40:07 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * makefile.pc: Rewrite for Turbo C 2.0.
+ * util.c [__TURBOC__] (utime): New function.
+ * alloca.c, tcexparg.c: New files.
+
+ * extern.h [STDC_HEADERS]: Don't declare malloc and realloc.
+
+ * main.c [MSDOS]: Make binary mode the default.
+ * copyin.c, copyout.c: Make stdin or stdout binary mode as
+ appropriate (so cpio archives don't get corrupted).
+
+ * Many files: Use <string.h> if STDC_HEADERS as well as if USG.
+
+ * configure, Makefile.in: $(INSTALLPROG) -> $(INSTALL),
+ $(INSTALLTEXT) -> $(INSTALLDATA).
+
+Mon Jul 8 23:18:28 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
+
+ * configure: For some library functions that might be missing,
+ conditionally add the .o files to Makefile instead of
+ defining func_MISSING.
+ * mkdir.c: Renamed from mkrmdir.c.
+
+Sat Jul 6 02:27:22 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * configure: echo messages to stdout, not stderr.
+ Use a test program to see if alloca needs -lPW.
+
+Thu Jun 27 16:15:15 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * copyin.c (process_copy_in), copyout.c (process_copy_out),
+ copypass.c (process_copy_pass): Check close return value for
+ delayed error notification because of NFS.
+
+Thu Jun 20 02:43:33 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * configure: Include $DEFS when compiling test programs.
+
+ * util.c: Only declare getpwuid and getgrgid if not POSIX.
+
+ * Version 1.3.
+
+ * copyin.c: Use time_t, not long, for time values.
+
+ * mt.c (print_status): Special cases for HP-UX and Ultrix.
+
+ * util.c: Compile bcopy if USG or STDC_HEADERS, not BCOPY_MISSING.
+
+Tue Jun 11 16:40:02 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * copyin.c: Don't include sys/sysmacros.h if _POSIX_SOURCE.
+
+ * copyin.c, copyout.c, copypass.c: Don't include sys/file.h if POSIX.
+
+ * util.c: Include sys/types.h before, not after, pwd.h and grp.h.
+
+ * configure: New shell script to aid configuration and create
+ Makefile from Makefile.in.
+
+ * copyin.c (process_copy_in): Use POSIX.2 fnmatch instead of
+ glob_match.
+
+Mon Jun 10 22:11:19 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * global.c, extern.h: New variable, name_end.
+ * main.c (process_args, usage): Add -0 +null option to set it.
+ * copypass.c (process_copy_pass), copyout.c (process_copy_out):
+ Use it.
+
+ * dstring.c (ds_fgetstr): New function made from ds_fgets.
+ (ds_fgets, ds_fgetname): Implement as front ends to ds_fgetstr.
+
+Sun Jun 2 15:45:24 1991 David J. MacKenzie (djm at wheat-chex)
+
+ * most files: use GPL version 2.
+
+Sat May 18 11:39:22 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
+
+ * copyin.c, copypass.c: Take out #ifdef MSDOS around chown.
+ * util.c [MSDOS]: Provide dummy chown.
+
+Fri May 17 21:29:05 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu)
+
+ * Version 1.2.
+
+ * makefile.pc, cpio.cs: Update for new source and object files.
+
+Fri Mar 15 05:48:36 1991 David J. MacKenzie (djm at geech.ai.mit.edu)
+
+ * global.c, extern.h: New variable `archive_desc'.
+ * main.c (process_args): Set it.
+ * copyout.c (process_copy_out), copyin.c (process_copy_in):
+ Use it.
+
+ * copyout.c (process_copy_out), copyin.c (process_copy_in):
+ Remote tapes are special and not seekable; don't fstat them.
+
+ * main.c (main, usage): Add -F, +file option. Use rmtopen.
+ (main): Exit after printing version number.
+ * util.c (empty_output_buffer): Use rmtwrite instead of write.
+ (fill_input_buffer): Use rmtread instead of read.
+ (tape_offline): Use rmtioctl instead of ioctl.
+ Test HAVE_MTIO instead of MTIO_MISSING, for tar compatibility.
+
+Thu Mar 14 17:49:57 1991 David J. MacKenzie (djm at geech.ai.mit.edu)
+
+ * util.c (create_all_directories): Use make_path to do the work.
+
+Sat Jan 12 15:32:15 1991 David J. MacKenzie (djm at geech.ai.mit.edu)
+
+ * copyin.c, copyout.c, copypass.c, util.c: Only declare
+ `errno' if not MSDOS. Some Unix errno.h do, some don't . . . .
+
+ * global.c, extern.h: Make `input_size' and `output_size'
+ unsigned, for 16 bit machines.
+
+ * copyin.c (print_name_with_quoting): All non-ctrl chars are
+ printable on MS-DOS.
+
+ * util.c (empty_output_buffer): Never make sparse files;
+ can create unrunnable executables.
+ * copyin.c, copyout.c, copypass.c: Callers changed.
+ * util.c (finish_output_file): Function removed.
+
+Tue Nov 6 15:47:16 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * copyin.c, util.c, extern.h: Rename copystring to xstrdup.
+
+Mon Oct 29 02:24:41 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * util.c (empty_output_buffer): Only make sparse files if
+ NO_SPARSE_FILES is undefined, to accomodate dumb kernels.
+
+Wed Jul 25 18:48:35 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * util.c (getuser, getgroup): Make uid and gid unsigned short,
+ not int.
+
+Sat Jul 21 00:44:44 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * copyin.c, copyout.c, copypass.c, util.c, cpio.h: Add ifdefs
+ for MSDOS.
+
+Sun Jul 15 23:51:48 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * copyin.c, copyout.c, copypass.c, global.c, extern.h, util.c:
+ Use longs where appropriate, for 16 bit machines.
+
+Sun Jul 8 22:58:06 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * main.c (process_args, usage): Change -b option to -O (old), to
+ allow adding byte swapping later.
+
+Sat Jul 7 14:48:35 1990 David J. MacKenzie (dave at edfmd)
+
+ * Version 1.1.
+
+ * cpio.h: Make `mtime' and `filesize' unsigned long.
+ * copyin.c (read_in_binary), copyout.c (write_out_header):
+ High short-word of `mtime' and `filesize' always comes first.
+
+ * (read_in_ascii, read_in_binary): New functions, from code in
+ read_in_header.
+ (read_in_header): Search for valid magic number, then fill in
+ rest of header using read_in_ascii and read_in_binary.
+ * global.c, extern.h: New variable, `binary_flag'.
+ * main.c (process_args): Recognize new -b +binary option.
+ * util.c [BCOPY_MISSING] (bcopy): New function.
+
+Wed Jul 4 00:40:58 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * main.c (process_args): Add local pointers to functions to
+ work around a pcc bug found on a Convex.
+
+ * copyin.c (process_copy_in), util.c (toss_input,
+ create_all_directories, add_inode): Don't use `index' as a
+ variable name.
+
+Tue Jul 3 02:33:36 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * version 1.0.
+
+Mon Jul 2 23:18:56 1990 David J. MacKenzie (djm at twiddle)
+
+ * copyin.c (process_copy_in), copyout.c (process_copy_out),
+ copypass.c (process_copy_pass): Print "1 block", not "1 blocks".
+
+ * copyin.c (process_copy_in), copypass.c (process_copy_pass):
+ Unlink existing dest. file unless either it is newer and
+ not unconditional, or it is a directory.
+
+Mon Jul 2 03:57:41 1990 David J. MacKenzie (dave at edfmd)
+
+ * util.c (xrealloc): New function.
+ * dstring.c (ds_resize): Use xrealloc instead of free and
+ xmalloc. Never shrink the string.
+
+ * copypass.c (process_copy_pass): More efficient
+ string handling while constructing output filename.
+
+ * global.c, extern.h, main.c, cpio.h: Change from an enum,
+ `copy_command', to a pointer to a void function, `copy_function'.
+
+ * cpio.h (struct cpio_header): Make most fields unsigned.
+ Rename h_filesize to h_filesizes and h_mtime to h_mtimes, and
+ add new `long' fields with the old names at the end of the
+ structure.
+ * copyin.c (read_in_header): Set the long fields from the
+ short arrays, making sure longs are aligned properly.
+ (process_copy_in, long_format): Use the long fields.
+ * copyout.c (write_out_header): Set the short arrays from the
+ long fields, making sure longs are aligned properly.
+ (process_copy_out): Use the long fields.
+
+ * global.c, extern.h: New variable `output_is_seekable'.
+ * util.c (empty_output_buffer): If output_is_seekable, use
+ lseek to write blocks of zeros.
+ (finish_output_file): New function.
+ * copyin.c (process_copy_in), copyout.c (process_copy_out),
+ copypass.c (process_copy_pass): Set `output_is_seekable'
+ correctly and call finish_output_file.
+ * main.c (initialize_buffers): Allocate space for sentinel in
+ `output_buffer'.
+
+ * global.c, extern.h: New variable `numeric_uid'.
+ * main.c (process_args): Accept -n +numeric-uid-gid option, like ls.
+ * copyin.c (long_format): Use numeric_uid.
+
+ * copyin.c (process_copy_in), copyout.c (process_copy_out),
+ copypass.c (process_copy_pass): Don't (for verbose) print the
+ names of files that are not copied because of errors. Try to
+ create missing directories for all file types. Free temporary
+ buffers on error.
+
+Sat Jun 30 14:28:45 1990 David J. MacKenzie (djm at apple-gunkies)
+
+ * version.c: New file.
+ * main.c: Add -V, +version option.
+ * Makefile [dist]: Extract version number from version.c.
+
+Sat Jun 30 12:44:47 1990 David J. MacKenzie (dave at edfmd)
+
+ * global.c, extern.h, copyin.c, copyout.c, util.c: Rename
+ `{input,output}_is_regular' to `{input,output}_is_special' and
+ reverse the truth value.
+
+ * global.c, extern.h: New variable `input_is_seekable' to
+ control whether to skip data with lseek or read.
+ * copyin.c (process_copy_in): Set it.
+ * util.c (toss_input): Use it.
+
+ * global.c, extern.h: New variable `xstat' that selects stat
+ or lstat for input files.
+ * main.c (process_args): New option -L, +dereference to set
+ xstat to stat instead of lstat.
+ (usage): Document it.
+ * copyout.c (process_copy_out), copypass.c
+ (process_copy_pass): Use *xstat on input file.
+
+Sat Jun 30 01:53:12 1990 David J. MacKenzie (dave at edfmd)
+
+ * dstring.c (ds_init): Return void because return value was
+ never used.
+ (ds_resize): Ditto, and free old value instead of new one.
+
+ * util.c (empty_output_buffer, fill_input_buffer,
+ copy_out_buf, copy_in_buf, toss_input, copy_files): Return
+ void instead of an error value and make errors fatal
+ immediately instead of several levels up, to prevent printing
+ of multiple error messages by different levels of functions.
+
+ * copyin.c (read_in_header): Return void, because the error
+ handling all happens at lower levels.
+ (print_name_with_quoting): New function.
+ (long_format): Call print_name_with_quoting. Take additional
+ arg for name of linked-to file, and print it if nonzero.
+ (process_copy_in): For verbose listing of symlinks, read in
+ the linkname and pass it to long_format.
+
+ * extern.h: Declare some more functions.
+
+Thu Jun 28 16:07:15 1990 David J. MacKenzie (dave at edfmd)
+
+ * copypass.c (process_copy_pass): Warn about unknown file types.
+
+ * copyout.c (process_copy_out): Check fstat return for error.
+ Record filesize of 0 for special files. Warn about unknown
+ file types.
+
+ * copyin.c (process_copy_in): Warn about unknown file types.
+ (read_in_header): Warn about byte-reversed binary headers.
+
+Sat Jun 23 22:50:45 1990 David J. MacKenzie (dave at edfmd)
+
+ * main.c (main): Set umask to 0 so permissions of created
+ files are preserved.
+
+ * copyin.c, copyout.c, copypass.c, util.c: Pass file
+ descriptors as ints, not pointers to ints.
+ Cast file timestamps and sizes to long *, not int *, for 16
+ bit machines.
+ Use lstat instead of stat, if available.
+ Handle FIFO's, sockets, and symlinks, if supported by O.S.
+
+ * copyin.c (process_copy_in), copyout.c (process_copy_out):
+ Don't consider FIFO'S, sockets, etc. to be possible tape drives.
+
+ * util.c (create_all_directories): Fix incorrect loop
+ termination check. Only copy string if it contains slashes.
+ Don't check whether directory "" exists.
+ (tape_offline): Code moved from get_next_reel.
+ (get_next_reel): Print message before taking tape offline.
+ Read a line of arbitrary length.
+
+ * copyout.c, copyin.c, copypass.c: Always use utime, not utimes.
+
+ * copyin.c (swab_short): New macro.
+ (swab_array): New function.
+ (read_in_header): In binary mode, if a byte-swapped header is
+ read, swap the bytes back.
+ (process_copy_in, process_copy_pass): Don't stat each file to
+ create unless !unconditional_flag. Create device files correctly.
+ Don't temporarily allow files being created to be read by
+ other users. Don't unnecessarily chmod special files.
+
+Thu May 31 20:51:43 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * copyin.c (long_format): Use mode_string to format
+ file protections instead of doing it ourselves.
+ (protections): Function removed.
+
+Sat Apr 14 02:31:01 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * cpio.h (struct cpio_header): Make inode, mode, uid, gid
+ fields unsigned.
+
+ * util.c (getgroup): New function.
+ * copyin.c (long_format): Print group name of files.
+ Print file size, etc. as unsigned integers, not signed.
+
+ * main.c (process_args): If -t is given and neither -i, -o, or
+ -p is given, assume -i.
+
+ * Add -f, +nonmatching option.
+ * main.c: Rename +out to +create, +in to +extract,
+ +modification-time to +preserve-modification-time,
+ +pass to +pass-through.
+
+ * copyin.c (process_copy_in), copypass.c (process_copy_pass):
+ Don't complain in chown fails because the user doesn't have
+ permission.
+
+Fri Apr 13 13:53:20 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * Add ifdefs for USG/Xenix.
+ * util.c (cpio_error): Function removed.
+ * Use error instead of cpio_error, so system error messages
+ will be included.
+ * cpio.h: Rename 'hdr_struct' to 'struct cpio_header'.
+ * Move definition of xmalloc from dstring.c to util.c.
+ * global.c, extern.c: Add global `program_name'.
+ * main.c (main): Set program_name.
+ (process_args): Rename +reset-atime to +reset-access-time,
+ +table to +list.
+ Have +block-size take an argument.
+
+Thu Apr 12 13:33:32 1990 David J. MacKenzie (djm at rice-chex)
+
+ * util.c (find_inode_file): Make inode an int, not a short.
+
+ * Make functions that don't return a value have type void.
+ Add some casts to function calls.
+
+Wed Apr 11 14:55:28 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * main.c (process_args): -i, -o, and -p don't take arguments.
+
+ * main.c (process_args): Get the non-option args from the
+ correct elements of argv.
+
+Tue Apr 10 00:20:26 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
+
+ * Indent source code and update copyrights.
+
+ * cpio.c (usage): Change `collection' to `archive' in message.
+
+Thu Dec 28 03:03:55 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * dstring.c (xmalloc): Don't return a null pointer if size is 0,
+ on the assumption that trying to allocate 0 bytes is a bug that
+ should be trapped.
+
+Wed Dec 20 03:24:48 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * All files: Change from GNU CPIO General Public License to
+ GNU General Public License.
+
+Mon Dec 18 13:18:36 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * Makefile: Add clean target and defines for CC and LDFLAGS.
+ Add dist target and SRCS, DISTFILES macros. Add tags and TAGS targets.
+ * dstring.c (ds_fgets): Read characters into an int, not char.
+ (xmalloc): New function.
+ (out_of_memory): Function removed.
+ Global: use xmalloc instead of malloc and out_of_memory.
+ * extern.h, global.c: Make flag variables ints instead of chars for
+ compatibility with getopt_long.
+ * extern.h: Declare more functions.
+ * main.c (usage): Put the whole usage message into a single string
+ and fix errors.
+ * util.c (create_all_directories): Remove unused variable.
+ (get_next_reel): Ditto.
+ * dstring.h: Declare function.
+
+Sat Dec 2 13:22:37 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
+
+ * main.c: Change +copy-pass option to +pass, +copy-in to +in,
+ +copy-out to +out, and +mkdir to +make-directories, and add null
+ option to terminate table.
+ (process_args): Use the same code to handle long and short named
+ options.
+ (usage): Mention long options in message.
+
+Local Variables:
+mode: indented-text
+left-margin: 8
+version-control: never
+End:
diff --git a/contrib/cpio/NEWS b/contrib/cpio/NEWS
new file mode 100644
index 0000000..5da98da
--- /dev/null
+++ b/contrib/cpio/NEWS
@@ -0,0 +1,64 @@
+
+Major changes in version 2.4:
+
+* new texinfo documentation
+* --sparse option to write sparse files
+* --only-verify-crc option to verify a CRC format archive
+* --no-absolute-paths option to ignore absolute paths
+* --quiet option to supress printing number of blocks copied
+* handle disk input errors more gracefully
+
+Major changes in version 2.3:
+
+* in newc and crc format archives, only store 1 copy of multiply linked files
+* handle multiply linked devices properly
+* handle multiply linked files with cpio -pl even when the source and
+ destination are on different file systems
+* support HPUX Context Dependent Files
+* read and write HPUX cpio archives
+* read System V.4 POSIX tar archives and HPUX POSIX tar archives
+* use rmdir, instead of unlink, to delete existing directories
+
+Major changes in version 2.2:
+
+* handle link counts correctly when reading binary cpio archives
+* configure checks for some libraries that SVR4 needs
+
+Major changes in version 2.1:
+
+* cpio can access remote non-device files as well as remote devices
+* fix bugs in the MS-DOS port
+* add --swap equivalent to -b option
+
+Version 2.0 adds the following features:
+
+Support for the SVR4 cpio formats, which can store inodes >65535, and
+for traditional and POSIX tar archives. Also adds these options:
+
+-A --append append to instead of replacing the archive
+-V --dot print a dot for each file processed
+-H --format select archive format
+-C --io-size select I/O block size in bytes
+-M --message print a message at end of media volumes
+--no-preserve-owner don't change files' owners when extracting
+-R --owner set files' owners when extracting
+-E --pattern-file list of shell filename patterns to process
+-s --swap-bytes handle byte-order differences when extracting files
+-S --swap-halfwords ditto
+-b like -sS
+-I input archive filename
+-k recognize corrupted archives (we alawys do it, though)
+-O output archive filename
+
+Some options of previous versions have been renamed in 2.0:
+
+--binary was replaced by --format=bin
+--portability was replaced by --format=odc
+
+Some options have changed meaning in 2.0, for SVR4 compatibility:
+
+-O used to select the binary archive format, now selects the output file
+-V used to print the version number, now prints a dot for each file
+
+Version 2.0 also fixes several bugs in the handling of files with
+multiple links and of multi-volume archives on floppy disks.
diff --git a/contrib/cpio/README b/contrib/cpio/README
new file mode 100644
index 0000000..8206e97
--- /dev/null
+++ b/contrib/cpio/README
@@ -0,0 +1,71 @@
+This is GNU cpio, a program to manage archives of files.
+As of version 2.0, it supports the features of the System V release 4
+cpio, including support for tar archives.
+
+This package also includes rmt, the remote tape server, and mt, a tape
+drive control program; these two programs will only be compiled if
+your system supports remote command execution, and tape drive control
+operations, respectively.
+
+See the file INSTALL for compilation and installation instructions for Unix.
+
+For non-Unix systems:
+
+makefile.pc is a makefile for Turbo C or C++ or Borland C++ on MS-DOS.
+
+makefile.os2 is a makefile for MS C and GNU C (emx/gcc) on OS/2.
+cpio.def is a linker definition file for the MS C OS/2 version.
+
+
+The main advantages of GNU cpio over Unix versions are:
+
+* It can access tape drives on other hosts using TCP/IP.
+
+* `-o' and `-p' can copy symbolic links either as symbolic links or,
+with `-L', as the files they point to.
+
+* `-i' automatically recognizes the archive format and tries to
+recover from corrupted archives.
+
+* The output of '-itv' looks like 'ls -l'.
+
+* It accepts long-named options as well as traditional
+single-character options.
+
+A few features of other versions of cpio are missing from GNU cpio, including:
+
+* The `-6' option to support Sixth Edition Unix cpio archives with `-i'.
+
+* An option to limit volume size, like afio -s.
+
+
+GNU cpio supports the POSIX.1 "ustar" tar format. GNU tar supports a
+somewhat different, early draft of that format. That draft format has
+a slightly different magic number in the tar header and doesn't
+include the path prefix part of the header, which allows storing file
+names that are longer than 100 characters. GNU cpio knows to
+recognize the nonstandard GNU tar "ustar" archives.
+
+The following patch to GNU tar 1.11.1 makes GNU tar recognize standard
+"ustar" archives, such as GNU cpio produces, except that it won't use
+the path prefix. Without this patch, GNU tar thinks that standard
+"ustar" archives are old-format tar archives and can not use the extra
+information that "ustar" format contains. If you use this patch,
+remember that you will lose the beginnings of paths that are longer
+than 100 characters. That's why it's not an official part of GNU tar.
+(Adding support for the path prefix to GNU tar is not trivial.)
+
+--- list.c.orig Mon Sep 14 17:04:03 1992
++++ list.c Wed Oct 14 14:02:28 1992
+@@ -439,7 +439,7 @@
+ st->st_ctime = from_oct(1+12, header->header.ctime);
+ }
+
+- if (0==strcmp(header->header.magic, TMAGIC)) {
++ if (0==strncmp(header->header.magic, TMAGIC, 5)) {
+ /* Unix Standard tar archive */
+ *stdp = 1;
+ if (wantug) {
+
+Mail suggestions and bug reports for GNU cpio to
+bug-gnu-utils@prep.ai.mit.edu.
diff --git a/contrib/cpio/alloca.c b/contrib/cpio/alloca.c
new file mode 100644
index 0000000..7061cec
--- /dev/null
+++ b/contrib/cpio/alloca.c
@@ -0,0 +1,495 @@
+/* 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
+
+#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
+
+#define NULL 0
+
+/* 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 use xmalloc.
+
+ Callers below should use malloc. */
+
+#ifndef emacs
+#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)
+ unsigned 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/cpio/copyin.c b/contrib/cpio/copyin.c
new file mode 100644
index 0000000..1cc7e47
--- /dev/null
+++ b/contrib/cpio/copyin.c
@@ -0,0 +1,1352 @@
+/* copyin.c - extract or list a cpio archive
+ Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "system.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "defer.h"
+#include "rmt.h"
+#ifndef FNM_PATHNAME
+#include <fnmatch.h>
+#endif
+
+#ifndef HAVE_LCHOWN
+#define lchown chown
+#endif
+
+static void read_pattern_file ();
+static void tape_skip_padding ();
+static void defer_copyin ();
+static void create_defered_links ();
+static void create_final_defers ();
+
+/* Return 16-bit integer I with the bytes swapped. */
+#define swab_short(i) ((((i) << 8) & 0xff00) | (((i) >> 8) & 0x00ff))
+
+/* Read the header, including the name of the file, from file
+ descriptor IN_DES into FILE_HDR. */
+
+void
+read_in_header (file_hdr, in_des)
+ struct new_cpio_header *file_hdr;
+ int in_des;
+{
+ long bytes_skipped = 0; /* Bytes of junk found before magic number. */
+
+ /* Search for a valid magic number. */
+
+ if (archive_format == arf_unknown)
+ {
+ char tmpbuf[512];
+ int check_tar;
+ int peeked_bytes;
+
+ while (archive_format == arf_unknown)
+ {
+ peeked_bytes = tape_buffered_peek (tmpbuf, in_des, 512);
+ if (peeked_bytes < 6)
+ error (1, 0, "premature end of archive");
+
+ if (!strncmp (tmpbuf, "070701", 6))
+ archive_format = arf_newascii;
+ else if (!strncmp (tmpbuf, "070707", 6))
+ archive_format = arf_oldascii;
+ else if (!strncmp (tmpbuf, "070702", 6))
+ {
+ archive_format = arf_crcascii;
+ crc_i_flag = TRUE;
+ }
+ else if ((*((unsigned short *) tmpbuf) == 070707) ||
+ (*((unsigned short *) tmpbuf) == swab_short ((unsigned short) 070707)))
+ archive_format = arf_binary;
+ else if (peeked_bytes >= 512
+ && (check_tar = is_tar_header (tmpbuf)))
+ {
+ if (check_tar == 2)
+ archive_format = arf_ustar;
+ else
+ archive_format = arf_tar;
+ }
+ else
+ {
+ tape_buffered_read ((char *) tmpbuf, in_des, 1L);
+ ++bytes_skipped;
+ }
+ }
+ }
+
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ if (append_flag)
+ last_header_start = input_bytes - io_block_size +
+ (in_buff - input_buffer);
+ if (bytes_skipped > 0)
+ error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
+ read_in_tar_header (file_hdr, in_des);
+ return;
+ }
+
+ file_hdr->c_tar_linkname = NULL;
+
+ tape_buffered_read ((char *) file_hdr, in_des, 6L);
+ while (1)
+ {
+ if (append_flag)
+ last_header_start = input_bytes - io_block_size
+ + (in_buff - input_buffer) - 6;
+ if (archive_format == arf_newascii
+ && !strncmp ((char *) file_hdr, "070701", 6))
+ {
+ if (bytes_skipped > 0)
+ error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
+ read_in_new_ascii (file_hdr, in_des);
+ break;
+ }
+ if (archive_format == arf_crcascii
+ && !strncmp ((char *) file_hdr, "070702", 6))
+ {
+ if (bytes_skipped > 0)
+ error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
+ read_in_new_ascii (file_hdr, in_des);
+ break;
+ }
+ if ( (archive_format == arf_oldascii || archive_format == arf_hpoldascii)
+ && !strncmp ((char *) file_hdr, "070707", 6))
+ {
+ if (bytes_skipped > 0)
+ error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
+ read_in_old_ascii (file_hdr, in_des);
+ break;
+ }
+ if ( (archive_format == arf_binary || archive_format == arf_hpbinary)
+ && (file_hdr->c_magic == 070707
+ || file_hdr->c_magic == swab_short ((unsigned short) 070707)))
+ {
+ /* Having to skip 1 byte because of word alignment is normal. */
+ if (bytes_skipped > 0)
+ error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
+ read_in_binary (file_hdr, in_des);
+ break;
+ }
+ bytes_skipped++;
+ bcopy ((char *) file_hdr + 1, (char *) file_hdr, 5);
+ tape_buffered_read ((char *) file_hdr + 5, in_des, 1L);
+ }
+}
+
+/* Fill in FILE_HDR by reading an old-format ASCII format cpio header from
+ file descriptor IN_DES, except for the magic number, which is
+ already filled in. */
+
+void
+read_in_old_ascii (file_hdr, in_des)
+ struct new_cpio_header *file_hdr;
+ int in_des;
+{
+ char ascii_header[78];
+ unsigned long dev;
+ unsigned long rdev;
+
+ tape_buffered_read (ascii_header, in_des, 70L);
+ ascii_header[70] = '\0';
+ sscanf (ascii_header,
+ "%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo",
+ &dev, &file_hdr->c_ino,
+ &file_hdr->c_mode, &file_hdr->c_uid, &file_hdr->c_gid,
+ &file_hdr->c_nlink, &rdev, &file_hdr->c_mtime,
+ &file_hdr->c_namesize, &file_hdr->c_filesize);
+ file_hdr->c_dev_maj = major (dev);
+ file_hdr->c_dev_min = minor (dev);
+ file_hdr->c_rdev_maj = major (rdev);
+ file_hdr->c_rdev_min = minor (rdev);
+
+ /* Read file name from input. */
+ if (file_hdr->c_name != NULL)
+ free (file_hdr->c_name);
+ file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize + 1);
+ tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize);
+#ifndef __MSDOS__
+ /* HP/UX cpio creates archives that look just like ordinary archives,
+ but for devices it sets major = 0, minor = 1, and puts the
+ actual major/minor number in the filesize field. See if this
+ is an HP/UX cpio archive, and if so fix it. We have to do this
+ here because process_copy_in() assumes filesize is always 0
+ for devices. */
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ if (file_hdr->c_filesize != 0
+ && file_hdr->c_rdev_maj == 0
+ && file_hdr->c_rdev_min == 1)
+ {
+ file_hdr->c_rdev_maj = major (file_hdr->c_filesize);
+ file_hdr->c_rdev_min = minor (file_hdr->c_filesize);
+ file_hdr->c_filesize = 0;
+ }
+ break;
+ default:
+ break;
+ }
+#endif /* __MSDOS__ */
+}
+
+/* Fill in FILE_HDR by reading a new-format ASCII format cpio header from
+ file descriptor IN_DES, except for the magic number, which is
+ already filled in. */
+
+void
+read_in_new_ascii (file_hdr, in_des)
+ struct new_cpio_header *file_hdr;
+ int in_des;
+{
+ char ascii_header[112];
+
+ tape_buffered_read (ascii_header, in_des, 104L);
+ ascii_header[104] = '\0';
+ sscanf (ascii_header,
+ "%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx",
+ &file_hdr->c_ino, &file_hdr->c_mode, &file_hdr->c_uid,
+ &file_hdr->c_gid, &file_hdr->c_nlink, &file_hdr->c_mtime,
+ &file_hdr->c_filesize, &file_hdr->c_dev_maj, &file_hdr->c_dev_min,
+ &file_hdr->c_rdev_maj, &file_hdr->c_rdev_min, &file_hdr->c_namesize,
+ &file_hdr->c_chksum);
+ /* Read file name from input. */
+ if (file_hdr->c_name != NULL)
+ free (file_hdr->c_name);
+ file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize);
+ tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize);
+
+ /* In SVR4 ASCII format, the amount of space allocated for the header
+ is rounded up to the next long-word, so we might need to drop
+ 1-3 bytes. */
+ tape_skip_padding (in_des, file_hdr->c_namesize + 110);
+}
+
+/* Fill in FILE_HDR by reading a binary format cpio header from
+ file descriptor IN_DES, except for the first 6 bytes (the magic
+ number, device, and inode number), which are already filled in. */
+
+void
+read_in_binary (file_hdr, in_des)
+ struct new_cpio_header *file_hdr;
+ int in_des;
+{
+ struct old_cpio_header short_hdr;
+
+ /* Copy the data into the short header, then later transfer
+ it into the argument long header. */
+ short_hdr.c_dev = ((struct old_cpio_header *) file_hdr)->c_dev;
+ short_hdr.c_ino = ((struct old_cpio_header *) file_hdr)->c_ino;
+ tape_buffered_read (((char *) &short_hdr) + 6, in_des, 20L);
+
+ /* If the magic number is byte swapped, fix the header. */
+ if (file_hdr->c_magic == swab_short ((unsigned short) 070707))
+ {
+ static int warned = 0;
+
+ /* Alert the user that they might have to do byte swapping on
+ the file contents. */
+ if (warned == 0)
+ {
+ error (0, 0, "warning: archive header has reverse byte-order");
+ warned = 1;
+ }
+ swab_array ((char *) &short_hdr, 13);
+ }
+
+ file_hdr->c_dev_maj = major (short_hdr.c_dev);
+ file_hdr->c_dev_min = minor (short_hdr.c_dev);
+ file_hdr->c_ino = short_hdr.c_ino;
+ file_hdr->c_mode = short_hdr.c_mode;
+ file_hdr->c_uid = short_hdr.c_uid;
+ file_hdr->c_gid = short_hdr.c_gid;
+ file_hdr->c_nlink = short_hdr.c_nlink;
+ file_hdr->c_rdev_maj = major (short_hdr.c_rdev);
+ file_hdr->c_rdev_min = minor (short_hdr.c_rdev);
+ file_hdr->c_mtime = (unsigned long) short_hdr.c_mtimes[0] << 16
+ | short_hdr.c_mtimes[1];
+
+ file_hdr->c_namesize = short_hdr.c_namesize;
+ file_hdr->c_filesize = (unsigned long) short_hdr.c_filesizes[0] << 16
+ | short_hdr.c_filesizes[1];
+
+ /* Read file name from input. */
+ if (file_hdr->c_name != NULL)
+ free (file_hdr->c_name);
+ file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize);
+ tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize);
+
+ /* In binary mode, the amount of space allocated in the header for
+ the filename is `c_namesize' rounded up to the next short-word,
+ so we might need to drop a byte. */
+ if (file_hdr->c_namesize % 2)
+ tape_toss_input (in_des, 1L);
+
+#ifndef __MSDOS__
+ /* HP/UX cpio creates archives that look just like ordinary archives,
+ but for devices it sets major = 0, minor = 1, and puts the
+ actual major/minor number in the filesize field. See if this
+ is an HP/UX cpio archive, and if so fix it. We have to do this
+ here because process_copy_in() assumes filesize is always 0
+ for devices. */
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ if (file_hdr->c_filesize != 0
+ && file_hdr->c_rdev_maj == 0
+ && file_hdr->c_rdev_min == 1)
+ {
+ file_hdr->c_rdev_maj = major (file_hdr->c_filesize);
+ file_hdr->c_rdev_min = minor (file_hdr->c_filesize);
+ file_hdr->c_filesize = 0;
+ }
+ break;
+ default:
+ break;
+ }
+#endif /* __MSDOS__ */
+}
+
+/* Exchange the bytes of each element of the array of COUNT shorts
+ starting at PTR. */
+
+void
+swab_array (ptr, count)
+ char *ptr;
+ int count;
+{
+ char tmp;
+
+ while (count-- > 0)
+ {
+ tmp = *ptr;
+ *ptr = *(ptr + 1);
+ ++ptr;
+ *ptr = tmp;
+ ++ptr;
+ }
+}
+
+/* Current time for verbose table. */
+static time_t current_time;
+
+/* Read the collection from standard input and create files
+ in the file system. */
+
+void
+process_copy_in ()
+{
+ char done = FALSE; /* True if trailer reached. */
+ int res; /* Result of various function calls. */
+ dynamic_string new_name; /* New file name for rename option. */
+ FILE *tty_in; /* Interactive file for rename option. */
+ FILE *tty_out; /* Interactive file for rename option. */
+ FILE *rename_in; /* Batch file for rename option. */
+ char *str_res; /* Result for string function. */
+ struct utimbuf times; /* For setting file times. */
+ struct stat file_stat; /* Output file stat record. */
+ struct new_cpio_header file_hdr; /* Output header information. */
+ int out_file_des; /* Output file descriptor. */
+ int in_file_des; /* Input file descriptor. */
+ char skip_file; /* Flag for use with patterns. */
+ int existing_dir; /* True if file is a dir & already exists. */
+ int i; /* Loop index variable. */
+ char *link_name = NULL; /* Name of hard and symbolic links. */
+#ifdef HPUX_CDF
+ int cdf_flag; /* True if file is a CDF. */
+ int cdf_char; /* Index of `+' char indicating a CDF. */
+#endif
+
+ /* Initialize the copy in. */
+ if (pattern_file_name)
+ read_pattern_file ();
+ file_hdr.c_name = NULL;
+ ds_init (&new_name, 128);
+ /* Initialize this in case it has members we don't know to set. */
+ bzero (&times, sizeof (struct utimbuf));
+
+ if (rename_batch_file)
+ {
+ rename_in = fopen (rename_batch_file, "r");
+ if (rename_in == NULL)
+ error (2, errno, CONSOLE);
+ }
+ else if (rename_flag)
+ {
+ /* Open interactive file pair for rename operation. */
+ tty_in = fopen (CONSOLE, "r");
+ if (tty_in == NULL)
+ error (2, errno, CONSOLE);
+ tty_out = fopen (CONSOLE, "w");
+ if (tty_out == NULL)
+ error (2, errno, CONSOLE);
+ }
+
+ /* Get date and time if needed for processing the table option. */
+ if (table_flag && verbose_flag)
+ time (&current_time);
+
+#ifdef __MSDOS__
+ setmode (archive_des, O_BINARY);
+#endif
+ /* Check whether the input file might be a tape. */
+ in_file_des = archive_des;
+ if (_isrmt (in_file_des))
+ {
+ input_is_special = 1;
+ input_is_seekable = 0;
+ }
+ else
+ {
+ if (fstat (in_file_des, &file_stat))
+ error (1, errno, "standard input is closed");
+ input_is_special =
+#ifdef S_ISBLK
+ S_ISBLK (file_stat.st_mode) ||
+#endif
+ S_ISCHR (file_stat.st_mode);
+ input_is_seekable = S_ISREG (file_stat.st_mode);
+ }
+ output_is_seekable = TRUE;
+
+ /* While there is more input in the collection, process the input. */
+ while (!done)
+ {
+ link_name = NULL;
+ swapping_halfwords = swapping_bytes = FALSE;
+
+ /* Start processing the next file by reading the header. */
+ read_in_header (&file_hdr, in_file_des);
+
+#ifdef DEBUG_CPIO
+ if (debug_flag)
+ {
+ struct new_cpio_header *h;
+ h = &file_hdr;
+ fprintf (stderr,
+ "magic = 0%o, ino = %d, mode = 0%o, uid = %d, gid = %d\n",
+ h->c_magic, h->c_ino, h->c_mode, h->c_uid, h->c_gid);
+ fprintf (stderr,
+ "nlink = %d, mtime = %d, filesize = %d, dev_maj = 0x%x\n",
+ h->c_nlink, h->c_mtime, h->c_filesize, h->c_dev_maj);
+ fprintf (stderr,
+ "dev_min = 0x%x, rdev_maj = 0x%x, rdev_min = 0x%x, namesize = %d\n",
+ h->c_dev_min, h->c_rdev_maj, h->c_rdev_min, h->c_namesize);
+ fprintf (stderr,
+ "chksum = %d, name = \"%s\", tar_linkname = \"%s\"\n",
+ h->c_chksum, h->c_name,
+ h->c_tar_linkname ? h->c_tar_linkname : "(null)" );
+
+ }
+#endif
+ /* Is this the header for the TRAILER file? */
+ if (strcmp ("TRAILER!!!", file_hdr.c_name) == 0)
+ {
+ done = TRUE;
+ break;
+ }
+
+ /* Do we have to ignore absolute paths, and if so, does the filename
+ have an absolute path? */
+ if (no_abs_paths_flag && file_hdr.c_name && file_hdr.c_name [0] == '/')
+ {
+ char *p;
+
+ p = file_hdr.c_name;
+ while (*p == '/')
+ ++p;
+ if (*p == '\0')
+ {
+ strcpy (file_hdr.c_name, ".");
+ }
+ else
+ {
+ char *non_abs_name;
+
+ non_abs_name = (char *) xmalloc (strlen (p) + 1);
+ strcpy (non_abs_name, p);
+ free (file_hdr.c_name);
+ file_hdr.c_name = non_abs_name;
+ }
+ }
+
+ /* Does the file name match one of the given patterns? */
+ if (num_patterns <= 0)
+ skip_file = FALSE;
+ else
+ {
+ skip_file = copy_matching_files;
+ for (i = 0; i < num_patterns
+ && skip_file == copy_matching_files; i++)
+ {
+ if (fnmatch (save_patterns[i], file_hdr.c_name, 0) == 0)
+ skip_file = !copy_matching_files;
+ }
+ }
+
+ if (skip_file)
+ {
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ }
+ else if (table_flag)
+ {
+ if (verbose_flag)
+ {
+#ifdef CP_IFLNK
+ if ((file_hdr.c_mode & CP_IFMT) == CP_IFLNK)
+ {
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ {
+ link_name = (char *) xmalloc ((unsigned int) file_hdr.c_filesize + 1);
+ link_name[file_hdr.c_filesize] = '\0';
+ tape_buffered_read (link_name, in_file_des, file_hdr.c_filesize);
+ long_format (&file_hdr, link_name);
+ free (link_name);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ continue;
+ }
+ else
+ {
+ long_format (&file_hdr, file_hdr.c_tar_linkname);
+ continue;
+ }
+ }
+ else
+#endif
+ long_format (&file_hdr, (char *) 0);
+ }
+ else
+ printf ("%s\n", file_hdr.c_name);
+
+ crc = 0;
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ if (only_verify_crc_flag)
+ {
+#ifdef CP_IFLNK
+ if ((file_hdr.c_mode & CP_IFMT) == CP_IFLNK)
+ continue; /* links don't have a checksum */
+#endif
+ if (crc != file_hdr.c_chksum)
+ error (0, 0, "%s: checksum error (0x%x, should be 0x%x)",
+ file_hdr.c_name, crc, file_hdr.c_chksum);
+ }
+ }
+ else if (append_flag)
+ {
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ }
+ else if (only_verify_crc_flag)
+ {
+#ifdef CP_IFLNK
+ if ((file_hdr.c_mode & CP_IFMT) == CP_IFLNK)
+ {
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ {
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ continue;
+ }
+ }
+#endif
+ crc = 0;
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ if (crc != file_hdr.c_chksum)
+ error (0, 0, "%s: checksum error (0x%x, should be 0x%x)",
+ file_hdr.c_name, crc, file_hdr.c_chksum);
+ }
+ else
+ {
+ /* Copy the input file into the directory structure. */
+
+ /* Do we need to rename the file? */
+ if (rename_flag || rename_batch_file)
+ {
+ if (rename_flag)
+ {
+ fprintf (tty_out, "rename %s -> ", file_hdr.c_name);
+ fflush (tty_out);
+ str_res = ds_fgets (tty_in, &new_name);
+ }
+ else
+ {
+ str_res = ds_fgetstr (rename_in, &new_name, '\n');
+ }
+ if (str_res == NULL || str_res[0] == 0)
+ {
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ continue;
+ }
+ else
+ file_hdr.c_name = xstrdup (new_name.ds_string);
+ }
+
+ /* See if the file already exists. */
+ existing_dir = FALSE;
+ if (lstat (file_hdr.c_name, &file_stat) == 0)
+ {
+ if (S_ISDIR (file_stat.st_mode)
+ && ((file_hdr.c_mode & CP_IFMT) == CP_IFDIR))
+ {
+ /* If there is already a directory there that
+ we are trying to create, don't complain about
+ it. */
+ existing_dir = TRUE;
+ }
+ else if (!unconditional_flag
+ && file_hdr.c_mtime <= file_stat.st_mtime)
+ {
+ error (0, 0, "%s not created: newer or same age version exists",
+ file_hdr.c_name);
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ continue; /* Go to the next file. */
+ }
+ else if (S_ISDIR (file_stat.st_mode)
+ ? rmdir (file_hdr.c_name)
+ : unlink (file_hdr.c_name))
+ {
+ error (0, errno, "cannot remove current %s",
+ file_hdr.c_name);
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ continue; /* Go to the next file. */
+ }
+ }
+
+ /* Do the real copy or link. */
+ switch (file_hdr.c_mode & CP_IFMT)
+ {
+ case CP_IFREG:
+#ifndef __MSDOS__
+ /* Can the current file be linked to a previously copied file? */
+ if (file_hdr.c_nlink > 1 && (archive_format == arf_newascii
+ || archive_format == arf_crcascii) )
+ {
+ int link_res;
+ if (file_hdr.c_filesize == 0)
+ {
+ /* The newc and crc formats store multiply linked copies
+ of the same file in the archive only once. The
+ actual data is attached to the last link in the
+ archive, and the other links all have a filesize
+ of 0. Since this file has multiple links and a
+ filesize of 0, its data is probably attatched to
+ another file in the archive. Save the link, and
+ process it later when we get the actual data. We
+ can't just create it with length 0 and add the
+ data later, in case the file is readonly. We still
+ lose if its parent directory is readonly (and we aren't
+ running as root), but there's nothing we can do about
+ that. */
+ defer_copyin (&file_hdr);
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ break;
+ }
+ /* If the file has data (filesize != 0), then presumably
+ any other links have already been defer_copyin'ed(),
+ but GNU cpio version 2.0-2.2 didn't do that, so we
+ still have to check for links here (and also in case
+ the archive was created and later appeneded to). */
+ link_res = link_to_maj_min_ino (file_hdr.c_name,
+ file_hdr.c_dev_maj, file_hdr.c_dev_maj,
+ file_hdr.c_ino);
+ if (link_res == 0)
+ {
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ break;
+ }
+ }
+ else if (file_hdr.c_nlink > 1 && archive_format != arf_tar
+ && archive_format != arf_ustar)
+ {
+ int link_res;
+ link_res = link_to_maj_min_ino (file_hdr.c_name,
+ file_hdr.c_dev_maj, file_hdr.c_dev_maj,
+ file_hdr.c_ino);
+ if (link_res == 0)
+ {
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ break;
+ }
+ }
+ else if ((archive_format == arf_tar || archive_format == arf_ustar)
+ && file_hdr.c_tar_linkname &&
+ file_hdr.c_tar_linkname[0] != '\0')
+ {
+ int link_res;
+ link_res = link_to_name (file_hdr.c_name,
+ file_hdr.c_tar_linkname);
+ if (link_res < 0)
+ {
+ error (0, errno, "cannot link %s to %s",
+ file_hdr.c_tar_linkname, file_hdr.c_name);
+ }
+ break;
+ }
+#endif
+
+ /* If not linked, copy the contents of the file. */
+ if (link_name == NULL)
+ {
+ out_file_des = open (file_hdr.c_name,
+ O_CREAT | O_WRONLY | O_BINARY, 0600);
+ if (out_file_des < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr.c_name);
+ out_file_des = open (file_hdr.c_name,
+ O_CREAT | O_WRONLY | O_BINARY,
+ 0600);
+ }
+ if (out_file_des < 0)
+ {
+ error (0, errno, "%s", file_hdr.c_name);
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ continue;
+ }
+
+ crc = 0;
+ if (swap_halfwords_flag)
+ {
+ if ((file_hdr.c_filesize % 4) == 0)
+ swapping_halfwords = TRUE;
+ else
+ error (0, 0, "cannot swap halfwords of %s: odd number of halfwords",
+ file_hdr.c_name);
+ }
+ if (swap_bytes_flag)
+ {
+ if ((file_hdr.c_filesize % 2) == 0)
+ swapping_bytes = TRUE;
+ else
+ error (0, 0, "cannot swap bytes of %s: odd number of bytes",
+ file_hdr.c_name);
+ }
+ copy_files_tape_to_disk (in_file_des, out_file_des, file_hdr.c_filesize);
+ disk_empty_output_buffer (out_file_des);
+ if (close (out_file_des) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+
+ if (archive_format == arf_crcascii)
+ {
+ if (crc != file_hdr.c_chksum)
+ error (0, 0, "%s: checksum error (0x%x, should be 0x%x)",
+ file_hdr.c_name, crc, file_hdr.c_chksum);
+ }
+ /* File is now copied; set attributes. */
+ if (!no_chown_flag)
+ if ((chown (file_hdr.c_name,
+ set_owner_flag ? set_owner : file_hdr.c_uid,
+ set_group_flag ? set_group : file_hdr.c_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", file_hdr.c_name);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (file_hdr.c_name, (int) file_hdr.c_mode) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = file_hdr.c_mtime;
+ if (utime (file_hdr.c_name, &times) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ }
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ if (file_hdr.c_nlink > 1 && (archive_format == arf_newascii
+ || archive_format == arf_crcascii) )
+ {
+ /* (see comment above for how the newc and crc formats
+ store multiple links). Now that we have the data
+ for this file, create any other links to it which
+ we defered. */
+ create_defered_links (&file_hdr);
+ }
+ }
+ break;
+
+ case CP_IFDIR:
+ /* Strip any trailing `/'s off the filename; tar puts
+ them on. We might as well do it here in case anybody
+ else does too, since they cause strange things to happen. */
+ strip_trailing_slashes (file_hdr.c_name);
+
+ /* Ignore the current directory. It must already exist,
+ and we don't want to change its permission, ownership
+ or time. */
+ if (file_hdr.c_name[0] == '.' && file_hdr.c_name[1] == '\0')
+ break;
+
+#ifdef HPUX_CDF
+ cdf_flag = 0;
+#endif
+ if (!existing_dir)
+
+ {
+#ifdef HPUX_CDF
+ /* If the directory name ends in a + and is SUID,
+ then it is a CDF. Strip the trailing + from
+ the name before creating it. */
+ cdf_char = strlen (file_hdr.c_name) - 1;
+ if ( (cdf_char > 0) &&
+ (file_hdr.c_mode & 04000) &&
+ (file_hdr.c_name [cdf_char] == '+') )
+ {
+ file_hdr.c_name [cdf_char] = '\0';
+ cdf_flag = 1;
+ }
+#endif
+ res = mkdir (file_hdr.c_name, file_hdr.c_mode);
+ }
+ else
+ res = 0;
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr.c_name);
+ res = mkdir (file_hdr.c_name, file_hdr.c_mode);
+ }
+ if (res < 0)
+ {
+ /* In some odd cases where the file_hdr.c_name includes `.',
+ the directory may have actually been created by
+ create_all_directories(), so the mkdir will fail
+ because the directory exists. If that's the case,
+ don't complain about it. */
+ if ( (errno != EEXIST) ||
+ (lstat (file_hdr.c_name, &file_stat) != 0) ||
+ !(S_ISDIR (file_stat.st_mode) ) )
+ {
+ error (0, errno, "%s", file_hdr.c_name);
+ continue;
+ }
+ }
+ if (!no_chown_flag)
+ if ((chown (file_hdr.c_name,
+ set_owner_flag ? set_owner : file_hdr.c_uid,
+ set_group_flag ? set_group : file_hdr.c_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", file_hdr.c_name);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (file_hdr.c_name, (int) file_hdr.c_mode) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+#ifdef HPUX_CDF
+ if (cdf_flag)
+ /* Once we "hide" the directory with the chmod(),
+ we have to refer to it using name+ instead of name. */
+ file_hdr.c_name [cdf_char] = '+';
+#endif
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = file_hdr.c_mtime;
+ if (utime (file_hdr.c_name, &times) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ }
+ break;
+
+#ifndef __MSDOS__
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ if (file_hdr.c_nlink > 1 && archive_format != arf_tar
+ && archive_format != arf_ustar)
+ {
+ int link_res;
+ link_res = link_to_maj_min_ino (file_hdr.c_name,
+ file_hdr.c_dev_maj, file_hdr.c_dev_maj,
+ file_hdr.c_ino);
+ if (link_res == 0)
+ break;
+ }
+ else if (archive_format == arf_ustar &&
+ file_hdr.c_tar_linkname &&
+ file_hdr.c_tar_linkname [0] != '\0')
+ {
+ int link_res;
+ link_res = link_to_name (file_hdr.c_name,
+ file_hdr.c_tar_linkname);
+ if (link_res < 0)
+ {
+ error (0, errno, "cannot link %s to %s",
+ file_hdr.c_tar_linkname, file_hdr.c_name);
+ /* Something must be wrong, because we couldn't
+ find the file to link to. But can we assume
+ that the device maj/min numbers are correct
+ and fall through to the mknod? It's probably
+ safer to just break, rather than possibly
+ creating a bogus device file. */
+ }
+ break;
+ }
+
+ res = mknod (file_hdr.c_name, file_hdr.c_mode,
+ makedev (file_hdr.c_rdev_maj, file_hdr.c_rdev_min));
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr.c_name);
+ res = mknod (file_hdr.c_name, file_hdr.c_mode,
+ makedev (file_hdr.c_rdev_maj, file_hdr.c_rdev_min));
+ }
+ if (res < 0)
+ {
+ error (0, errno, "%s", file_hdr.c_name);
+ continue;
+ }
+ if (!no_chown_flag)
+ if ((chown (file_hdr.c_name,
+ set_owner_flag ? set_owner : file_hdr.c_uid,
+ set_group_flag ? set_group : file_hdr.c_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", file_hdr.c_name);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (file_hdr.c_name, file_hdr.c_mode) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = file_hdr.c_mtime;
+ if (utime (file_hdr.c_name, &times) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ }
+ break;
+#endif
+
+#ifdef CP_IFLNK
+ case CP_IFLNK:
+ {
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ {
+ link_name = (char *) xmalloc ((unsigned int) file_hdr.c_filesize + 1);
+ link_name[file_hdr.c_filesize] = '\0';
+ tape_buffered_read (link_name, in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ }
+ else
+ {
+ link_name = xstrdup (file_hdr.c_tar_linkname);
+ }
+
+ res = UMASKED_SYMLINK (link_name, file_hdr.c_name,
+ file_hdr.c_mode);
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (file_hdr.c_name);
+ res = UMASKED_SYMLINK (link_name, file_hdr.c_name,
+ file_hdr.c_mode);
+ }
+ if (res < 0)
+ {
+ error (0, errno, "%s", file_hdr.c_name);
+ free (link_name);
+ link_name = NULL;
+ continue;
+ }
+ if (!no_chown_flag)
+ if ((lchown (file_hdr.c_name,
+ set_owner_flag ? set_owner : file_hdr.c_uid,
+ set_group_flag ? set_group : file_hdr.c_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", file_hdr.c_name);
+ free (link_name);
+ link_name = NULL;
+ }
+ break;
+#endif
+
+ default:
+ error (0, 0, "%s: unknown file type", file_hdr.c_name);
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ }
+
+ if (verbose_flag)
+ fprintf (stderr, "%s\n", file_hdr.c_name);
+ if (dot_flag)
+ fputc ('.', stderr);
+ }
+ }
+
+ if (dot_flag)
+ fputc ('\n', stderr);
+
+ if (append_flag)
+ return;
+
+ if (archive_format == arf_newascii || archive_format == arf_crcascii)
+ create_final_defers ();
+ if (!quiet_flag)
+ {
+ res = (input_bytes + io_block_size - 1) / io_block_size;
+ if (res == 1)
+ fprintf (stderr, "1 block\n");
+ else
+ fprintf (stderr, "%d blocks\n", res);
+ }
+}
+
+/* Print the file described by FILE_HDR in long format.
+ If LINK_NAME is nonzero, it is the name of the file that
+ this file is a symbolic link to. */
+
+void
+long_format (file_hdr, link_name)
+ struct new_cpio_header *file_hdr;
+ char *link_name;
+{
+ char mbuf[11];
+ char tbuf[40];
+ time_t when;
+
+ mode_string (file_hdr->c_mode, mbuf);
+ mbuf[10] = '\0';
+
+ /* Get time values ready to print. */
+ when = file_hdr->c_mtime;
+ strcpy (tbuf, ctime (&when));
+ if (current_time - when > 6L * 30L * 24L * 60L * 60L
+ || current_time - when < 0L)
+ {
+ /* The file is older than 6 months, or in the future.
+ Show the year instead of the time of day. */
+ strcpy (tbuf + 11, tbuf + 19);
+ }
+ tbuf[16] = '\0';
+
+ printf ("%s %3u ", mbuf, file_hdr->c_nlink);
+
+#ifndef __MSDOS__
+ if (numeric_uid)
+#endif
+ printf ("%-8u %-8u ", (unsigned int) file_hdr->c_uid,
+ (unsigned int) file_hdr->c_gid);
+#ifndef __MSDOS__
+ else
+ printf ("%-8.8s %-8.8s ", getuser (file_hdr->c_uid),
+ getgroup (file_hdr->c_gid));
+
+ if ((file_hdr->c_mode & CP_IFMT) == CP_IFCHR
+ || (file_hdr->c_mode & CP_IFMT) == CP_IFBLK)
+ printf ("%3u, %3u ", file_hdr->c_rdev_maj,
+ file_hdr->c_rdev_min);
+ else
+#endif
+ printf ("%8lu ", file_hdr->c_filesize);
+
+ printf ("%s ", tbuf + 4);
+
+ print_name_with_quoting (file_hdr->c_name);
+ if (link_name)
+ {
+ printf (" -> ");
+ print_name_with_quoting (link_name);
+ }
+ putc ('\n', stdout);
+}
+
+void
+print_name_with_quoting (p)
+ register char *p;
+{
+ register unsigned char c;
+
+ while ( (c = *p++) )
+ {
+ switch (c)
+ {
+#ifndef __MSDOS__
+ case '\\':
+ printf ("\\\\");
+ break;
+#endif
+
+ case '\n':
+ printf ("\\n");
+ break;
+
+ case '\b':
+ printf ("\\b");
+ break;
+
+ case '\r':
+ printf ("\\r");
+ break;
+
+ case '\t':
+ printf ("\\t");
+ break;
+
+ case '\f':
+ printf ("\\f");
+ break;
+
+ case ' ':
+ printf ("\\ ");
+ break;
+
+ case '"':
+ printf ("\\\"");
+ break;
+
+ default:
+ if (c > 040 &&
+#ifdef __MSDOS__
+ c < 0377 && c != 0177
+#else
+ c < 0177
+#endif
+ )
+ putchar (c);
+ else
+ printf ("\\%03o", (unsigned int) c);
+ }
+ }
+}
+
+/* Read a pattern file (for the -E option). Put a list of
+ `num_patterns' elements in `save_patterns'. Any patterns that were
+ already in `save_patterns' (from the command line) are preserved. */
+
+static void
+read_pattern_file ()
+{
+ int max_new_patterns;
+ char **new_save_patterns;
+ int new_num_patterns;
+ int i;
+ dynamic_string pattern_name;
+ FILE *pattern_fp;
+
+ if (num_patterns < 0)
+ num_patterns = 0;
+ max_new_patterns = 1 + num_patterns;
+ new_save_patterns = (char **) xmalloc (max_new_patterns * sizeof (char *));
+ new_num_patterns = num_patterns;
+ ds_init (&pattern_name, 128);
+
+ pattern_fp = fopen (pattern_file_name, "r");
+ if (pattern_fp == NULL)
+ error (1, errno, "%s", pattern_file_name);
+ while (ds_fgetstr (pattern_fp, &pattern_name, '\n') != NULL)
+ {
+ if (new_num_patterns >= max_new_patterns)
+ {
+ max_new_patterns += 1;
+ new_save_patterns = (char **)
+ xrealloc ((char *) new_save_patterns,
+ max_new_patterns * sizeof (char *));
+ }
+ new_save_patterns[new_num_patterns] = xstrdup (pattern_name.ds_string);
+ ++new_num_patterns;
+ }
+ if (ferror (pattern_fp) || fclose (pattern_fp) == EOF)
+ error (1, errno, "%s", pattern_file_name);
+
+ for (i = 0; i < num_patterns; ++i)
+ new_save_patterns[i] = save_patterns[i];
+
+ save_patterns = new_save_patterns;
+ num_patterns = new_num_patterns;
+}
+
+/* Skip the padding on IN_FILE_DES after a header or file,
+ up to the next header.
+ The number of bytes skipped is based on OFFSET -- the current offset
+ from the last start of a header (or file) -- and the current
+ header type. */
+
+static void
+tape_skip_padding (in_file_des, offset)
+ int in_file_des;
+ int offset;
+{
+ int pad;
+
+ if (archive_format == arf_crcascii || archive_format == arf_newascii)
+ pad = (4 - (offset % 4)) % 4;
+ else if (archive_format == arf_binary || archive_format == arf_hpbinary)
+ pad = (2 - (offset % 2)) % 2;
+ else if (archive_format == arf_tar || archive_format == arf_ustar)
+ pad = (512 - (offset % 512)) % 512;
+ else
+ pad = 0;
+
+ if (pad != 0)
+ tape_toss_input (in_file_des, pad);
+}
+
+
+/* The newc and crc formats store multiply linked copies of the same file
+ in the archive only once. The actual data is attached to the last link
+ in the archive, and the other links all have a filesize of 0. When a
+ file in the archive has multiple links and a filesize of 0, its data is
+ probably "attatched" to another file in the archive, so we can't create
+ it right away. We have to "defer" creating it until we have created
+ the file that has the data "attatched" to it. We keep a list of the
+ "defered" links on deferments. */
+
+struct deferment *deferments = NULL;
+
+/* Add a file header to the deferments list. For now they all just
+ go on one list, although we could optimize this if necessary. */
+
+static void
+defer_copyin (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ struct deferment *d;
+ d = create_deferment (file_hdr);
+ d->next = deferments;
+ deferments = d;
+ return;
+}
+
+/* We just created a file that (probably) has some other links to it
+ which have been defered. Go through all of the links on the deferments
+ list and create any which are links to this file. */
+
+static void
+create_defered_links (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ struct deferment *d;
+ struct deferment *d_prev;
+ int ino;
+ int maj;
+ int min;
+ int link_res;
+ ino = file_hdr->c_ino;
+ maj = file_hdr->c_dev_maj;
+ min = file_hdr->c_dev_min;
+ d = deferments;
+ d_prev = NULL;
+ while (d != NULL)
+ {
+ if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj)
+ && (d->header.c_dev_min == min) )
+ {
+ struct deferment *d_free;
+ link_res = link_to_name (d->header.c_name, file_hdr->c_name);
+ if (link_res < 0)
+ {
+ error (0, errno, "cannot link %s to %s",
+ d->header.c_name, file_hdr->c_name);
+ }
+ if (d_prev != NULL)
+ d_prev->next = d->next;
+ else
+ deferments = d->next;
+ d_free = d;
+ d = d->next;
+ free_deferment (d_free);
+ }
+ else
+ {
+ d_prev = d;
+ d = d->next;
+ }
+ }
+}
+
+/* If we had a multiply linked file that really was empty then we would
+ have defered all of its links, since we never found any with data
+ "attached", and they will still be on the deferment list even when
+ we are done reading the whole archive. Write out all of these
+ empty links that are still on the deferments list. */
+
+static void
+create_final_defers ()
+{
+ struct deferment *d;
+ int link_res;
+ int out_file_des;
+ struct utimbuf times; /* For setting file times. */
+ /* Initialize this in case it has members we don't know to set. */
+ bzero (&times, sizeof (struct utimbuf));
+
+ for (d = deferments; d != NULL; d = d->next)
+ {
+ d = deferments;
+ link_res = link_to_maj_min_ino (d->header.c_name,
+ d->header.c_dev_maj, d->header.c_dev_maj,
+ d->header.c_ino);
+ if (link_res == 0)
+ {
+ continue;
+ }
+ out_file_des = open (d->header.c_name,
+ O_CREAT | O_WRONLY | O_BINARY, 0600);
+ if (out_file_des < 0 && create_dir_flag)
+ {
+ create_all_directories (d->header.c_name);
+ out_file_des = open (d->header.c_name,
+ O_CREAT | O_WRONLY | O_BINARY,
+ 0600);
+ }
+ if (out_file_des < 0)
+ {
+ error (0, errno, "%s", d->header.c_name);
+ continue;
+ }
+
+ if (close (out_file_des) < 0)
+ error (0, errno, "%s", d->header.c_name);
+
+ /* File is now copied; set attributes. */
+ if (!no_chown_flag)
+ if ((chown (d->header.c_name,
+ set_owner_flag ? set_owner : d->header.c_uid,
+ set_group_flag ? set_group : d->header.c_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", d->header.c_name);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (d->header.c_name, (int) d->header.c_mode) < 0)
+ error (0, errno, "%s", d->header.c_name);
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = d->header.c_mtime;
+ if (utime (d->header.c_name, &times) < 0)
+ error (0, errno, "%s", d->header.c_name);
+ }
+ }
+}
diff --git a/contrib/cpio/copyout.c b/contrib/cpio/copyout.c
new file mode 100644
index 0000000..22e9a0c
--- /dev/null
+++ b/contrib/cpio/copyout.c
@@ -0,0 +1,807 @@
+/* copyout.c - create a cpio archive
+ Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "system.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "defer.h"
+#include "rmt.h"
+
+static unsigned long read_for_checksum ();
+static void tape_clear_rest_of_block ();
+static void tape_pad_output ();
+static int last_link ();
+static int count_defered_links_to_dev_ino ();
+static void add_link_defer ();
+static void writeout_other_defers ();
+static void writeout_final_defers();
+static void writeout_defered_file ();
+
+/* Write out header FILE_HDR, including the file name, to file
+ descriptor OUT_DES. */
+
+void
+write_out_header (file_hdr, out_des)
+ struct new_cpio_header *file_hdr;
+ int out_des;
+{
+ if (archive_format == arf_newascii || archive_format == arf_crcascii)
+ {
+ char ascii_header[112];
+ char *magic_string;
+
+ if (archive_format == arf_crcascii)
+ magic_string = "070702";
+ else
+ magic_string = "070701";
+ sprintf (ascii_header,
+ "%6s%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx%08lx",
+ magic_string,
+ file_hdr->c_ino, file_hdr->c_mode, file_hdr->c_uid,
+ file_hdr->c_gid, file_hdr->c_nlink, file_hdr->c_mtime,
+ file_hdr->c_filesize, file_hdr->c_dev_maj, file_hdr->c_dev_min,
+ file_hdr->c_rdev_maj, file_hdr->c_rdev_min, file_hdr->c_namesize,
+ file_hdr->c_chksum);
+ tape_buffered_write (ascii_header, out_des, 110L);
+
+ /* Write file name to output. */
+ tape_buffered_write (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
+ tape_pad_output (out_des, file_hdr->c_namesize + 110);
+ }
+ else if (archive_format == arf_oldascii || archive_format == arf_hpoldascii)
+ {
+ char ascii_header[78];
+#ifndef __MSDOS__
+ dev_t dev;
+ dev_t rdev;
+
+ if (archive_format == arf_oldascii)
+ {
+ dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min);
+ rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min);
+ }
+ else
+ {
+ /* HP/UX cpio creates archives that look just like ordinary archives,
+ but for devices it sets major = 0, minor = 1, and puts the
+ actual major/minor number in the filesize field. */
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ file_hdr->c_filesize = makedev (file_hdr->c_rdev_maj,
+ file_hdr->c_rdev_min);
+ rdev = 1;
+ break;
+ default:
+ dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min);
+ rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min);
+ break;
+ }
+ }
+#else
+ int dev = 0, rdev = 0;
+#endif
+
+ if ((file_hdr->c_ino >> 16) != 0)
+ error (0, 0, "%s: truncating inode number", file_hdr->c_name);
+
+ sprintf (ascii_header,
+ "%06o%06o%06lo%06lo%06lo%06lo%06lo%06o%011lo%06lo%011lo",
+ file_hdr->c_magic & 0xFFFF, dev & 0xFFFF,
+ file_hdr->c_ino & 0xFFFF, file_hdr->c_mode & 0xFFFF,
+ file_hdr->c_uid & 0xFFFF, file_hdr->c_gid & 0xFFFF,
+ file_hdr->c_nlink & 0xFFFF, rdev & 0xFFFF,
+ file_hdr->c_mtime, file_hdr->c_namesize & 0xFFFF,
+ file_hdr->c_filesize);
+ tape_buffered_write (ascii_header, out_des, 76L);
+
+ /* Write file name to output. */
+ tape_buffered_write (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
+ }
+ else if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ write_out_tar_header (file_hdr, out_des);
+ }
+ else
+ {
+ struct old_cpio_header short_hdr;
+
+ short_hdr.c_magic = 070707;
+ short_hdr.c_dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min);
+
+ if ((file_hdr->c_ino >> 16) != 0)
+ error (0, 0, "%s: truncating inode number", file_hdr->c_name);
+
+ short_hdr.c_ino = file_hdr->c_ino & 0xFFFF;
+ short_hdr.c_mode = file_hdr->c_mode & 0xFFFF;
+ short_hdr.c_uid = file_hdr->c_uid & 0xFFFF;
+ short_hdr.c_gid = file_hdr->c_gid & 0xFFFF;
+ short_hdr.c_nlink = file_hdr->c_nlink & 0xFFFF;
+ if (archive_format != arf_hpbinary)
+ short_hdr.c_rdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min);
+ else
+ {
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ /* HP/UX cpio creates archives that look just like ordinary
+ archives, but for devices it sets major = 0, minor = 1, and
+ puts the actual major/minor number in the filesize field. */
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ file_hdr->c_filesize = makedev (file_hdr->c_rdev_maj,
+ file_hdr->c_rdev_min);
+ short_hdr.c_rdev = makedev (0, 1);
+ break;
+ default:
+ short_hdr.c_rdev = makedev (file_hdr->c_rdev_maj,
+ file_hdr->c_rdev_min);
+ break;
+ }
+ }
+ short_hdr.c_mtimes[0] = file_hdr->c_mtime >> 16;
+ short_hdr.c_mtimes[1] = file_hdr->c_mtime & 0xFFFF;
+
+ short_hdr.c_namesize = file_hdr->c_namesize & 0xFFFF;
+
+ short_hdr.c_filesizes[0] = file_hdr->c_filesize >> 16;
+ short_hdr.c_filesizes[1] = file_hdr->c_filesize & 0xFFFF;
+
+ /* Output the file header. */
+ tape_buffered_write ((char *) &short_hdr, out_des, 26L);
+
+ /* Write file name to output. */
+ tape_buffered_write (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
+
+ tape_pad_output (out_des, file_hdr->c_namesize + 26);
+ }
+}
+
+/* Read a list of file names from the standard input
+ and write a cpio collection on the standard output.
+ The format of the header depends on the compatibility (-c) flag. */
+
+void
+process_copy_out ()
+{
+ int res; /* Result of functions. */
+ dynamic_string input_name; /* Name of file read from stdin. */
+ struct utimbuf times; /* For resetting file times after copy. */
+ struct stat file_stat; /* Stat record for file. */
+ struct new_cpio_header file_hdr; /* Output header information. */
+ int in_file_des; /* Source file descriptor. */
+ int out_file_des; /* Output file descriptor. */
+ char *p;
+
+ /* Initialize the copy out. */
+ ds_init (&input_name, 128);
+ /* Initialize this in case it has members we don't know to set. */
+ bzero (&times, sizeof (struct utimbuf));
+ file_hdr.c_magic = 070707;
+
+#ifdef __MSDOS__
+ setmode (archive_des, O_BINARY);
+#endif
+ /* Check whether the output file might be a tape. */
+ out_file_des = archive_des;
+ if (_isrmt (out_file_des))
+ {
+ output_is_special = 1;
+ output_is_seekable = 0;
+ }
+ else
+ {
+ if (fstat (out_file_des, &file_stat))
+ error (1, errno, "standard output is closed");
+ output_is_special =
+#ifdef S_ISBLK
+ S_ISBLK (file_stat.st_mode) ||
+#endif
+ S_ISCHR (file_stat.st_mode);
+ output_is_seekable = S_ISREG (file_stat.st_mode);
+ }
+
+ if (append_flag)
+ {
+ process_copy_in ();
+ prepare_append (out_file_des);
+ }
+
+ /* Copy files with names read from stdin. */
+ while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
+ {
+ /* Check for blank line. */
+ if (input_name.ds_string[0] == 0)
+ {
+ error (0, 0, "blank line ignored");
+ continue;
+ }
+
+ /* Process next file. */
+ if ((*xstat) (input_name.ds_string, &file_stat) < 0)
+ error (0, errno, "%s", input_name.ds_string);
+ else
+ {
+ /* Set values in output header. */
+ file_hdr.c_dev_maj = major (file_stat.st_dev);
+ file_hdr.c_dev_min = minor (file_stat.st_dev);
+ file_hdr.c_ino = file_stat.st_ino;
+ /* For POSIX systems that don't define the S_IF macros,
+ we can't assume that S_ISfoo means the standard Unix
+ S_IFfoo bit(s) are set. So do it manually, with a
+ different name. Bleah. */
+ file_hdr.c_mode = (file_stat.st_mode & 07777);
+ if (S_ISREG (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFREG;
+ else if (S_ISDIR (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFDIR;
+#ifdef S_ISBLK
+ else if (S_ISBLK (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFBLK;
+#endif
+#ifdef S_ISCHR
+ else if (S_ISCHR (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFCHR;
+#endif
+#ifdef S_ISFIFO
+ else if (S_ISFIFO (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFIFO;
+#endif
+#ifdef S_ISLNK
+ else if (S_ISLNK (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFLNK;
+#endif
+#ifdef S_ISSOCK
+ else if (S_ISSOCK (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFSOCK;
+#endif
+#ifdef S_ISNWK
+ else if (S_ISNWK (file_stat.st_mode))
+ file_hdr.c_mode |= CP_IFNWK;
+#endif
+ file_hdr.c_uid = file_stat.st_uid;
+ file_hdr.c_gid = file_stat.st_gid;
+ file_hdr.c_nlink = file_stat.st_nlink;
+ file_hdr.c_rdev_maj = major (file_stat.st_rdev);
+ file_hdr.c_rdev_min = minor (file_stat.st_rdev);
+ file_hdr.c_mtime = file_stat.st_mtime;
+ file_hdr.c_filesize = file_stat.st_size;
+ file_hdr.c_chksum = 0;
+ file_hdr.c_tar_linkname = NULL;
+
+ /* Strip leading `./' from the filename. */
+ p = input_name.ds_string;
+ while (*p == '.' && *(p + 1) == '/')
+ {
+ ++p;
+ while (*p == '/')
+ ++p;
+ }
+#ifndef HPUX_CDF
+ file_hdr.c_name = p;
+ file_hdr.c_namesize = strlen (p) + 1;
+#else
+ if ( (archive_format != arf_tar) && (archive_format != arf_ustar) )
+ {
+ /* We mark CDF's in cpio files by adding a 2nd `/' after the
+ "hidden" directory name. We need to do this so we can
+ properly recreate the directory as hidden (in case the
+ files of a directory go into the archive before the
+ directory itself (e.g from "find ... -depth ... | cpio")). */
+ file_hdr.c_name = add_cdf_double_slashes (p);
+ file_hdr.c_namesize = strlen (file_hdr.c_name) + 1;
+ }
+ else
+ {
+ /* We don't mark CDF's in tar files. We assume the "hidden"
+ directory will always go into the archive before any of
+ its files. */
+ file_hdr.c_name = p;
+ file_hdr.c_namesize = strlen (p) + 1;
+ }
+#endif
+ if ((archive_format == arf_tar || archive_format == arf_ustar)
+ && is_tar_filename_too_long (file_hdr.c_name))
+ {
+ error (0, 0, "%s: file name too long", file_hdr.c_name);
+ continue;
+ }
+
+ /* Copy the named file to the output. */
+ switch (file_hdr.c_mode & CP_IFMT)
+ {
+ case CP_IFREG:
+#ifndef __MSDOS__
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ char *otherfile;
+ if ((otherfile = find_inode_file (file_hdr.c_ino,
+ file_hdr.c_dev_maj,
+ file_hdr.c_dev_min)))
+ {
+ file_hdr.c_tar_linkname = otherfile;
+ write_out_header (&file_hdr, out_file_des);
+ break;
+ }
+ }
+ if ( (archive_format == arf_newascii || archive_format == arf_crcascii)
+ && (file_hdr.c_nlink > 1) )
+ {
+ if (last_link (&file_hdr) )
+ {
+ writeout_other_defers (&file_hdr, out_file_des);
+ }
+ else
+ {
+ add_link_defer (&file_hdr);
+ break;
+ }
+ }
+#endif
+ in_file_des = open (input_name.ds_string,
+ O_RDONLY | O_BINARY, 0);
+ if (in_file_des < 0)
+ {
+ error (0, errno, "%s", input_name.ds_string);
+ continue;
+ }
+
+ if (archive_format == arf_crcascii)
+ file_hdr.c_chksum = read_for_checksum (in_file_des,
+ file_hdr.c_filesize,
+ input_name.ds_string);
+
+ write_out_header (&file_hdr, out_file_des);
+ copy_files_disk_to_tape (in_file_des, out_file_des, file_hdr.c_filesize, input_name.ds_string);
+
+#ifndef __MSDOS__
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ add_inode (file_hdr.c_ino, file_hdr.c_name, file_hdr.c_dev_maj,
+ file_hdr.c_dev_min);
+#endif
+
+ tape_pad_output (out_file_des, file_hdr.c_filesize);
+
+ if (close (in_file_des) < 0)
+ error (0, errno, "%s", input_name.ds_string);
+ if (reset_time_flag)
+ {
+ times.actime = file_stat.st_atime;
+ times.modtime = file_stat.st_mtime;
+ if (utime (file_hdr.c_name, &times) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ }
+ break;
+
+ case CP_IFDIR:
+ file_hdr.c_filesize = 0;
+ write_out_header (&file_hdr, out_file_des);
+ break;
+
+#ifndef __MSDOS__
+ case CP_IFCHR:
+ case CP_IFBLK:
+#ifdef CP_IFSOCK
+ case CP_IFSOCK:
+#endif
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+#endif
+ if (archive_format == arf_tar)
+ {
+ error (0, 0, "%s not dumped: not a regular file",
+ file_hdr.c_name);
+ continue;
+ }
+ else if (archive_format == arf_ustar)
+ {
+ char *otherfile;
+ if ((otherfile = find_inode_file (file_hdr.c_ino,
+ file_hdr.c_dev_maj,
+ file_hdr.c_dev_min)))
+ {
+ /* This file is linked to another file already in the
+ archive, so write it out as a hard link. */
+ file_hdr.c_mode = (file_stat.st_mode & 07777);
+ file_hdr.c_mode |= CP_IFREG;
+ file_hdr.c_tar_linkname = otherfile;
+ write_out_header (&file_hdr, out_file_des);
+ break;
+ }
+ add_inode (file_hdr.c_ino, file_hdr.c_name,
+ file_hdr.c_dev_maj, file_hdr.c_dev_min);
+ }
+ file_hdr.c_filesize = 0;
+ write_out_header (&file_hdr, out_file_des);
+ break;
+#endif
+
+#ifdef CP_IFLNK
+ case CP_IFLNK:
+ {
+ char *link_name = (char *) xmalloc (file_stat.st_size + 1);
+ int link_size;
+
+ link_size = readlink (input_name.ds_string, link_name,
+ file_stat.st_size);
+ if (link_size < 0)
+ {
+ error (0, errno, "%s", input_name.ds_string);
+ free (link_name);
+ continue;
+ }
+ file_hdr.c_filesize = link_size;
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ {
+ if (link_size + 1 > 100)
+ {
+ error (0, 0, "%s: symbolic link too long",
+ file_hdr.c_name);
+ }
+ else
+ {
+ link_name[link_size] = '\0';
+ file_hdr.c_tar_linkname = link_name;
+ write_out_header (&file_hdr, out_file_des);
+ }
+ }
+ else
+ {
+ write_out_header (&file_hdr, out_file_des);
+ tape_buffered_write (link_name, out_file_des, link_size);
+ tape_pad_output (out_file_des, link_size);
+ }
+ free (link_name);
+ }
+ break;
+#endif
+
+ default:
+ error (0, 0, "%s: unknown file type", input_name.ds_string);
+ }
+
+ if (verbose_flag)
+ fprintf (stderr, "%s\n", input_name.ds_string);
+ if (dot_flag)
+ fputc ('.', stderr);
+ }
+ }
+
+ writeout_final_defers(out_file_des);
+ /* The collection is complete; append the trailer. */
+ file_hdr.c_ino = 0;
+ file_hdr.c_mode = 0;
+ file_hdr.c_uid = 0;
+ file_hdr.c_gid = 0;
+ file_hdr.c_nlink = 1; /* Must be 1 for crc format. */
+ file_hdr.c_dev_maj = 0;
+ file_hdr.c_dev_min = 0;
+ file_hdr.c_rdev_maj = 0;
+ file_hdr.c_rdev_min = 0;
+ file_hdr.c_mtime = 0;
+ file_hdr.c_chksum = 0;
+
+ file_hdr.c_filesize = 0;
+ file_hdr.c_namesize = 11;
+ file_hdr.c_name = "TRAILER!!!";
+ if (archive_format != arf_tar && archive_format != arf_ustar)
+ write_out_header (&file_hdr, out_file_des);
+ else
+ {
+ tape_buffered_write (zeros_512, out_file_des, 512);
+ tape_buffered_write (zeros_512, out_file_des, 512);
+ }
+
+ /* Fill up the output block. */
+ tape_clear_rest_of_block (out_file_des);
+ tape_empty_output_buffer (out_file_des);
+ if (dot_flag)
+ fputc ('\n', stderr);
+ if (!quiet_flag)
+ {
+ res = (output_bytes + io_block_size - 1) / io_block_size;
+ if (res == 1)
+ fprintf (stderr, "1 block\n");
+ else
+ fprintf (stderr, "%d blocks\n", res);
+ }
+}
+
+/* Read FILE_SIZE bytes of FILE_NAME from IN_FILE_DES and
+ compute and return a checksum for them. */
+
+static unsigned long
+read_for_checksum (in_file_des, file_size, file_name)
+ int in_file_des;
+ int file_size;
+ char *file_name;
+{
+ unsigned long crc;
+ char buf[BUFSIZ];
+ int bytes_left;
+ int bytes_read;
+ int i;
+
+ crc = 0;
+
+ for (bytes_left = file_size; bytes_left > 0; bytes_left -= bytes_read)
+ {
+ bytes_read = read (in_file_des, buf, BUFSIZ);
+ if (bytes_read < 0)
+ error (1, errno, "cannot read checksum for %s", file_name);
+ if (bytes_read == 0)
+ break;
+ for (i = 0; i < bytes_read; ++i)
+ crc += buf[i] & 0xff;
+ }
+ if (lseek (in_file_des, 0L, SEEK_SET))
+ error (1, errno, "cannot read checksum for %s", file_name);
+
+ return crc;
+}
+
+/* Write out NULs to fill out the rest of the current block on
+ OUT_FILE_DES. */
+
+static void
+tape_clear_rest_of_block (out_file_des)
+ int out_file_des;
+{
+ while (output_size < io_block_size)
+ {
+ if ((io_block_size - output_size) > 512)
+ tape_buffered_write (zeros_512, out_file_des, 512);
+ else
+ tape_buffered_write (zeros_512, out_file_des, io_block_size - output_size);
+ }
+}
+
+/* Write NULs on OUT_FILE_DES to move from OFFSET (the current location)
+ to the end of the header. */
+
+static void
+tape_pad_output (out_file_des, offset)
+ int out_file_des;
+ int offset;
+{
+ int pad;
+
+ if (archive_format == arf_newascii || archive_format == arf_crcascii)
+ pad = (4 - (offset % 4)) % 4;
+ else if (archive_format == arf_tar || archive_format == arf_ustar)
+ pad = (512 - (offset % 512)) % 512;
+ else if (archive_format != arf_oldascii && archive_format != arf_hpoldascii)
+ pad = (2 - (offset % 2)) % 2;
+ else
+ pad = 0;
+
+ if (pad != 0)
+ tape_buffered_write (zeros_512, out_file_des, pad);
+}
+
+
+/* When creating newc and crc archives if a file has multiple (hard)
+ links, we don't put any of them into the archive until we have seen
+ all of them (or until we get to the end of the list of files that
+ are going into the archive and know that we have seen all of the links
+ to the file that we will see). We keep these "defered" files on
+ this list. */
+
+struct deferment *deferouts = NULL;
+
+
+/* Is this file_hdr the last (hard) link to a file? I.e., have
+ we already seen and defered all of the other links? */
+
+static int
+last_link (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ int other_files_sofar;
+
+ other_files_sofar = count_defered_links_to_dev_ino (file_hdr);
+ if (file_hdr->c_nlink == (other_files_sofar + 1) )
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/* Count the number of other (hard) links to this file that have
+ already been defered. */
+
+static int
+count_defered_links_to_dev_ino (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ struct deferment *d;
+ int ino;
+ int maj;
+ int min;
+ int count;
+ ino = file_hdr->c_ino;
+ maj = file_hdr->c_dev_maj;
+ min = file_hdr->c_dev_min;
+ count = 0;
+ for (d = deferouts; d != NULL; d = d->next)
+ {
+ if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj)
+ && (d->header.c_dev_min == min) )
+ ++count;
+ }
+ return count;
+}
+
+/* Add the file header for a link that is being defered to the deferouts
+ list. */
+
+static void
+add_link_defer (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ struct deferment *d;
+ d = create_deferment (file_hdr);
+ d->next = deferouts;
+ deferouts = d;
+}
+
+/* We are about to put a file into a newc or crc archive that is
+ multiply linked. We have already seen and defered all of the
+ other links to the file but haven't written them into the archive.
+ Write the other links into the archive, and remove them from the
+ deferouts list. */
+
+static void
+writeout_other_defers (file_hdr, out_des)
+ struct new_cpio_header *file_hdr;
+ int out_des;
+{
+ struct deferment *d;
+ struct deferment *d_prev;
+ int ino;
+ int maj;
+ int min;
+ ino = file_hdr->c_ino;
+ maj = file_hdr->c_dev_maj;
+ min = file_hdr->c_dev_min;
+ d_prev = NULL;
+ d = deferouts;
+ while (d != NULL)
+ {
+ if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj)
+ && (d->header.c_dev_min == min) )
+ {
+ struct deferment *d_free;
+ d->header.c_filesize = 0;
+ write_out_header (&d->header, out_des);
+ if (d_prev != NULL)
+ d_prev->next = d->next;
+ else
+ deferouts = d->next;
+ d_free = d;
+ d = d->next;
+ free_deferment (d_free);
+ }
+ else
+ {
+ d_prev = d;
+ d = d->next;
+ }
+ }
+ return;
+}
+/* When writing newc and crc format archives we defer multiply linked
+ files until we have seen all of the links to the file. If a file
+ has links to it that aren't going into the archive, then we will
+ never see the "last" link to the file, so at the end we just write
+ all of the leftover defered files into the archive. */
+
+static void
+writeout_final_defers(out_des)
+ int out_des;
+{
+ struct deferment *d;
+ int other_count;
+ while (deferouts != NULL)
+ {
+ d = deferouts;
+ other_count = count_defered_links_to_dev_ino (&d->header);
+ if (other_count == 1)
+ {
+ writeout_defered_file (&d->header, out_des);
+ }
+ else
+ {
+ struct new_cpio_header file_hdr;
+ file_hdr = d->header;
+ file_hdr.c_filesize = 0;
+ write_out_header (&file_hdr, out_des);
+ }
+ deferouts = deferouts->next;
+ }
+}
+
+/* Write a file into the archive. This code is the same as
+ the code in process_copy_out(), but we need it here too
+ for writeout_final_defers() to call. */
+
+static void
+writeout_defered_file (header, out_file_des)
+ struct new_cpio_header *header;
+ int out_file_des;
+{
+ int in_file_des;
+ struct new_cpio_header file_hdr;
+ struct utimbuf times; /* For setting file times. */
+ /* Initialize this in case it has members we don't know to set. */
+ bzero (&times, sizeof (struct utimbuf));
+
+ file_hdr = *header;
+
+
+ in_file_des = open (header->c_name,
+ O_RDONLY | O_BINARY, 0);
+ if (in_file_des < 0)
+ {
+ error (0, errno, "%s", header->c_name);
+ return;
+ }
+
+ if (archive_format == arf_crcascii)
+ file_hdr.c_chksum = read_for_checksum (in_file_des,
+ file_hdr.c_filesize,
+ header->c_name);
+
+ write_out_header (&file_hdr, out_file_des);
+ copy_files_disk_to_tape (in_file_des, out_file_des, file_hdr.c_filesize, header->c_name);
+
+#ifndef __MSDOS__
+ if (archive_format == arf_tar || archive_format == arf_ustar)
+ add_inode (file_hdr.c_ino, file_hdr.c_name, file_hdr.c_dev_maj,
+ file_hdr.c_dev_min);
+#endif
+
+ tape_pad_output (out_file_des, file_hdr.c_filesize);
+
+ if (close (in_file_des) < 0)
+ error (0, errno, "%s", header->c_name);
+ if (reset_time_flag)
+ {
+ times.actime = file_hdr.c_mtime;
+ times.modtime = file_hdr.c_mtime;
+ if (utime (file_hdr.c_name, &times) < 0)
+ error (0, errno, "%s", file_hdr.c_name);
+ }
+ return;
+}
diff --git a/contrib/cpio/copypass.c b/contrib/cpio/copypass.c
new file mode 100644
index 0000000..dde43d5
--- /dev/null
+++ b/contrib/cpio/copypass.c
@@ -0,0 +1,464 @@
+/* copypass.c - cpio copy pass sub-function.
+ Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "system.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+
+#ifndef HAVE_LCHOWN
+#define lchown chown
+#endif
+
+/* Copy files listed on the standard input into directory `directory_name'.
+ If `link_flag', link instead of copying. */
+
+void
+process_copy_pass ()
+{
+ dynamic_string input_name; /* Name of file from stdin. */
+ dynamic_string output_name; /* Name of new file. */
+ int dirname_len; /* Length of `directory_name'. */
+ int res; /* Result of functions. */
+ char *slash; /* For moving past slashes in input name. */
+ struct utimbuf times; /* For resetting file times after copy. */
+ struct stat in_file_stat; /* Stat record for input file. */
+ struct stat out_file_stat; /* Stat record for output file. */
+ int in_file_des; /* Input file descriptor. */
+ int out_file_des; /* Output file descriptor. */
+ int existing_dir; /* True if file is a dir & already exists. */
+#ifdef HPUX_CDF
+ int cdf_flag;
+ int cdf_char;
+#endif
+
+ /* Initialize the copy pass. */
+ dirname_len = strlen (directory_name);
+ ds_init (&input_name, 128);
+ ds_init (&output_name, dirname_len + 2);
+ strcpy (output_name.ds_string, directory_name);
+ output_name.ds_string[dirname_len] = '/';
+ output_is_seekable = TRUE;
+ /* Initialize this in case it has members we don't know to set. */
+ bzero (&times, sizeof (struct utimbuf));
+
+ /* Copy files with names read from stdin. */
+ while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
+ {
+ int link_res = -1;
+
+ /* Check for blank line and ignore it if found. */
+ if (input_name.ds_string[0] == '\0')
+ {
+ error (0, 0, "blank line ignored");
+ continue;
+ }
+
+ /* Check for current directory and ignore it if found. */
+ if (input_name.ds_string[0] == '.'
+ && (input_name.ds_string[1] == '\0'
+ || (input_name.ds_string[1] == '/'
+ && input_name.ds_string[2] == '\0')))
+ continue;
+
+ if ((*xstat) (input_name.ds_string, &in_file_stat) < 0)
+ {
+ error (0, errno, "%s", input_name.ds_string);
+ continue;
+ }
+
+ /* Make the name of the new file. */
+ for (slash = input_name.ds_string; *slash == '/'; ++slash)
+ ;
+#ifdef HPUX_CDF
+ /* For CDF's we add a 2nd `/' after all "hidden" directories.
+ This kind of a kludge, but it's what we do when creating
+ archives, and it's easier to do this than to separately
+ keep track of which directories in a path are "hidden". */
+ slash = add_cdf_double_slashes (slash);
+#endif
+ ds_resize (&output_name, dirname_len + strlen (slash) + 2);
+ strcpy (output_name.ds_string + dirname_len + 1, slash);
+
+ existing_dir = FALSE;
+ if (lstat (output_name.ds_string, &out_file_stat) == 0)
+ {
+ if (S_ISDIR (out_file_stat.st_mode)
+ && S_ISDIR (in_file_stat.st_mode))
+ {
+ /* If there is already a directory there that
+ we are trying to create, don't complain about it. */
+ existing_dir = TRUE;
+ }
+ else if (!unconditional_flag
+ && in_file_stat.st_mtime <= out_file_stat.st_mtime)
+ {
+ error (0, 0, "%s not created: newer or same age version exists",
+ output_name.ds_string);
+ continue; /* Go to the next file. */
+ }
+ else if (S_ISDIR (out_file_stat.st_mode)
+ ? rmdir (output_name.ds_string)
+ : unlink (output_name.ds_string))
+ {
+ error (0, errno, "cannot remove current %s",
+ output_name.ds_string);
+ continue; /* Go to the next file. */
+ }
+ }
+
+ /* Do the real copy or link. */
+ if (S_ISREG (in_file_stat.st_mode))
+ {
+#ifndef __MSDOS__
+ /* Can the current file be linked to a another file?
+ Set link_name to the original file name. */
+ if (link_flag)
+ /* User said to link it if possible. Try and link to
+ the original copy. If that fails we'll still try
+ and link to a copy we've already made. */
+ link_res = link_to_name (output_name.ds_string,
+ input_name.ds_string);
+ if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
+ link_res = link_to_maj_min_ino (output_name.ds_string,
+ major (in_file_stat.st_dev),
+ minor (in_file_stat.st_dev),
+ in_file_stat.st_ino);
+#endif
+
+ /* If the file was not linked, copy contents of file. */
+ if (link_res < 0)
+ {
+ in_file_des = open (input_name.ds_string,
+ O_RDONLY | O_BINARY, 0);
+ if (in_file_des < 0)
+ {
+ error (0, errno, "%s", input_name.ds_string);
+ continue;
+ }
+ out_file_des = open (output_name.ds_string,
+ O_CREAT | O_WRONLY | O_BINARY, 0600);
+ if (out_file_des < 0 && create_dir_flag)
+ {
+ create_all_directories (output_name.ds_string);
+ out_file_des = open (output_name.ds_string,
+ O_CREAT | O_WRONLY | O_BINARY, 0600);
+ }
+ if (out_file_des < 0)
+ {
+ error (0, errno, "%s", output_name.ds_string);
+ close (in_file_des);
+ continue;
+ }
+
+ copy_files_disk_to_disk (in_file_des, out_file_des, in_file_stat.st_size, input_name.ds_string);
+ disk_empty_output_buffer (out_file_des);
+ if (close (in_file_des) < 0)
+ error (0, errno, "%s", input_name.ds_string);
+ if (close (out_file_des) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+
+ /* Set the attributes of the new file. */
+ if (!no_chown_flag)
+ if ((chown (output_name.ds_string,
+ set_owner_flag ? set_owner : in_file_stat.st_uid,
+ set_group_flag ? set_group : in_file_stat.st_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", output_name.ds_string);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+ if (reset_time_flag)
+ {
+ times.actime = in_file_stat.st_atime;
+ times.modtime = in_file_stat.st_mtime;
+ if (utime (input_name.ds_string, &times) < 0)
+ error (0, errno, "%s", input_name.ds_string);
+ if (utime (output_name.ds_string, &times) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+ }
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = in_file_stat.st_mtime;
+ if (utime (output_name.ds_string, &times) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+ }
+ }
+ }
+ else if (S_ISDIR (in_file_stat.st_mode))
+ {
+#ifdef HPUX_CDF
+ cdf_flag = 0;
+#endif
+ if (!existing_dir)
+ {
+#ifdef HPUX_CDF
+ /* If the directory name ends in a + and is SUID,
+ then it is a CDF. Strip the trailing + from the name
+ before creating it. */
+ cdf_char = strlen (output_name.ds_string) - 1;
+ if ( (cdf_char > 0) &&
+ (in_file_stat.st_mode & 04000) &&
+ (output_name.ds_string [cdf_char] == '+') )
+ {
+ output_name.ds_string [cdf_char] = '\0';
+ cdf_flag = 1;
+ }
+#endif
+ res = mkdir (output_name.ds_string, in_file_stat.st_mode);
+
+ }
+ else
+ res = 0;
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (output_name.ds_string);
+ res = mkdir (output_name.ds_string, in_file_stat.st_mode);
+ }
+ if (res < 0)
+ {
+ /* In some odd cases where the output_name includes `.',
+ the directory may have actually been created by
+ create_all_directories(), so the mkdir will fail
+ because the directory exists. If that's the case,
+ don't complain about it. */
+ if ( (errno != EEXIST) ||
+ (lstat (output_name.ds_string, &out_file_stat) != 0) ||
+ !(S_ISDIR (out_file_stat.st_mode) ) )
+ {
+ error (0, errno, "%s", output_name.ds_string);
+ continue;
+ }
+ }
+ if (!no_chown_flag)
+ if ((chown (output_name.ds_string,
+ set_owner_flag ? set_owner : in_file_stat.st_uid,
+ set_group_flag ? set_group : in_file_stat.st_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", output_name.ds_string);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+#ifdef HPUX_CDF
+ if (cdf_flag)
+ /* Once we "hide" the directory with the chmod(),
+ we have to refer to it using name+ isntead of name. */
+ output_name.ds_string [cdf_char] = '+';
+#endif
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = in_file_stat.st_mtime;
+ if (utime (output_name.ds_string, &times) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+ }
+ }
+#ifndef __MSDOS__
+ else if (S_ISCHR (in_file_stat.st_mode) ||
+ S_ISBLK (in_file_stat.st_mode) ||
+#ifdef S_ISFIFO
+ S_ISFIFO (in_file_stat.st_mode) ||
+#endif
+#ifdef S_ISSOCK
+ S_ISSOCK (in_file_stat.st_mode) ||
+#endif
+ 0)
+ {
+ /* Can the current file be linked to a another file?
+ Set link_name to the original file name. */
+ if (link_flag)
+ /* User said to link it if possible. */
+ link_res = link_to_name (output_name.ds_string,
+ input_name.ds_string);
+ if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
+ link_res = link_to_maj_min_ino (output_name.ds_string,
+ major (in_file_stat.st_dev),
+ minor (in_file_stat.st_dev),
+ in_file_stat.st_ino);
+
+ if (link_res < 0)
+ {
+ res = mknod (output_name.ds_string, in_file_stat.st_mode,
+ in_file_stat.st_rdev);
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (output_name.ds_string);
+ res = mknod (output_name.ds_string, in_file_stat.st_mode,
+ in_file_stat.st_rdev);
+ }
+ if (res < 0)
+ {
+ error (0, errno, "%s", output_name.ds_string);
+ continue;
+ }
+ if (!no_chown_flag)
+ if ((chown (output_name.ds_string,
+ set_owner_flag ? set_owner : in_file_stat.st_uid,
+ set_group_flag ? set_group : in_file_stat.st_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", output_name.ds_string);
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod (output_name.ds_string, in_file_stat.st_mode) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+ if (retain_time_flag)
+ {
+ times.actime = times.modtime = in_file_stat.st_mtime;
+ if (utime (output_name.ds_string, &times) < 0)
+ error (0, errno, "%s", output_name.ds_string);
+ }
+ }
+ }
+#endif
+
+#ifdef S_ISLNK
+ else if (S_ISLNK (in_file_stat.st_mode))
+ {
+ char *link_name;
+ int link_size;
+ link_name = (char *) xmalloc ((unsigned int) in_file_stat.st_size + 1);
+
+ link_size = readlink (input_name.ds_string, link_name,
+ in_file_stat.st_size);
+ if (link_size < 0)
+ {
+ error (0, errno, "%s", input_name.ds_string);
+ free (link_name);
+ continue;
+ }
+ link_name[link_size] = '\0';
+
+ res = UMASKED_SYMLINK (link_name, output_name.ds_string,
+ in_file_stat.st_mode);
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (output_name.ds_string);
+ res = UMASKED_SYMLINK (link_name, output_name.ds_string,
+ in_file_stat.st_mode);
+ }
+ if (res < 0)
+ {
+ error (0, errno, "%s", output_name.ds_string);
+ free (link_name);
+ continue;
+ }
+
+ /* Set the attributes of the new link. */
+ if (!no_chown_flag)
+ if ((lchown (output_name.ds_string,
+ set_owner_flag ? set_owner : in_file_stat.st_uid,
+ set_group_flag ? set_group : in_file_stat.st_gid) < 0)
+ && errno != EPERM)
+ error (0, errno, "%s", output_name.ds_string);
+ free (link_name);
+ }
+#endif
+ else
+ {
+ error (0, 0, "%s: unknown file type", input_name.ds_string);
+ }
+
+ if (verbose_flag)
+ fprintf (stderr, "%s\n", output_name.ds_string);
+ if (dot_flag)
+ fputc ('.', stderr);
+ }
+
+ if (dot_flag)
+ fputc ('\n', stderr);
+ if (!quiet_flag)
+ {
+ res = (output_bytes + io_block_size - 1) / io_block_size;
+ if (res == 1)
+ fprintf (stderr, "1 block\n");
+ else
+ fprintf (stderr, "%d blocks\n", res);
+ }
+}
+
+/* Try and create a hard link from FILE_NAME to another file
+ with the given major/minor device number and inode. If no other
+ file with the same major/minor/inode numbers is known, add this file
+ to the list of known files and associated major/minor/inode numbers
+ and return -1. If another file with the same major/minor/inode
+ numbers is found, try and create another link to it using
+ link_to_name, and return 0 for success and -1 for failure. */
+
+int
+link_to_maj_min_ino (file_name, st_dev_maj, st_dev_min, st_ino)
+ char *file_name;
+ int st_dev_maj;
+ int st_dev_min;
+ int st_ino;
+{
+ int link_res;
+ char *link_name;
+ link_res = -1;
+#ifndef __MSDOS__
+ /* Is the file a link to a previously copied file? */
+ link_name = find_inode_file (st_ino,
+ st_dev_maj,
+ st_dev_min);
+ if (link_name == NULL)
+ add_inode (st_ino, file_name,
+ st_dev_maj,
+ st_dev_min);
+ else
+ link_res = link_to_name (file_name, link_name);
+#endif
+ return link_res;
+}
+
+/* Try and create a hard link from LINK_NAME to LINK_TARGET. If
+ `create_dir_flag' is set, any non-existent (parent) directories
+ needed by LINK_NAME will be created. If the link is successfully
+ created and `verbose_flag' is set, print "LINK_TARGET linked to LINK_NAME\n".
+ If the link can not be created and `link_flag' is set, print
+ "cannot link LINK_TARGET to LINK_NAME\n". Return 0 if the link
+ is created, -1 otherwise. */
+
+int
+link_to_name (link_name, link_target)
+ char *link_name;
+ char *link_target;
+{
+ int res;
+#ifdef __MSDOS__
+ res = -1;
+#else /* not __MSDOS__ */
+ res = link (link_target, link_name);
+ if (res < 0 && create_dir_flag)
+ {
+ create_all_directories (link_name);
+ res = link (link_target, link_name);
+ }
+ if (res == 0)
+ {
+ if (verbose_flag)
+ error (0, 0, "%s linked to %s",
+ link_target, link_name);
+ }
+ else if (link_flag)
+ {
+ error (0, errno, "cannot link %s to %s",
+ link_target, link_name);
+ }
+#endif /* not __MSDOS__ */
+ return res;
+}
diff --git a/contrib/cpio/cpio.1 b/contrib/cpio/cpio.1
new file mode 100644
index 0000000..0554766
--- /dev/null
+++ b/contrib/cpio/cpio.1
@@ -0,0 +1,326 @@
+.TH CPIO 1L \" -*- nroff -*-
+.SH NAME
+cpio \- copy files to and from archives
+.SH SYNOPSIS
+.B cpio
+{\-o|\-\-create} [\-0acvABLV] [\-C bytes] [\-H format] [\-M message]
+[\-O [[user@]host:]archive] [\-F [[user@]host:]archive]
+[\-\-file=[[user@]host:]archive] [\-\-format=format] [\-\-message=message]
+[\-\-null] [\-\-reset-access-time] [\-\-verbose] [\-\-dot] [\-\-append]
+[\-\-block-size=blocks] [\-\-dereference] [\-\-io-size=bytes] [\-\-quiet]
+[\-\-force\-local] [\-\-help] [\-\-version] < name-list [> archive]
+
+.B cpio
+{\-i|\-\-extract} [\-bcdfmnrtsuvBSV] [\-C bytes] [\-E file] [\-H format]
+[\-M message] [\-R [user][:.][group]] [\-I [[user@]host:]archive]
+[\-F [[user@]host:]archive] [\-\-file=[[user@]host:]archive]
+[\-\-make-directories] [\-\-nonmatching] [\-\-preserve-modification-time]
+[\-\-numeric-uid-gid] [\-\-rename] [\-\-list] [\-\-swap-bytes] [\-\-swap] [\-\-dot]
+[\-\-unconditional] [\-\-verbose] [\-\-block-size=blocks] [\-\-swap-halfwords]
+[\-\-io-size=bytes] [\-\-pattern-file=file] [\-\-format=format]
+[\-\-owner=[user][:.][group]] [\-\-no-preserve-owner] [\-\-message=message]
+[\-\-force\-local] [\-\-no\-absolute\-filenames] [\-\-sparse] [\-\-only\-verify\-crc]
+[\-\-quiet] [\-\-help] [\-\-version] [pattern...] [< archive]
+
+.B cpio
+{\-p|\-\-pass-through} [\-0adlmuvLV] [\-R [user][:.][group]]
+[\-\-null] [\-\-reset-access-time] [\-\-make-directories] [\-\-link] [\-\-quiet]
+[\-\-preserve-modification-time] [\-\-unconditional] [\-\-verbose] [\-\-dot]
+[\-\-dereference] [\-\-owner=[user][:.][group]] [\-\-no-preserve-owner]
+[\-\-sparse] [\-\-help] [\-\-version] destination-directory < name-list
+.SH DESCRIPTION
+This manual page
+documents the GNU version of
+.BR cpio .
+.B cpio
+copies files into or out of a cpio or tar archive, which is a file that
+contains other files plus information about them, such as their
+file name, owner, timestamps, and access permissions. The archive can
+be another file on the disk, a magnetic tape, or a pipe.
+.B cpio
+has three operating modes.
+.PP
+In copy-out mode,
+.B cpio
+copies files into an archive. It reads a list of filenames, one per
+line, on the standard input, and writes the archive onto the standard
+output. A typical way to generate the list of filenames is with the
+.B find
+command; you should give
+.B find
+the \-depth option to minimize problems with permissions on
+directories that are unwritable or not searchable.
+.PP
+In copy-in mode,
+.B cpio
+copies files out of an archive or lists the archive contents. It
+reads the archive from the standard input. Any non-option command
+line arguments are shell globbing patterns; only files in the archive
+whose names match one or more of those patterns are copied from the
+archive. Unlike in the shell, an initial `.' in a filename does
+match a wildcard at the start of a pattern, and a `/' in a filename
+can match wildcards. If no patterns are given, all files are
+extracted.
+.PP
+In copy-pass mode,
+.B cpio
+copies files from one directory tree to another, combining the
+copy-out and copy-in steps without actually using an archive.
+It reads the list of files to copy from the standard input; the
+directory into which it will copy them is given as a non-option
+argument.
+.PP
+.B cpio
+supports the following archive formats: binary, old ASCII, new
+ASCII, crc, HPUX binary, HPUX old ASCII, old tar, and POSIX.1 tar.
+The binary format
+is obsolete because it encodes information about the files in a way
+that is not portable between different machine architectures.
+The old ASCII format is portable between different machine architectures,
+but should not be used on file systems with more than 65536 i-nodes.
+The new ASCII format is portable between different machine architectures
+and can be used on any size file system, but is not supported by all
+versions of
+.BR cpio ;
+currently, it is only supported by GNU and Unix System V R4.
+The crc format is
+like the new ASCII format, but also contains a checksum for each file
+which
+.B cpio
+calculates when creating an archive
+and verifies when the file is extracted from the archive.
+The HPUX formats are provided for compatibility with HPUX's cpio which
+stores device files differently.
+.PP
+The tar format is provided for compatability with
+the
+.B tar
+program. It can not be used to archive files with names
+longer than 100 characters, and can not be used to archive "special"
+(block or character devices) files.
+The POSIX.1 tar format can not be used to archive files with names longer
+than 255 characters (less unless they have a "/" in just the right place).
+.PP
+By default,
+.B cpio
+creates binary format archives, for compatibility with
+older
+.B cpio
+programs.
+When extracting from archives,
+.B cpio
+automatically recognizes which kind of archive it is reading and can
+read archives created on machines with a different byte-order.
+.PP
+Some of the options to
+.B cpio
+apply only to certain operating modes; see the SYNOPSIS section for a
+list of which options are allowed in which modes.
+.SS OPTIONS
+.TP
+.I "\-0, \-\-null"
+In copy-out and copy-pass modes, read a list of filenames terminated
+by a null character instead of a newline, so that files whose names
+contain newlines can be archived. GNU
+.B find
+is one way to produce a list of null-terminated filenames.
+.TP
+.I "\-a, \-\-reset-access-time"
+Reset the access times of files after reading them, so that it does
+not look like they have just been read.
+.TP
+.I "\-A, \-\-append"
+Append to an existing archive. Only works in copy-out mode. The
+archive must be a disk file specified with the
+.I \-O
+or
+.I "\-F (\-\-file)"
+option.
+.TP
+.I "\-b, \-\-swap"
+In copy-in mode, swap both halfwords of words and bytes of halfwords
+in the data. Equivalent to
+.IR "\-sS" .
+Use this option to convert 32-bit integers between big-endian and
+little-endian machines.
+.TP
+.I "\-B"
+Set the I/O block size to 5120 bytes. Initially the block size is 512
+bytes.
+.TP
+.I "\-\-block-size=BLOCK-SIZE"
+Set the I/O block size to BLOCK-SIZE * 512 bytes.
+.TP
+.I "\-c"
+Use the old portable (ASCII) archive format.
+.TP
+.I "\-C IO-SIZE, \-\-io-size=IO-SIZE"
+Set the I/O block size to IO-SIZE bytes.
+.TP
+.I "\-d, \-\-make-directories"
+Create leading directories where needed.
+.TP
+.I "\-E FILE, \-\-pattern-file=FILE"
+In copy-in mode, read additional patterns specifying filenames to
+extract or list from FILE. The lines of FILE are treated as if they
+had been non-option arguments to
+.BR cpio .
+.TP
+.I "\-f, \-\-nonmatching"
+Only copy files that do not match any of the given patterns.
+.TP
+.I "\-F, \-\-file=archive"
+Archive filename to use instead of standard input or output. To use a
+tape drive on another machine as the archive, use a filename that
+starts with `HOSTNAME:'. The hostname can be preceded by a
+username and an `@' to access the remote tape drive as that user, if
+you have permission to do so (typically an entry in that user's
+`~/.rhosts' file).
+.TP
+.I "\-\-force-local"
+With
+.IR \-F ,
+.IR \-I ,
+or
+.IR \-O ,
+take the archive file name to be a local file even if it contains a
+colon, which would ordinarily indicate a remote host name.
+.TP
+.I "\-H FORMAT, \-\-format=FORMAT"
+Use archive format FORMAT. The valid formats are listed below;
+the same names are also recognized in all-caps. The default in
+copy-in mode is to automatically detect the archive format, and in
+copy-out mode is "bin".
+.RS
+.IP bin
+The obsolete binary format.
+.IP odc
+The old (POSIX.1) portable format.
+.IP newc
+The new (SVR4) portable format, which supports file systems having
+more than 65536 i-nodes.
+.IP crc
+The new (SVR4) portable format with a checksum added.
+.IP tar
+The old tar format.
+.IP ustar
+The POSIX.1 tar format. Also recognizes GNU
+.B tar
+archives, which are similar but not identical.
+.IP hpbin
+The obsolete binary format used by HPUX's cpio (which stores device files
+differently).
+.IP hpodc
+The portable format used by HPUX's cpio (which stores device files differently).
+.RE
+.TP
+.I "\-i, \-\-extract"
+Run in copy-in mode.
+.TP
+.I "\-I archive"
+Archive filename to use instead of standard input. To use a
+tape drive on another machine as the archive, use a filename that
+starts with `HOSTNAME:'. The hostname can be preceded by a
+username and an `@' to access the remote tape drive as that user, if
+you have permission to do so (typically an entry in that user's
+`~/.rhosts' file).
+.TP
+.I \-k
+Ignored; for compatibility with other versions of
+.BR cpio .
+.TP
+.I "\-l, \-\-link"
+Link files instead of copying them, when possible.
+.TP
+.I "\-L, \-\-dereference"
+Dereference symbolic links (copy the files that they point to instead
+of copying the links).
+.TP
+.I "\-m, \-\-preserve-modification-time"
+Retain previous file modification times when creating files.
+.TP
+.I "\-M MESSAGE, \-\-message=MESSAGE"
+Print MESSAGE when the end of a volume of the backup media (such as a
+tape or a floppy disk) is reached, to prompt the user to insert a new
+volume. If MESSAGE contains the string "%d", it is replaced by the
+current volume number (starting at 1).
+.TP
+.I "\-n, \-\-numeric-uid-gid"
+In the verbose table of contents listing, show numeric UID and GID
+instead of translating them into names.
+.TP
+.I " \-\-no-absolute-filenames"
+In copy-in mode, create all files relative to the current directory,
+even if they have an absolute file name in the archive.
+.TP
+.I " \-\-no-preserve-owner"
+In copy-in mode and copy-pass mode, do not change the ownership of the
+files; leave them owned by the user extracting them. This is the
+default for non-root users, so that users on System V don't
+inadvertantly give away files.
+.TP
+.I "\-o, \-\-create"
+Run in copy-out mode.
+.TP
+.I "\-O archive"
+Archive filename to use instead of standard output. To use a tape
+drive on another machine as the archive, use a filename that starts
+with `HOSTNAME:'. The hostname can be preceded by a username and an
+`@' to access the remote tape drive as that user, if you have
+permission to do so (typically an entry in that user's `~/.rhosts'
+file).
+.TP
+.I " \-\-only-verify-crc"
+When reading a CRC format archive in copy-in mode, only verify the
+CRC's of each file in the archive, don't actually extract the files.
+.TP
+.I "\-p, \-\-pass-through"
+Run in copy-pass mode.
+.TP
+.I "\-\-quiet"
+Do not print the number of blocks copied.
+.TP
+.I "\-r, \-\-rename"
+Interactively rename files.
+.TP
+.I "\-R [user][:.][group], \-\-owner [user][:.][group]"
+In copy-out and copy-pass modes, set the ownership of all files created
+to the specified user and/or group. Either the user or the group, or
+both, must be present. If the group is omitted but the ":" or "."
+separator is given, use the given user's login group. Only the
+super-user can change files' ownership.
+.TP
+.I "\-\-sparse"
+In copy-out and copy-pass modes, write files with large blocks of zeros
+as sparse files.
+.TP
+.I "\-s, \-\-swap-bytes"
+In copy-in mode, swap the bytes of each halfword (pair of bytes) in the
+files.
+.TP
+.I "\-S, \-\-swap-halfwords"
+In copy-in mode, swap the halfwords of each word (4 bytes) in the
+files.
+.TP
+.I "\-t, \-\-list"
+Print a table of contents of the input.
+.TP
+.I "\-u, \-\-unconditional"
+Replace all files, without asking whether to replace existing newer
+files with older files.
+.TP
+.I "\-v, \-\-verbose"
+List the files processed, or with
+.IR \-t ,
+give an `ls \-l' style table of contents listing. In a verbose table
+of contents of a ustar archive, user and group names in the archive
+that do not exist on the local system are replaced by the names that
+correspond locally to the numeric UID and GID stored in the archive.
+.TP
+.I "\-V \-\-dot"
+Print a "." for each file processed.
+.TP
+.I "\-\-version"
+Print the
+.B cpio
+program version number and exit.
diff --git a/contrib/cpio/cpio.h b/contrib/cpio/cpio.h
new file mode 100644
index 0000000..537da72
--- /dev/null
+++ b/contrib/cpio/cpio.h
@@ -0,0 +1,69 @@
+/* Extended cpio format from POSIX.1.
+ Copyright (C) 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _CPIO_H
+
+#define _CPIO_H 1
+
+/* A cpio archive consists of a sequence of files.
+ Each file has a 76 byte header,
+ a variable length, NUL terminated filename,
+ and variable length file data.
+ A header for a filename "TRAILER!!!" indicates the end of the archive. */
+
+/* All the fields in the header are ISO 646 (approximately ASCII) strings
+ of octal numbers, left padded, not NUL terminated.
+
+ Field Name Length in Bytes Notes
+ c_magic 6 must be "070707"
+ c_dev 6
+ c_ino 6
+ c_mode 6 see below for value
+ c_uid 6
+ c_gid 6
+ c_nlink 6
+ c_rdev 6 only valid for chr and blk special files
+ c_mtime 11
+ c_namesize 6 count includes terminating NUL in pathname
+ c_filesize 11 must be 0 for FIFOs and directories */
+
+/* Values for c_mode, OR'd together: */
+
+#define C_IRUSR 000400
+#define C_IWUSR 000200
+#define C_IXUSR 000100
+#define C_IRGRP 000040
+#define C_IWGRP 000020
+#define C_IXGRP 000010
+#define C_IROTH 000004
+#define C_IWOTH 000002
+#define C_IXOTH 000001
+
+#define C_ISUID 004000
+#define C_ISGID 002000
+#define C_ISVTX 001000
+
+#define C_ISBLK 060000
+#define C_ISCHR 020000
+#define C_ISDIR 040000
+#define C_ISFIFO 010000
+#define C_ISSOCK 0140000
+#define C_ISLNK 0120000
+#define C_ISCTG 0110000
+#define C_ISREG 0100000
+
+#endif /* cpio.h */
diff --git a/contrib/cpio/cpiohdr.h b/contrib/cpio/cpiohdr.h
new file mode 100644
index 0000000..9694af6
--- /dev/null
+++ b/contrib/cpio/cpiohdr.h
@@ -0,0 +1,90 @@
+/* Extended cpio header from POSIX.1.
+ Copyright (C) 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _CPIOHDR_H
+
+#define _CPIOHDR_H 1
+
+#include <cpio.h>
+
+struct old_cpio_header
+{
+ unsigned short c_magic;
+ short c_dev;
+ unsigned short c_ino;
+ unsigned short c_mode;
+ unsigned short c_uid;
+ unsigned short c_gid;
+ unsigned short c_nlink;
+ short c_rdev;
+ unsigned short c_mtimes[2];
+ unsigned short c_namesize;
+ unsigned short c_filesizes[2];
+ unsigned long c_mtime; /* Long-aligned copy of `c_mtimes'. */
+ unsigned long c_filesize; /* Long-aligned copy of `c_filesizes'. */
+ char *c_name;
+};
+
+/* "New" portable format and CRC format:
+
+ Each file has a 110 byte header,
+ a variable length, NUL terminated filename,
+ and variable length file data.
+ A header for a filename "TRAILER!!!" indicates the end of the archive. */
+
+/* All the fields in the header are ISO 646 (approximately ASCII) strings
+ of hexadecimal numbers, left padded, not NUL terminated.
+
+ Field Name Length in Bytes Notes
+ c_magic 6 "070701" for "new" portable format
+ "070702" for CRC format
+ c_ino 8
+ c_mode 8
+ c_uid 8
+ c_gid 8
+ c_nlink 8
+ c_mtime 8
+ c_filesize 8 must be 0 for FIFOs and directories
+ c_maj 8
+ c_min 8
+ c_rmaj 8 only valid for chr and blk special files
+ c_rmin 8 only valid for chr and blk special files
+ c_namesize 8 count includes terminating NUL in pathname
+ c_chksum 8 0 for "new" portable format; for CRC format
+ the sum of all the bytes in the file */
+
+struct new_cpio_header
+{
+ unsigned short c_magic;
+ unsigned long c_ino;
+ unsigned long c_mode;
+ unsigned long c_uid;
+ unsigned long c_gid;
+ unsigned long c_nlink;
+ unsigned long c_mtime;
+ unsigned long c_filesize;
+ long c_dev_maj;
+ long c_dev_min;
+ long c_rdev_maj;
+ long c_rdev_min;
+ unsigned long c_namesize;
+ unsigned long c_chksum;
+ char *c_name;
+ char *c_tar_linkname;
+};
+
+#endif /* cpiohdr.h */
diff --git a/contrib/cpio/defer.c b/contrib/cpio/defer.c
new file mode 100644
index 0000000..efe60e0
--- /dev/null
+++ b/contrib/cpio/defer.c
@@ -0,0 +1,43 @@
+/* defer.c - handle "defered" links in newc and crc archives
+ Copyright (C) 1993 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "system.h"
+#include "cpiohdr.h"
+#include "extern.h"
+#include "defer.h"
+
+struct deferment *
+create_deferment (file_hdr)
+ struct new_cpio_header *file_hdr;
+{
+ struct deferment *d;
+ d = (struct deferment *) xmalloc (sizeof (struct deferment) );
+ d->header = *file_hdr;
+ d->header.c_name = (char *) xmalloc (strlen (file_hdr->c_name) + 1);
+ strcpy (d->header.c_name, file_hdr->c_name);
+ return d;
+}
+
+void
+free_deferment (d)
+ struct deferment *d;
+{
+ free (d->header.c_name);
+ free (d);
+}
diff --git a/contrib/cpio/defer.h b/contrib/cpio/defer.h
new file mode 100644
index 0000000..89abffe
--- /dev/null
+++ b/contrib/cpio/defer.h
@@ -0,0 +1,8 @@
+struct deferment
+ {
+ struct deferment *next;
+ struct new_cpio_header header;
+ };
+
+struct deferment *create_deferment P_((struct new_cpio_header *file_hdr));
+void free_deferment P_((struct deferment *d));
diff --git a/contrib/cpio/dirname.c b/contrib/cpio/dirname.c
new file mode 100644
index 0000000..15d2596
--- /dev/null
+++ b/contrib/cpio/dirname.c
@@ -0,0 +1,70 @@
+/* dirname.c -- return all but the last element in a path
+ Copyright (C) 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+#endif
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#ifndef strrchr
+#define strrchr rindex
+#endif
+#endif
+
+/* Return the leading directories part of PATH,
+ allocated with malloc. If out of memory, return 0.
+ Assumes that trailing slashes have already been
+ removed. */
+
+char *
+dirname (path)
+ char *path;
+{
+ char *newpath;
+ char *slash;
+ int length; /* Length of result, not including NUL. */
+
+ slash = strrchr (path, '/');
+ if (slash == 0)
+ {
+ /* File is in the current directory. */
+ path = ".";
+ length = 1;
+ }
+ else
+ {
+ /* Remove any trailing slashes from the result. */
+ while (slash > path && *slash == '/')
+ --slash;
+
+ length = slash - path + 1;
+ }
+ newpath = (char *) malloc (length + 1);
+ if (newpath == 0)
+ return 0;
+ strncpy (newpath, path, length);
+ newpath[length] = 0;
+ return newpath;
+}
diff --git a/contrib/cpio/dstring.c b/contrib/cpio/dstring.c
new file mode 100644
index 0000000..26d6bbc
--- /dev/null
+++ b/contrib/cpio/dstring.c
@@ -0,0 +1,114 @@
+/* dstring.c - The dynamic string handling routines used by cpio.
+ Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include "dstring.h"
+
+#if __STDC__
+# define P_(s) s
+#else
+# define P_(s) ()
+#endif
+char *xmalloc P_((unsigned n));
+char *xrealloc P_((char *p, unsigned n));
+
+/* Initialiaze dynamic string STRING with space for SIZE characters. */
+
+void
+ds_init (string, size)
+ dynamic_string *string;
+ int size;
+{
+ string->ds_length = size;
+ string->ds_string = (char *) xmalloc (size);
+}
+
+/* Expand dynamic string STRING, if necessary, to hold SIZE characters. */
+
+void
+ds_resize (string, size)
+ dynamic_string *string;
+ int size;
+{
+ if (size > string->ds_length)
+ {
+ string->ds_length = size;
+ string->ds_string = (char *) xrealloc ((char *) string->ds_string, size);
+ }
+}
+
+/* Dynamic string S gets a string terminated by the EOS character
+ (which is removed) from file F. S will increase
+ in size during the function if the string from F is longer than
+ the current size of S.
+ Return NULL if end of file is detected. Otherwise,
+ Return a pointer to the null-terminated string in S. */
+
+char *
+ds_fgetstr (f, s, eos)
+ FILE *f;
+ dynamic_string *s;
+ char eos;
+{
+ int insize; /* Amount needed for line. */
+ int strsize; /* Amount allocated for S. */
+ int next_ch;
+
+ /* Initialize. */
+ insize = 0;
+ strsize = s->ds_length;
+
+ /* Read the input string. */
+ next_ch = getc (f);
+ while (next_ch != eos && next_ch != EOF)
+ {
+ if (insize >= strsize - 1)
+ {
+ ds_resize (s, strsize * 2 + 2);
+ strsize = s->ds_length;
+ }
+ s->ds_string[insize++] = next_ch;
+ next_ch = getc (f);
+ }
+ s->ds_string[insize++] = '\0';
+
+ if (insize == 1 && next_ch == EOF)
+ return NULL;
+ else
+ return s->ds_string;
+}
+
+char *
+ds_fgets (f, s)
+ FILE *f;
+ dynamic_string *s;
+{
+ return ds_fgetstr (f, s, '\n');
+}
+
+char *
+ds_fgetname (f, s)
+ FILE *f;
+ dynamic_string *s;
+{
+ return ds_fgetstr (f, s, '\0');
+}
diff --git a/contrib/cpio/dstring.h b/contrib/cpio/dstring.h
new file mode 100644
index 0000000..369da0b
--- /dev/null
+++ b/contrib/cpio/dstring.h
@@ -0,0 +1,49 @@
+/* dstring.h - Dynamic string handling include file. Requires strings.h.
+ Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* A dynamic string consists of record that records the size of an
+ allocated string and the pointer to that string. The actual string
+ is a normal zero byte terminated string that can be used with the
+ usual string functions. The major difference is that the
+ dynamic_string routines know how to get more space if it is needed
+ by allocating new space and copying the current string. */
+
+typedef struct
+{
+ int ds_length; /* Actual amount of storage allocated. */
+ char *ds_string; /* String. */
+} dynamic_string;
+
+
+/* Macros that look similar to the original string functions.
+ WARNING: These macros work only on pointers to dynamic string records.
+ If used with a real record, an "&" must be used to get the pointer. */
+#define ds_strlen(s) strlen ((s)->ds_string)
+#define ds_strcmp(s1, s2) strcmp ((s1)->ds_string, (s2)->ds_string)
+#define ds_strncmp(s1, s2, n) strncmp ((s1)->ds_string, (s2)->ds_string, n)
+#define ds_index(s, c) index ((s)->ds_string, c)
+#define ds_rindex(s, c) rindex ((s)->ds_string, c)
+
+void ds_init ();
+void ds_resize ();
+char *ds_fgetname ();
+char *ds_fgets ();
+char *ds_fgetstr ();
diff --git a/contrib/cpio/error.c b/contrib/cpio/error.c
new file mode 100644
index 0000000..a36198b
--- /dev/null
+++ b/contrib/cpio/error.c
@@ -0,0 +1,130 @@
+/* error.c -- error handler for noninteractive utilities
+ Copyright (C) 1990, 91, 92, 93, 94, 95 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#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
+
+/* This variable is incremented each time `error' is called. */
+unsigned int error_message_count;
+
+/* 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) () = NULL;
+
+#ifdef _LIBC
+#define program_name program_invocation_name
+#endif
+
+/* The calling program should define program_name and set it to the
+ name of the executing program. */
+extern char *program_name;
+
+#if HAVE_STRERROR || _LIBC
+# 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
+
+/* 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
+
+ if (error_print_progname)
+ (*error_print_progname) ();
+ else
+ {
+ fflush (stdout);
+ fprintf (stderr, "%s: ", program_name);
+ }
+
+#ifdef VA_START
+ VA_START (args, message);
+# if HAVE_VPRINTF || _LIBC
+ vfprintf (stderr, message, args);
+# else
+ _doprnt (message, args, stderr);
+# endif
+ va_end (args);
+#else
+ fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+
+ ++error_message_count;
+
+ if (errnum)
+ fprintf (stderr, ": %s", strerror (errnum));
+ putc ('\n', stderr);
+ fflush (stderr);
+ if (status)
+ exit (status);
+}
diff --git a/contrib/cpio/extern.h b/contrib/cpio/extern.h
new file mode 100644
index 0000000..3ff70cc
--- /dev/null
+++ b/contrib/cpio/extern.h
@@ -0,0 +1,194 @@
+/* extern.h - External declarations for cpio. Requires system.h.
+ Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+enum archive_format
+{
+ arf_unknown, arf_binary, arf_oldascii, arf_newascii, arf_crcascii,
+ arf_tar, arf_ustar, arf_hpoldascii, arf_hpbinary
+};
+extern enum archive_format archive_format;
+extern int reset_time_flag;
+extern int io_block_size;
+extern int create_dir_flag;
+extern int rename_flag;
+extern char *rename_batch_file;
+extern int table_flag;
+extern int unconditional_flag;
+extern int verbose_flag;
+extern int dot_flag;
+extern int link_flag;
+extern int retain_time_flag;
+extern int crc_i_flag;
+extern int append_flag;
+extern int swap_bytes_flag;
+extern int swap_halfwords_flag;
+extern int swapping_bytes;
+extern int swapping_halfwords;
+extern int set_owner_flag;
+extern uid_t set_owner;
+extern int set_group_flag;
+extern gid_t set_group;
+extern int no_chown_flag;
+extern int sparse_flag;
+extern int quiet_flag;
+extern int only_verify_crc_flag;
+extern int no_abs_paths_flag;
+
+extern int last_header_start;
+extern int copy_matching_files;
+extern int numeric_uid;
+extern char *pattern_file_name;
+extern char *new_media_message;
+extern char *new_media_message_with_number;
+extern char *new_media_message_after_number;
+extern int archive_des;
+extern char *archive_name;
+extern unsigned long crc;
+#ifdef DEBUG_CPIO
+extern int debug_flag;
+#endif
+
+extern char *input_buffer, *output_buffer;
+extern char *in_buff, *out_buff;
+extern long input_buffer_size;
+extern long input_size, output_size;
+#ifdef __GNUC__
+extern long long input_bytes, output_bytes;
+#else
+extern long input_bytes, output_bytes;
+#endif
+extern char zeros_512[];
+extern char *directory_name;
+extern char **save_patterns;
+extern int num_patterns;
+extern char name_end;
+extern char input_is_special;
+extern char output_is_special;
+extern char input_is_seekable;
+extern char output_is_seekable;
+extern int f_force_local;
+extern char *program_name;
+extern int (*xstat) ();
+extern void (*copy_function) ();
+
+#if __STDC__ || defined(__MSDOS__)
+# define P_(s) s
+#else
+# define P_(s) ()
+#endif
+
+/* copyin.c */
+void read_in_header P_((struct new_cpio_header *file_hdr, int in_des));
+void read_in_old_ascii P_((struct new_cpio_header *file_hdr, int in_des));
+void read_in_new_ascii P_((struct new_cpio_header *file_hdr, int in_des));
+void read_in_binary P_((struct new_cpio_header *file_hdr, int in_des));
+void swab_array P_((char *arg, int count));
+void process_copy_in P_((void));
+void long_format P_((struct new_cpio_header *file_hdr, char *link_name));
+void print_name_with_quoting P_((char *p));
+
+/* copyout.c */
+void write_out_header P_((struct new_cpio_header *file_hdr, int out_des));
+void process_copy_out P_((void));
+
+/* copypass.c */
+void process_copy_pass P_((void));
+int link_to_maj_min_ino P_((char *file_name, int st_dev_maj,
+ int st_dev_min, int st_ino));
+int link_to_name P_((char *link_name, char *link_target));
+
+/* dirname.c */
+char *dirname P_((char *path));
+
+/* error.c */
+void error P_((int status, int errnum, char *message, ...));
+
+/* filemode.c */
+void mode_string P_((unsigned int mode, char *str));
+
+/* idcache.c */
+#ifndef __MSDOS__
+char *getgroup ();
+char *getuser ();
+uid_t *getuidbyname ();
+gid_t *getgidbyname ();
+#endif
+
+/* main.c */
+void process_args P_((int argc, char *argv[]));
+void initialize_buffers P_((void));
+
+/* makepath.c */
+int make_path P_((char *argpath, int mode, int parent_mode,
+ uid_t owner, gid_t group, char *verbose_fmt_string));
+
+/* stripslash.c */
+void strip_trailing_slashes P_((char *path));
+
+/* tar.c */
+void write_out_tar_header P_((struct new_cpio_header *file_hdr, int out_des));
+int null_block P_((long *block, int size));
+void read_in_tar_header P_((struct new_cpio_header *file_hdr, int in_des));
+int otoa P_((char *s, unsigned long *n));
+int is_tar_header P_((char *buf));
+int is_tar_filename_too_long P_((char *name));
+
+/* userspec.c */
+#ifndef __MSDOS__
+char *parse_user_spec P_((char *name, uid_t *uid, gid_t *gid,
+ char **username, char **groupname));
+#endif
+
+/* util.c */
+void tape_empty_output_buffer P_((int out_des));
+void disk_empty_output_buffer P_((int out_des));
+void swahw_array P_((char *ptr, int count));
+void tape_buffered_write P_((char *in_buf, int out_des, long num_bytes));
+void tape_buffered_read P_((char *in_buf, int in_des, long num_bytes));
+int tape_buffered_peek P_((char *peek_buf, int in_des, int num_bytes));
+void tape_toss_input P_((int in_des, long num_bytes));
+void copy_files_tape_to_disk P_((int in_des, int out_des, long num_bytes));
+void copy_files_disk_to_tape P_((int in_des, int out_des, long num_bytes, char *filename));
+void copy_files_disk_to_disk P_((int in_des, int out_des, long num_bytes, char *filename));
+void create_all_directories P_((char *name));
+void prepare_append P_((int out_file_des));
+char *find_inode_file P_((unsigned long node_num,
+ unsigned long major_num, unsigned long minor_num));
+void add_inode P_((unsigned long node_num, char *file_name,
+ unsigned long major_num, unsigned long minor_num));
+int open_archive P_((char *file));
+void tape_offline P_((int tape_des));
+void get_next_reel P_((int tape_des));
+void set_new_media_message P_((char *message));
+#if defined(__MSDOS__) && !defined(__GNUC__)
+int chown P_((char *path, int owner, int group));
+#endif
+#ifdef __TURBOC__
+int utime P_((char *filename, struct utimbuf *utb));
+#endif
+#ifdef HPUX_CDF
+char *add_cdf_double_slashes P_((char *filename));
+#endif
+
+/* xmalloc.c */
+char *xmalloc P_((unsigned n));
+char *xrealloc P_((char *p, unsigned n));
+
+/* xstrdup.c */
+char *xstrdup P_((char *string));
+
+#define DISK_IO_BLOCK_SIZE (512)
diff --git a/contrib/cpio/filemode.c b/contrib/cpio/filemode.c
new file mode 100644
index 0000000..20c65c4
--- /dev/null
+++ b/contrib/cpio/filemode.c
@@ -0,0 +1,255 @@
+/* filemode.c -- make a string describing file modes
+ Copyright (C) 1985, 1990, 1993 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if !S_IRUSR
+# if S_IREAD
+# define S_IRUSR S_IREAD
+# else
+# define S_IRUSR 00400
+# endif
+#endif
+
+#if !S_IWUSR
+# if S_IWRITE
+# define S_IWUSR S_IWRITE
+# else
+# define S_IWUSR 00200
+# endif
+#endif
+
+#if !S_IXUSR
+# if S_IEXEC
+# define S_IXUSR S_IEXEC
+# else
+# define S_IXUSR 00100
+# endif
+#endif
+
+#ifdef STAT_MACROS_BROKEN
+#undef S_ISBLK
+#undef S_ISCHR
+#undef S_ISDIR
+#undef S_ISFIFO
+#undef S_ISLNK
+#undef S_ISMPB
+#undef S_ISMPC
+#undef S_ISNWK
+#undef S_ISREG
+#undef S_ISSOCK
+#endif /* STAT_MACROS_BROKEN. */
+
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
+#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
+#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+#endif
+
+void mode_string ();
+static char ftypelet ();
+static void rwx ();
+static void setst ();
+
+/* filemodestring - fill in string STR with an ls-style ASCII
+ representation of the st_mode field of file stats block STATP.
+ 10 characters are stored in STR; no terminating null is added.
+ The characters stored in STR are:
+
+ 0 File type. 'd' for directory, 'c' for character
+ special, 'b' for block special, 'm' for multiplex,
+ 'l' for symbolic link, 's' for socket, 'p' for fifo,
+ '-' for regular, '?' for any other file type
+
+ 1 'r' if the owner may read, '-' otherwise.
+
+ 2 'w' if the owner may write, '-' otherwise.
+
+ 3 'x' if the owner may execute, 's' if the file is
+ set-user-id, '-' otherwise.
+ 'S' if the file is set-user-id, but the execute
+ bit isn't set.
+
+ 4 'r' if group members may read, '-' otherwise.
+
+ 5 'w' if group members may write, '-' otherwise.
+
+ 6 'x' if group members may execute, 's' if the file is
+ set-group-id, '-' otherwise.
+ 'S' if it is set-group-id but not executable.
+
+ 7 'r' if any user may read, '-' otherwise.
+
+ 8 'w' if any user may write, '-' otherwise.
+
+ 9 'x' if any user may execute, 't' if the file is "sticky"
+ (will be retained in swap space after execution), '-'
+ otherwise.
+ 'T' if the file is sticky but not executable. */
+
+void
+filemodestring (statp, str)
+ struct stat *statp;
+ char *str;
+{
+ mode_string (statp->st_mode, str);
+}
+
+/* Like filemodestring, but only the relevant part of the `struct stat'
+ is given as an argument. */
+
+void
+mode_string (mode, str)
+ unsigned short mode;
+ char *str;
+{
+ str[0] = ftypelet ((long) mode);
+ rwx ((mode & 0700) << 0, &str[1]);
+ rwx ((mode & 0070) << 3, &str[4]);
+ rwx ((mode & 0007) << 6, &str[7]);
+ setst (mode, str);
+}
+
+/* Return a character indicating the type of file described by
+ file mode BITS:
+ 'd' for directories
+ 'b' for block special files
+ 'c' for character special files
+ 'm' for multiplexor files
+ 'l' for symbolic links
+ 's' for sockets
+ 'p' for fifos
+ '-' for regular files
+ '?' for any other file type. */
+
+static char
+ftypelet (bits)
+ long bits;
+{
+#ifdef S_ISBLK
+ if (S_ISBLK (bits))
+ return 'b';
+#endif
+ if (S_ISCHR (bits))
+ return 'c';
+ if (S_ISDIR (bits))
+ return 'd';
+ if (S_ISREG (bits))
+ return '-';
+#ifdef S_ISFIFO
+ if (S_ISFIFO (bits))
+ return 'p';
+#endif
+#ifdef S_ISLNK
+ if (S_ISLNK (bits))
+ return 'l';
+#endif
+#ifdef S_ISSOCK
+ if (S_ISSOCK (bits))
+ return 's';
+#endif
+#ifdef S_ISMPC
+ if (S_ISMPC (bits))
+ return 'm';
+#endif
+#ifdef S_ISNWK
+ if (S_ISNWK (bits))
+ return 'n';
+#endif
+ return '?';
+}
+
+/* Look at read, write, and execute bits in BITS and set
+ flags in CHARS accordingly. */
+
+static void
+rwx (bits, chars)
+ unsigned short bits;
+ char *chars;
+{
+ chars[0] = (bits & S_IRUSR) ? 'r' : '-';
+ chars[1] = (bits & S_IWUSR) ? 'w' : '-';
+ chars[2] = (bits & S_IXUSR) ? 'x' : '-';
+}
+
+/* Set the 's' and 't' flags in file attributes string CHARS,
+ according to the file mode BITS. */
+
+static void
+setst (bits, chars)
+ unsigned short bits;
+ char *chars;
+{
+#ifdef S_ISUID
+ if (bits & S_ISUID)
+ {
+ if (chars[3] != 'x')
+ /* Set-uid, but not executable by owner. */
+ chars[3] = 'S';
+ else
+ chars[3] = 's';
+ }
+#endif
+#ifdef S_ISGID
+ if (bits & S_ISGID)
+ {
+ if (chars[6] != 'x')
+ /* Set-gid, but not executable by group. */
+ chars[6] = 'S';
+ else
+ chars[6] = 's';
+ }
+#endif
+#ifdef S_ISVTX
+ if (bits & S_ISVTX)
+ {
+ if (chars[9] != 'x')
+ /* Sticky, but not executable by others. */
+ chars[9] = 'T';
+ else
+ chars[9] = 't';
+ }
+#endif
+}
diff --git a/contrib/cpio/filetypes.h b/contrib/cpio/filetypes.h
new file mode 100644
index 0000000..46a79a9
--- /dev/null
+++ b/contrib/cpio/filetypes.h
@@ -0,0 +1,84 @@
+/* filetypes.h - deal with POSIX annoyances
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Include sys/types.h and sys/stat.h before this file. */
+
+#ifndef S_ISREG /* Doesn't have POSIX.1 stat stuff. */
+#define mode_t unsigned short
+#endif
+
+/* Define the POSIX macros for systems that lack them. */
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX network special */
+#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+#endif
+
+/* Define the file type bits used in cpio archives.
+ They have the same values as the S_IF bits in traditional Unix. */
+
+#define CP_IFMT 0170000 /* Mask for all file type bits. */
+
+#if defined(S_ISBLK)
+#define CP_IFBLK 0060000
+#endif
+#if defined(S_ISCHR)
+#define CP_IFCHR 0020000
+#endif
+#if defined(S_ISDIR)
+#define CP_IFDIR 0040000
+#endif
+#if defined(S_ISREG)
+#define CP_IFREG 0100000
+#endif
+#if defined(S_ISFIFO)
+#define CP_IFIFO 0010000
+#endif
+#if defined(S_ISLNK)
+#define CP_IFLNK 0120000
+#endif
+#if defined(S_ISSOCK)
+#define CP_IFSOCK 0140000
+#endif
+#if defined(S_ISNWK)
+#define CP_IFNWK 0110000
+#endif
+
+#ifndef S_ISLNK
+#define lstat stat
+#endif
+int lstat ();
+int stat ();
diff --git a/contrib/cpio/getopt.c b/contrib/cpio/getopt.c
new file mode 100644
index 0000000..beb7450
--- /dev/null
+++ b/contrib/cpio/getopt.c
@@ -0,0 +1,765 @@
+/* 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 roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95
+ 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, 675 Mass Ave, Cambridge, MA 02139, 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. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* 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>
+#endif /* GNU C library. */
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+ When compiling libc, the _ macro is predefined. */
+#ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# define _(msgid) gettext (msgid)
+#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 = NULL;
+
+/* 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 EOF, 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. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* 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 EOF 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
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv ();
+
+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__
+/* 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;
+
+/* 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. */
+
+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. */
+
+ 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;
+ }
+ /* 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;
+ }
+ /* 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. */
+
+static const char *
+_getopt_initialize (optstring)
+ 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 = 1;
+
+ 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;
+
+ 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 `EOF'.
+ 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;
+{
+ optarg = NULL;
+
+ if (optind == 0)
+ {
+ optstring = _getopt_initialize (optstring);
+ optind = 1; /* Don't scan ARGV[0], the program name. */
+ }
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ 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
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ 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 EOF;
+ }
+
+ /* 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 ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ 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;
+ 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 (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 (opterr)
+ fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ 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 (opterr)
+ 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);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ 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;
+ }
+
+ /* 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 (opterr)
+ {
+ 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++;
+ 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 (opterr)
+ {
+ 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 '?';
+ }
+ 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 (opterr)
+ {
+ /* 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 /* _LIBC or not __GNU_LIBRARY__. */
+
+#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 == EOF)
+ 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/cpio/getopt.h b/contrib/cpio/getopt.h
new file mode 100644
index 0000000..4ac33b7
--- /dev/null
+++ b/contrib/cpio/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 90, 91, 92, 93, 94 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#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 EOF, 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;
+
+/* 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__
+ 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
+
+#if defined (__STDC__) && __STDC__
+#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__ */
+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);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/contrib/cpio/getopt1.c b/contrib/cpio/getopt1.c
new file mode 100644
index 0000000..4580211
--- /dev/null
+++ b/contrib/cpio/getopt1.c
@@ -0,0 +1,180 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994
+ 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, 675 Mass Ave, Cambridge, MA 02139, 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. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#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 /* _LIBC or not __GNU_LIBRARY__. */
+
+#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 == EOF)
+ 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/cpio/global.c b/contrib/cpio/global.c
new file mode 100644
index 0000000..7fb66b2
--- /dev/null
+++ b/contrib/cpio/global.c
@@ -0,0 +1,197 @@
+/* global.c - global variables and initial values for cpio.
+ Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <sys/types.h>
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "system.h"
+#include "extern.h"
+
+/* If TRUE, reset access times after reading files (-a). */
+int reset_time_flag = FALSE;
+
+/* Block size value, initially 512. -B sets to 5120. */
+int io_block_size = 512;
+
+/* The header format to recognize and produce. */
+enum archive_format archive_format = arf_unknown;
+
+/* If TRUE, create directories as needed. (-d with -i or -p) */
+int create_dir_flag = FALSE;
+
+/* If TRUE, interactively rename files. (-r) */
+int rename_flag = FALSE;
+
+/* If non-NULL, the name of a file that will be read to
+ rename all of the files in the archive. --rename-batch-file. */
+char *rename_batch_file = NULL;
+
+/* If TRUE, print a table of contents of input. (-t) */
+int table_flag = FALSE;
+
+/* If TRUE, copy unconditionally (older replaces newer). (-u) */
+int unconditional_flag = FALSE;
+
+/* If TRUE, list the files processed, or ls -l style output with -t. (-v) */
+int verbose_flag = FALSE;
+
+/* If TRUE, print a . for each file processed. (-V) */
+int dot_flag = FALSE;
+
+/* If TRUE, link files whenever possible. Used with -p option. (-l) */
+int link_flag = FALSE;
+
+/* If TRUE, retain previous file modification time. (-m) */
+int retain_time_flag = FALSE;
+
+/* Set TRUE if crc_flag is TRUE and we are doing a cpio -i. Used
+ by copy_files so it knows whether to compute the crc. */
+int crc_i_flag = FALSE;
+
+/* If TRUE, append to end of archive. (-A) */
+int append_flag = FALSE;
+
+/* If TRUE, swap bytes of each file during cpio -i. */
+int swap_bytes_flag = FALSE;
+
+/* If TRUE, swap halfwords of each file during cpio -i. */
+int swap_halfwords_flag = FALSE;
+
+/* If TRUE, we are swapping halfwords on the current file. */
+int swapping_halfwords = FALSE;
+
+/* If TRUE, we are swapping bytes on the current file. */
+int swapping_bytes = FALSE;
+
+/* If TRUE, set ownership of all files to UID `set_owner'. */
+int set_owner_flag = FALSE;
+uid_t set_owner;
+
+/* If TRUE, set group ownership of all files to GID `set_group'. */
+int set_group_flag = FALSE;
+gid_t set_group;
+
+/* If TRUE, do not chown the files. */
+int no_chown_flag = FALSE;
+
+/* If TRUE, try to write sparse ("holey") files. */
+int sparse_flag = FALSE;
+
+/* If TRUE, don't report number of blocks copied. */
+int quiet_flag = FALSE;
+
+/* If TRUE, only read the archive and verify the files' CRC's, don't
+ actually extract the files. */
+int only_verify_crc_flag = FALSE;
+
+/* If TRUE, don't use any absolute paths, prefix them by `./'. */
+int no_abs_paths_flag = FALSE;
+
+#ifdef DEBUG_CPIO
+/* If TRUE, print debugging information. */
+int debug_flag = FALSE;
+#endif
+
+/* File position of last header read. Only used during -A to determine
+ where the old TRAILER!!! record started. */
+int last_header_start = 0;
+
+/* With -i; if TRUE, copy only files that match any of the given patterns;
+ if FALSE, copy only files that do not match any of the patterns. (-f) */
+int copy_matching_files = TRUE;
+
+/* With -itv; if TRUE, list numeric uid and gid instead of translating them
+ into names. */
+int numeric_uid = FALSE;
+
+/* Name of file containing additional patterns (-E). */
+char *pattern_file_name = NULL;
+
+/* Message to print when end of medium is reached (-M). */
+char *new_media_message = NULL;
+
+/* With -M with %d, message to print when end of medium is reached. */
+char *new_media_message_with_number = NULL;
+char *new_media_message_after_number = NULL;
+
+/* File descriptor containing the archive. */
+int archive_des;
+
+/* Name of file containing the archive, if known; NULL if stdin/out. */
+char *archive_name = NULL;
+
+/* CRC checksum. */
+unsigned long crc;
+
+/* Input and output buffers. */
+char *input_buffer, *output_buffer;
+
+/* The size of the input buffer. */
+long input_buffer_size;
+
+/* Current locations in `input_buffer' and `output_buffer'. */
+char *in_buff, *out_buff;
+
+/* Current number of bytes stored at `input_buff' and `output_buff'. */
+long input_size, output_size;
+
+/* Total number of bytes read and written for all files.
+ Now that many tape drives hold more than 4Gb we need more than 32
+ bits to hold input_bytes and output_bytes. But it's not worth
+ the trouble of adding special multi-precision arithmetic if the
+ compiler doesn't support 64 bit ints since input_bytes and
+ output_bytes are only used to print the number of blocks copied. */
+#ifdef __GNUC__
+long long input_bytes, output_bytes;
+#else
+long input_bytes, output_bytes;
+#endif
+
+/* 512 bytes of 0; used for various padding operations. */
+char zeros_512[512];
+
+/* Saving of argument values for later reference. */
+char *directory_name = NULL;
+char **save_patterns;
+int num_patterns;
+
+/* Character that terminates file names read from stdin. */
+char name_end = '\n';
+
+/* TRUE if input (cpio -i) or output (cpio -o) is a device node. */
+char input_is_special = FALSE;
+char output_is_special = FALSE;
+
+/* TRUE if lseek works on the input. */
+char input_is_seekable = FALSE;
+
+/* TRUE if lseek works on the output. */
+char output_is_seekable = FALSE;
+
+/* If nonzero, don't consider file names that contain a `:' to be
+ on remote hosts; all files are local. */
+int f_force_local = 0;
+
+/* The name this program was run with. */
+char *program_name;
+
+/* A pointer to either lstat or stat, depending on whether
+ dereferencing of symlinks is done for input files. */
+int (*xstat) ();
+
+/* Which copy operation to perform. (-i, -o, -p) */
+void (*copy_function) () = 0;
diff --git a/contrib/cpio/idcache.c b/contrib/cpio/idcache.c
new file mode 100644
index 0000000..34dcc07
--- /dev/null
+++ b/contrib/cpio/idcache.c
@@ -0,0 +1,210 @@
+/* idcache.c -- map user and group IDs, cached for speed
+ Copyright (C) 1985, 1988, 1989, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef _POSIX_VERSION
+struct passwd *getpwuid ();
+struct passwd *getpwnam ();
+struct group *getgrgid ();
+struct group *getgrnam ();
+#endif
+
+char *xmalloc ();
+char *xstrdup ();
+
+struct userid
+{
+ union
+ {
+ uid_t u;
+ gid_t g;
+ } id;
+ char *name;
+ struct userid *next;
+};
+
+static struct userid *user_alist;
+
+/* The members of this list have names not in the local passwd file. */
+static struct userid *nouser_alist;
+
+/* Translate UID to a login name or a stringified number,
+ with cache. */
+
+char *
+getuser (uid)
+ uid_t uid;
+{
+ register struct userid *tail;
+ struct passwd *pwent;
+ char usernum_string[20];
+
+ for (tail = user_alist; tail; tail = tail->next)
+ if (tail->id.u == uid)
+ return tail->name;
+
+ pwent = getpwuid (uid);
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->id.u = uid;
+ if (pwent == 0)
+ {
+ sprintf (usernum_string, "%u", (unsigned) uid);
+ tail->name = xstrdup (usernum_string);
+ }
+ else
+ tail->name = xstrdup (pwent->pw_name);
+
+ /* Add to the head of the list, so most recently used is first. */
+ tail->next = user_alist;
+ user_alist = tail;
+ return tail->name;
+}
+
+/* Translate USER to a UID, with cache.
+ Return NULL if there is no such user.
+ (We also cache which user names have no passwd entry,
+ so we don't keep looking them up.) */
+
+uid_t *
+getuidbyname (user)
+ char *user;
+{
+ register struct userid *tail;
+ struct passwd *pwent;
+
+ for (tail = user_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *user && !strcmp (tail->name, user))
+ return &tail->id.u;
+
+ for (tail = nouser_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *user && !strcmp (tail->name, user))
+ return 0;
+
+ pwent = getpwnam (user);
+
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->name = xstrdup (user);
+
+ /* Add to the head of the list, so most recently used is first. */
+ if (pwent)
+ {
+ tail->id.u = pwent->pw_uid;
+ tail->next = user_alist;
+ user_alist = tail;
+ return &tail->id.u;
+ }
+
+ tail->next = nouser_alist;
+ nouser_alist = tail;
+ return 0;
+}
+
+/* Use the same struct as for userids. */
+static struct userid *group_alist;
+static struct userid *nogroup_alist;
+
+/* Translate GID to a group name or a stringified number,
+ with cache. */
+
+char *
+getgroup (gid)
+ gid_t gid;
+{
+ register struct userid *tail;
+ struct group *grent;
+ char groupnum_string[20];
+
+ for (tail = group_alist; tail; tail = tail->next)
+ if (tail->id.g == gid)
+ return tail->name;
+
+ grent = getgrgid (gid);
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->id.g = gid;
+ if (grent == 0)
+ {
+ sprintf (groupnum_string, "%u", (unsigned int) gid);
+ tail->name = xstrdup (groupnum_string);
+ }
+ else
+ tail->name = xstrdup (grent->gr_name);
+
+ /* Add to the head of the list, so most recently used is first. */
+ tail->next = group_alist;
+ group_alist = tail;
+ return tail->name;
+}
+
+/* Translate GROUP to a UID, with cache.
+ Return NULL if there is no such group.
+ (We also cache which group names have no group entry,
+ so we don't keep looking them up.) */
+
+gid_t *
+getgidbyname (group)
+ char *group;
+{
+ register struct userid *tail;
+ struct group *grent;
+
+ for (tail = group_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *group && !strcmp (tail->name, group))
+ return &tail->id.g;
+
+ for (tail = nogroup_alist; tail; tail = tail->next)
+ /* Avoid a function call for the most common case. */
+ if (*tail->name == *group && !strcmp (tail->name, group))
+ return 0;
+
+ grent = getgrnam (group);
+
+ tail = (struct userid *) xmalloc (sizeof (struct userid));
+ tail->name = xstrdup (group);
+
+ /* Add to the head of the list, so most recently used is first. */
+ if (grent)
+ {
+ tail->id.g = grent->gr_gid;
+ tail->next = group_alist;
+ group_alist = tail;
+ return &tail->id.g;
+ }
+
+ tail->next = nogroup_alist;
+ nogroup_alist = tail;
+ return 0;
+}
diff --git a/contrib/cpio/main.c b/contrib/cpio/main.c
new file mode 100644
index 0000000..76125f0
--- /dev/null
+++ b/contrib/cpio/main.c
@@ -0,0 +1,521 @@
+/* main.c - main program and argument processing for cpio.
+ Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Phil Nelson <phil@cs.wwu.edu>,
+ David MacKenzie <djm@gnu.ai.mit.edu>,
+ and John Oleynick <juo@klinzhai.rutgers.edu>. */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "system.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "rmt.h"
+
+struct option long_opts[] =
+{
+ {"null", 0, 0, '0'},
+ {"append", 0, 0, 'A'},
+ {"block-size", 1, 0, 130},
+ {"create", 0, 0, 'o'},
+ {"dereference", 0, 0, 'L'},
+ {"dot", 0, 0, 'V'},
+ {"extract", 0, 0, 'i'},
+ {"file", 1, 0, 'F'},
+ {"force-local", 0, &f_force_local, 1},
+ {"format", 1, 0, 'H'},
+ {"help", 0, 0, 132},
+ {"io-size", 1, 0, 'C'},
+ {"link", 0, &link_flag, TRUE},
+ {"list", 0, &table_flag, TRUE},
+ {"make-directories", 0, &create_dir_flag, TRUE},
+ {"message", 1, 0, 'M'},
+ {"no-absolute-filenames", 0, 0, 136},
+ {"no-preserve-owner", 0, 0, 134},
+ {"nonmatching", 0, &copy_matching_files, FALSE},
+ {"numeric-uid-gid", 0, &numeric_uid, TRUE},
+ {"only-verify-crc", 0, 0, 139},
+ {"owner", 1, 0, 'R'},
+ {"pass-through", 0, 0, 'p'},
+ {"pattern-file", 1, 0, 'E'},
+ {"preserve-modification-time", 0, &retain_time_flag, TRUE},
+ {"rename", 0, &rename_flag, TRUE},
+ {"rename-batch-file", 1, 0, 137},
+ {"quiet", 0, 0, 138},
+ {"sparse", 0, 0, 135},
+ {"swap", 0, 0, 'b'},
+ {"swap-bytes", 0, 0, 's'},
+ {"swap-halfwords", 0, 0, 'S'},
+ {"reset-access-time", 0, &reset_time_flag, TRUE},
+ {"unconditional", 0, &unconditional_flag, TRUE},
+ {"verbose", 0, &verbose_flag, TRUE},
+ {"version", 0, 0, 131},
+#ifdef DEBUG_CPIO
+ {"debug", 0, &debug_flag, TRUE},
+#endif
+ {0, 0, 0, 0}
+};
+
+/* Print usage message and exit with error. */
+
+void
+usage (fp, status)
+ FILE *fp;
+ int status;
+{
+ fprintf (fp, "\
+Usage: %s {-o|--create} [-0acvABLV] [-C bytes] [-H format] [-M message]\n\
+ [-O [[user@]host:]archive] [-F [[user@]host:]archive]\n\
+ [--file=[[user@]host:]archive] [--format=format] [--message=message]\n\
+ [--null] [--reset-access-time] [--verbose] [--dot] [--append]\n\
+ [--block-size=blocks] [--dereference] [--io-size=bytes] [--quiet]\n\
+ [--force-local] [--help] [--version] < name-list [> archive]\n", program_name);
+ fprintf (fp, "\
+ %s {-i|--extract} [-bcdfmnrtsuvBSV] [-C bytes] [-E file] [-H format]\n\
+ [-M message] [-R [user][:.][group]] [-I [[user@]host:]archive]\n\
+ [-F [[user@]host:]archive] [--file=[[user@]host:]archive]\n\
+ [--make-directories] [--nonmatching] [--preserve-modification-time]\n\
+ [--numeric-uid-gid] [--rename] [--list] [--swap-bytes] [--swap] [--dot]\n\
+ [--unconditional] [--verbose] [--block-size=blocks] [--swap-halfwords]\n\
+ [--io-size=bytes] [--pattern-file=file] [--format=format]\n\
+ [--owner=[user][:.][group]] [--no-preserve-owner] [--message=message]\n\
+ [--force-local] [--no-absolute-filenames] [--sparse] [--only-verify-crc]\n\
+ [--quiet] [--help] [--version] [pattern...] [< archive]\n",
+ program_name);
+ fprintf (fp, "\
+ %s {-p|--pass-through} [-0adlmuvLV] [-R [user][:.][group]]\n\
+ [--null] [--reset-access-time] [--make-directories] [--link] [--quiet]\n\
+ [--preserve-modification-time] [--unconditional] [--verbose] [--dot]\n\
+ [--dereference] [--owner=[user][:.][group]] [--no-preserve-owner]\n\
+ [--sparse] [--help] [--version] destination-directory < name-list\n", program_name);
+ exit (status);
+}
+
+/* Process the arguments. Set all options and set up the copy pass
+ directory or the copy in patterns. */
+
+void
+process_args (argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *version_string;
+ void (*copy_in) (); /* Work around for pcc bug. */
+ void (*copy_out) ();
+ int c;
+ char *input_archive_name = 0;
+ char *output_archive_name = 0;
+
+ if (argc < 2)
+ usage (stderr, 2);
+
+ xstat = lstat;
+
+ while ((c = getopt_long (argc, argv,
+ "0aAbBcC:dfE:F:H:iI:lLmM:noO:prR:sStuvVz",
+ long_opts, (int *) 0)) != -1)
+ {
+ switch (c)
+ {
+ case 0: /* A long option that just sets a flag. */
+ break;
+
+ case '0': /* Read null-terminated filenames. */
+ name_end = '\0';
+ break;
+
+ case 'a': /* Reset access times. */
+ reset_time_flag = TRUE;
+ break;
+
+ case 'A': /* Append to the archive. */
+ append_flag = TRUE;
+ break;
+
+ case 'b': /* Swap bytes and halfwords. */
+ swap_bytes_flag = TRUE;
+ swap_halfwords_flag = TRUE;
+ break;
+
+ case 'B': /* Set block size to 5120. */
+ io_block_size = 5120;
+ break;
+
+ case 130: /* --block-size */
+ io_block_size = atoi (optarg);
+ if (io_block_size < 1)
+ error (2, 0, "invalid block size");
+ io_block_size *= 512;
+ break;
+
+ case 'c': /* Use the old portable ASCII format. */
+ if (archive_format != arf_unknown)
+ usage (stderr, 2);
+#ifdef SVR4_COMPAT
+ archive_format = arf_newascii; /* -H newc. */
+#else
+ archive_format = arf_oldascii; /* -H odc. */
+#endif
+ break;
+
+ case 'C': /* Block size. */
+ io_block_size = atoi (optarg);
+ if (io_block_size < 1)
+ error (2, 0, "invalid block size");
+ break;
+
+ case 'd': /* Create directories where needed. */
+ create_dir_flag = TRUE;
+ break;
+
+ case 'f': /* Only copy files not matching patterns. */
+ copy_matching_files = FALSE;
+ break;
+
+ case 'E': /* Pattern file name. */
+ pattern_file_name = optarg;
+ break;
+
+ case 'F': /* Archive file name. */
+ archive_name = optarg;
+ break;
+
+ case 'H': /* Header format name. */
+ if (archive_format != arf_unknown)
+ usage (stderr, 2);
+ if (!strcmp (optarg, "crc") || !strcmp (optarg, "CRC"))
+ archive_format = arf_crcascii;
+ else if (!strcmp (optarg, "newc") || !strcmp (optarg, "NEWC"))
+ archive_format = arf_newascii;
+ else if (!strcmp (optarg, "odc") || !strcmp (optarg, "ODC"))
+ archive_format = arf_oldascii;
+ else if (!strcmp (optarg, "bin") || !strcmp (optarg, "BIN"))
+ archive_format = arf_binary;
+ else if (!strcmp (optarg, "ustar") || !strcmp (optarg, "USTAR"))
+ archive_format = arf_ustar;
+ else if (!strcmp (optarg, "tar") || !strcmp (optarg, "TAR"))
+ archive_format = arf_tar;
+ else if (!strcmp (optarg, "hpodc") || !strcmp (optarg, "HPODC"))
+ archive_format = arf_hpoldascii;
+ else if (!strcmp (optarg, "hpbin") || !strcmp (optarg, "HPBIN"))
+ archive_format = arf_hpbinary;
+ else
+ error (2, 0, "\
+invalid archive format `%s'; valid formats are:\n\
+crc newc odc bin ustar tar (all-caps also recognized)", optarg);
+ break;
+
+ case 'i': /* Copy-in mode. */
+ if (copy_function != 0)
+ usage (stderr, 2);
+ copy_function = process_copy_in;
+ break;
+
+ case 'I': /* Input archive file name. */
+ input_archive_name = optarg;
+ break;
+
+ case 'k': /* Handle corrupted archives. We always handle
+ corrupted archives, but recognize this
+ option for compatability. */
+ break;
+
+ case 'l': /* Link files when possible. */
+ link_flag = TRUE;
+ break;
+
+ case 'L': /* Dereference symbolic links. */
+ xstat = stat;
+ break;
+
+ case 'm': /* Retain previous file modify times. */
+ retain_time_flag = TRUE;
+ break;
+
+ case 'M': /* New media message. */
+ set_new_media_message (optarg);
+ break;
+
+ case 'n': /* Long list owner and group as numbers. */
+ numeric_uid = TRUE;
+ break;
+
+ case 136: /* --no-absolute-filenames */
+ no_abs_paths_flag = TRUE;
+ break;
+
+ case 134: /* --no-preserve-owner */
+ if (set_owner_flag || set_group_flag)
+ usage (stderr, 2);
+ no_chown_flag = TRUE;
+ break;
+
+ case 'o': /* Copy-out mode. */
+ if (copy_function != 0)
+ usage (stderr, 2);
+ copy_function = process_copy_out;
+ break;
+
+ case 'O': /* Output archive file name. */
+ output_archive_name = optarg;
+ break;
+
+ case 139:
+ only_verify_crc_flag = TRUE;
+ break;
+
+ case 'p': /* Copy-pass mode. */
+ if (copy_function != 0)
+ usage (stderr, 2);
+ copy_function = process_copy_pass;
+ break;
+
+ case 'r': /* Interactively rename. */
+ rename_flag = TRUE;
+ break;
+
+ case 137:
+ rename_batch_file = optarg;
+ break;
+
+ case 138:
+ quiet_flag = TRUE;
+ break;
+
+ case 'R': /* Set the owner. */
+ if (no_chown_flag)
+ usage (stderr, 2);
+#ifndef __MSDOS__
+ {
+ char *e, *u, *g;
+
+ e = parse_user_spec (optarg, &set_owner, &set_group, &u, &g);
+ if (e)
+ error (2, 0, "%s: %s", optarg, e);
+ if (u)
+ {
+ free (u);
+ set_owner_flag = TRUE;
+ }
+ if (g)
+ {
+ free (g);
+ set_group_flag = TRUE;
+ }
+ }
+#endif
+ break;
+
+ case 's': /* Swap bytes. */
+ swap_bytes_flag = TRUE;
+ break;
+
+ case 'S': /* Swap halfwords. */
+ swap_halfwords_flag = TRUE;
+ break;
+
+ case 't': /* Only print a list. */
+ table_flag = TRUE;
+ break;
+
+ case 'u': /* Replace all! Unconditionally! */
+ unconditional_flag = TRUE;
+ break;
+
+ case 'v': /* Verbose! */
+ verbose_flag = TRUE;
+ break;
+
+ case 'V': /* Print `.' for each file. */
+ dot_flag = TRUE;
+ break;
+
+ case 131:
+ printf ("GNU cpio %s", version_string);
+ exit (0);
+ break;
+
+ case 135:
+ sparse_flag = TRUE;
+ break;
+
+ case 132: /* --help */
+ usage (stdout, 0);
+ break;
+
+ default:
+ usage (stderr, 2);
+ }
+ }
+
+ /* Do error checking and look at other args. */
+
+ if (copy_function == 0)
+ {
+ if (table_flag)
+ copy_function = process_copy_in;
+ else
+ usage (stderr, 2);
+ }
+
+ if ((!table_flag || !verbose_flag) && numeric_uid)
+ usage (stderr, 2);
+
+ /* Work around for pcc bug. */
+ copy_in = process_copy_in;
+ copy_out = process_copy_out;
+
+ if (copy_function == copy_in)
+ {
+ archive_des = 0;
+ if (link_flag || reset_time_flag || xstat != lstat || append_flag
+ || sparse_flag
+ || output_archive_name
+ || (archive_name && input_archive_name))
+ usage (stderr, 2);
+ if (archive_format == arf_crcascii)
+ crc_i_flag = TRUE;
+ num_patterns = argc - optind;
+ save_patterns = &argv[optind];
+ if (input_archive_name)
+ archive_name = input_archive_name;
+ }
+ else if (copy_function == copy_out)
+ {
+ archive_des = 1;
+ if (argc != optind || create_dir_flag || rename_flag
+ || table_flag || unconditional_flag || link_flag
+ || retain_time_flag || no_chown_flag || set_owner_flag
+ || set_group_flag || swap_bytes_flag || swap_halfwords_flag
+ || (append_flag && !(archive_name || output_archive_name))
+ || rename_batch_file || no_abs_paths_flag
+ || input_archive_name || (archive_name && output_archive_name))
+ usage (stderr, 2);
+ if (archive_format == arf_unknown)
+ archive_format = arf_binary;
+ if (output_archive_name)
+ archive_name = output_archive_name;
+ }
+ else
+ {
+ /* Copy pass. */
+ archive_des = -1;
+ if (argc - 1 != optind || archive_format != arf_unknown
+ || swap_bytes_flag || swap_halfwords_flag
+ || table_flag || rename_flag || append_flag
+ || rename_batch_file || no_abs_paths_flag)
+ usage (stderr, 2);
+ directory_name = argv[optind];
+ }
+
+ if (archive_name)
+ {
+ if (copy_function != copy_in && copy_function != copy_out)
+ usage (stderr, 2);
+ archive_des = open_archive (archive_name);
+ if (archive_des < 0)
+ error (1, errno, "%s", archive_name);
+ }
+
+#ifndef __MSDOS__
+ /* Prevent SysV non-root users from giving away files inadvertantly.
+ This happens automatically on BSD, where only root can give
+ away files. */
+ if (set_owner_flag == FALSE && set_group_flag == FALSE && geteuid ())
+ no_chown_flag = TRUE;
+#endif
+}
+
+/* Initialize the input and output buffers to their proper size and
+ initialize all variables associated with the input and output
+ buffers. */
+
+void
+initialize_buffers ()
+{
+ int in_buf_size, out_buf_size;
+
+ if (copy_function == process_copy_in)
+ {
+ /* Make sure the input buffer can always hold 2 blocks and that it
+ is big enough to hold 1 tar record (512 bytes) even if it
+ is not aligned on a block boundary. The extra buffer space
+ is needed by process_copyin and peek_in_buf to automatically
+ figure out what kind of archive it is reading. */
+ if (io_block_size >= 512)
+ in_buf_size = 2 * io_block_size;
+ else
+ in_buf_size = 1024;
+ out_buf_size = DISK_IO_BLOCK_SIZE;
+ }
+ else if (copy_function == process_copy_out)
+ {
+ in_buf_size = DISK_IO_BLOCK_SIZE;
+ out_buf_size = io_block_size;
+ }
+ else
+ {
+ in_buf_size = DISK_IO_BLOCK_SIZE;
+ out_buf_size = DISK_IO_BLOCK_SIZE;
+ }
+
+ input_buffer = (char *) xmalloc (in_buf_size);
+ in_buff = input_buffer;
+ input_buffer_size = in_buf_size;
+ input_size = 0;
+ input_bytes = 0;
+
+ output_buffer = (char *) xmalloc (out_buf_size);
+ out_buff = output_buffer;
+ output_size = 0;
+ output_bytes = 0;
+
+ /* Clear the block of zeros. */
+ bzero (zeros_512, 512);
+}
+
+void
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ program_name = argv[0];
+ umask (0);
+
+#ifdef __TURBOC__
+ _fmode = O_BINARY; /* Put stdin and stdout in binary mode. */
+#endif
+#ifdef __EMX__ /* gcc on OS/2. */
+ _response (&argc, &argv);
+ _wildcard (&argc, &argv);
+#endif
+
+ process_args (argc, argv);
+
+ initialize_buffers ();
+
+ (*copy_function) ();
+
+ if (archive_des >= 0 && rmtclose (archive_des) == -1)
+ error (1, errno, "error closing archive");
+
+ exit (0);
+}
diff --git a/contrib/cpio/makepath.c b/contrib/cpio/makepath.c
new file mode 100644
index 0000000..fc47871
--- /dev/null
+++ b/contrib/cpio/makepath.c
@@ -0,0 +1,307 @@
+/* makepath.c -- Ensure that a directory path exists.
+ Copyright (C) 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu> and
+ Jim Meyering <meyering@cs.utexas.edu>. */
+
+/* This copy of makepath is almost like the fileutils one, but has
+ changes for HPUX CDF's. Maybe the 2 versions of makepath can
+ come together again in the future. */
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+#include <errno.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+extern int errno;
+#endif
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#ifndef index
+#define index strchr
+#endif
+#else
+#include <strings.h>
+#endif
+
+#if defined(__MSDOS__) && !defined(__GNUC__)
+typedef int uid_t;
+typedef int gid_t;
+#endif
+
+void error ();
+
+/* Ensure that the directory ARGPATH exists.
+ Remove any trailing slashes from ARGPATH before calling this function.
+
+ Make any leading directories that don't already exist, with
+ permissions PARENT_MODE.
+ If the last element of ARGPATH does not exist, create it as
+ a new directory with permissions MODE.
+ If OWNER and GROUP are non-negative, make them the UID and GID of
+ created directories.
+ If VERBOSE_FMT_STRING is nonzero, use it as a printf format
+ string for printing a message after successfully making a directory,
+ with the name of the directory that was just made as an argument.
+
+ Return 0 if ARGPATH exists as a directory with the proper
+ ownership and permissions when done, otherwise 1. */
+
+int
+make_path (argpath, mode, parent_mode, owner, group, verbose_fmt_string)
+ char *argpath;
+ int mode;
+ int parent_mode;
+ uid_t owner;
+ gid_t group;
+ char *verbose_fmt_string;
+{
+ char *dirpath; /* A copy we can scribble NULs on. */
+ struct stat stats;
+ int retval = 0;
+ int oldmask = umask (0);
+ dirpath = alloca (strlen (argpath) + 1);
+ strcpy (dirpath, argpath);
+
+ if (stat (dirpath, &stats))
+ {
+ char *slash;
+ int tmp_mode; /* Initial perms for leading dirs. */
+ int re_protect; /* Should leading dirs be unwritable? */
+ struct ptr_list
+ {
+ char *dirname_end;
+ struct ptr_list *next;
+ };
+ struct ptr_list *p, *leading_dirs = NULL;
+
+ /* If leading directories shouldn't be writable or executable,
+ or should have set[ug]id or sticky bits set and we are setting
+ their owners, we need to fix their permissions after making them. */
+ if (((parent_mode & 0300) != 0300)
+ || (owner != (uid_t) -1 && group != (gid_t) -1
+ && (parent_mode & 07000) != 0))
+ {
+ tmp_mode = 0700;
+ re_protect = 1;
+ }
+ else
+ {
+ tmp_mode = parent_mode;
+ re_protect = 0;
+ }
+
+ slash = dirpath;
+ while (*slash == '/')
+ slash++;
+ while ((slash = index (slash, '/')))
+ {
+#ifdef HPUX_CDF
+ int iscdf;
+ iscdf = 0;
+#endif
+ *slash = '\0';
+ if (stat (dirpath, &stats))
+ {
+#ifdef HPUX_CDF
+ /* If this component of the pathname ends in `+' and is
+ followed by 2 `/'s, then this is a CDF. We remove the
+ `+' from the name and create the directory. Later
+ we will "hide" the directory. */
+ if ( (*(slash +1) == '/') && (*(slash -1) == '+') )
+ {
+ iscdf = 1;
+ *(slash -1) = '\0';
+ }
+#endif
+ if (mkdir (dirpath, tmp_mode))
+ {
+ error (0, errno, "cannot make directory `%s'", dirpath);
+ umask (oldmask);
+ return 1;
+ }
+ else
+ {
+ if (verbose_fmt_string != NULL)
+ error (0, 0, verbose_fmt_string, dirpath);
+
+ if (owner != (uid_t) -1 && group != (gid_t) -1
+ && chown (dirpath, owner, group)
+#ifdef AFS
+ && errno != EPERM
+#endif
+ )
+ {
+ error (0, errno, "%s", dirpath);
+ retval = 1;
+ }
+ if (re_protect)
+ {
+ struct ptr_list *new = (struct ptr_list *)
+ alloca (sizeof (struct ptr_list));
+ new->dirname_end = slash;
+ new->next = leading_dirs;
+ leading_dirs = new;
+ }
+#ifdef HPUX_CDF
+ if (iscdf)
+ {
+ /* If this is a CDF, "hide" the directory by setting
+ its hidden/setuid bit. Also add the `+' back to
+ its name (since once it's "hidden" we must refer
+ to as `name+' instead of `name'). */
+ chmod (dirpath, 04700);
+ *(slash - 1) = '+';
+ }
+#endif
+ }
+ }
+ else if (!S_ISDIR (stats.st_mode))
+ {
+ error (0, 0, "`%s' exists but is not a directory", dirpath);
+ umask (oldmask);
+ return 1;
+ }
+
+ *slash++ = '/';
+
+ /* Avoid unnecessary calls to `stat' when given
+ pathnames containing multiple adjacent slashes. */
+ while (*slash == '/')
+ slash++;
+ }
+
+ /* We're done making leading directories.
+ Make the final component of the path. */
+
+ if (mkdir (dirpath, mode))
+ {
+ /* In some cases, if the final component in dirpath was `.' then we
+ just got an EEXIST error from that last mkdir(). If that's
+ the case, ignore it. */
+ if ( (errno != EEXIST) ||
+ (stat (dirpath, &stats) != 0) ||
+ (!S_ISDIR (stats.st_mode) ) )
+ {
+ error (0, errno, "cannot make directory `%s'", dirpath);
+ umask (oldmask);
+ return 1;
+ }
+ }
+ if (verbose_fmt_string != NULL)
+ error (0, 0, verbose_fmt_string, dirpath);
+
+ if (owner != (uid_t) -1 && group != (gid_t) -1)
+ {
+ if (chown (dirpath, owner, group)
+#ifdef AFS
+ && errno != EPERM
+#endif
+ )
+ {
+ error (0, errno, "%s", dirpath);
+ retval = 1;
+ }
+ }
+ /* chown may have turned off some permission bits we wanted. */
+ if ((mode & 07000) != 0 && chmod (dirpath, mode))
+ {
+ error (0, errno, "%s", dirpath);
+ retval = 1;
+ }
+
+ /* If the mode for leading directories didn't include owner "wx"
+ privileges, we have to reset their protections to the correct
+ value. */
+ for (p = leading_dirs; p != NULL; p = p->next)
+ {
+ *(p->dirname_end) = '\0';
+#if 0
+ /* cpio always calls make_path with parent mode 0700, so
+ we don't have to do this. If we ever do have to do this,
+ we have to stat the directory first to get the setuid
+ bit so we don't break HP CDF's. */
+ if (chmod (dirpath, parent_mode))
+ {
+ error (0, errno, "%s", dirpath);
+ retval = 1;
+ }
+#endif
+
+ }
+ }
+ else
+ {
+ /* We get here if the entire path already exists. */
+
+ if (!S_ISDIR (stats.st_mode))
+ {
+ error (0, 0, "`%s' exists but is not a directory", dirpath);
+ umask (oldmask);
+ return 1;
+ }
+
+ /* chown must precede chmod because on some systems,
+ chown clears the set[ug]id bits for non-superusers,
+ resulting in incorrect permissions.
+ On System V, users can give away files with chown and then not
+ be able to chmod them. So don't give files away. */
+
+ if (owner != (uid_t) -1 && group != (gid_t) -1
+ && chown (dirpath, owner, group)
+#ifdef AFS
+ && errno != EPERM
+#endif
+ )
+ {
+ error (0, errno, "%s", dirpath);
+ retval = 1;
+ }
+ if (chmod (dirpath, mode))
+ {
+ error (0, errno, "%s", dirpath);
+ retval = 1;
+ }
+ }
+
+ umask (oldmask);
+ return retval;
+}
diff --git a/contrib/cpio/rmt.h b/contrib/cpio/rmt.h
new file mode 100644
index 0000000..2155223
--- /dev/null
+++ b/contrib/cpio/rmt.h
@@ -0,0 +1,98 @@
+/* Definitions for communicating with a remote tape drive.
+ Copyright (C) 1988, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if !defined(_POSIX_VERSION)
+#ifdef __MSDOS__
+#include <io.h>
+#else /* !__MSDOS__ */
+extern off_t lseek ();
+#endif /* __MSDOS__ */
+#endif /* _POSIX_VERSION */
+
+#ifdef NO_REMOTE
+#define _isrmt(f) 0
+#define rmtopen open
+#define rmtaccess access
+#define rmtstat stat
+#define rmtcreat creat
+#define rmtlstat lstat
+#define rmtread read
+#define rmtwrite write
+#define rmtlseek lseek
+#define rmtclose close
+#define rmtioctl ioctl
+#define rmtdup dup
+#define rmtfstat fstat
+#define rmtfcntl fcntl
+#define rmtisatty isatty
+
+#else /* !NO_REMOTE */
+
+#define __REM_BIAS 128
+#define RMTIOCTL
+
+#ifndef O_CREAT
+#define O_CREAT 01000
+#endif
+
+extern char *__rmt_path;
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#ifndef index
+#define index strchr
+#endif
+#else
+extern char *index ();
+#endif
+
+#define _remdev(path) (!f_force_local && (__rmt_path=index(path, ':')))
+#define _isrmt(fd) ((fd) >= __REM_BIAS)
+
+#define rmtopen(path,oflag,mode) (_remdev(path) ? __rmt_open(path, oflag, mode, __REM_BIAS) : open(path, oflag, mode))
+#define rmtaccess(path, amode) (_remdev(path) ? 0 : access(path, amode))
+#define rmtstat(path, buf) (_remdev(path) ? (errno = EOPNOTSUPP), -1 : stat(path, buf))
+#define rmtcreat(path, mode) (_remdev(path) ? __rmt_open (path, 1 | O_CREAT, mode, __REM_BIAS) : creat(path, mode))
+#define rmtlstat(path,buf) (_remdev(path) ? (errno = EOPNOTSUPP), -1 : lstat(path,buf))
+
+#define rmtread(fd, buf, n) (_isrmt(fd) ? __rmt_read(fd - __REM_BIAS, buf, n) : read(fd, buf, n))
+#define rmtwrite(fd, buf, n) (_isrmt(fd) ? __rmt_write(fd - __REM_BIAS, buf, n) : write(fd, buf, n))
+#define rmtlseek(fd, off, wh) (_isrmt(fd) ? __rmt_lseek(fd - __REM_BIAS, off, wh) : lseek(fd, off, wh))
+#define rmtclose(fd) (_isrmt(fd) ? __rmt_close(fd - __REM_BIAS) : close(fd))
+#ifdef RMTIOCTL
+#define rmtioctl(fd,req,arg) (_isrmt(fd) ? __rmt_ioctl(fd - __REM_BIAS, req, arg) : ioctl(fd, req, arg))
+#else
+#define rmtioctl(fd,req,arg) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : ioctl(fd, req, arg))
+#endif
+#define rmtdup(fd) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : dup(fd))
+#define rmtfstat(fd, buf) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : fstat(fd, buf))
+#define rmtfcntl(fd,cmd,arg) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : fcntl (fd, cmd, arg))
+#define rmtisatty(fd) (_isrmt(fd) ? 0 : isatty(fd))
+
+#undef RMTIOCTL
+
+int __rmt_open ();
+int __rmt_close ();
+int __rmt_read ();
+int __rmt_write ();
+long __rmt_lseek ();
+int __rmt_ioctl ();
+#endif /* !NO_REMOTE */
diff --git a/contrib/cpio/rtapelib.c b/contrib/cpio/rtapelib.c
new file mode 100644
index 0000000..eece76f
--- /dev/null
+++ b/contrib/cpio/rtapelib.c
@@ -0,0 +1,582 @@
+/* Functions for communicating with a remote tape drive.
+ Copyright (C) 1988, 1992 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., 675 Mass Ave, Cambridge, MA 02139, 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 rmtXXX calls into macros for speed by Jay Fenlason.
+ Use -DHAVE_NETDB_H for rexec code, courtesy of Dan Kegel, srs!dan. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#ifdef HAVE_SYS_MTIO_H
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/stat.h>
+
+#ifndef errno
+extern int errno;
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef STDC_HEADERS
+#include <string.h>
+#include <stdlib.h>
+#endif
+
+/* Maximum size of a fully qualified host name. */
+#define MAXHOSTLEN 257
+
+/* Size of buffers for reading and writing commands to rmt.
+ (An arbitrary limit.) */
+#define CMDBUFSIZE 64
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+
+/* Maximum number of simultaneous remote tape connections.
+ (Another arbitrary limit.) */
+#define MAXUNIT 4
+
+/* Return the parent's read side of remote tape connection FILDES. */
+#define READ(fildes) (from_rmt[fildes][0])
+
+/* Return the parent's write side of remote tape connection FILDES. */
+#define WRITE(fildes) (to_rmt[fildes][1])
+
+/* The pipes for receiving data from remote tape drives. */
+static int from_rmt[MAXUNIT][2] =
+{-1, -1, -1, -1, -1, -1, -1, -1};
+
+/* The pipes for sending data to remote tape drives. */
+static int to_rmt[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 FILDES. */
+
+static void
+_rmt_shutdown (fildes)
+ int fildes;
+{
+ close (READ (fildes));
+ close (WRITE (fildes));
+ READ (fildes) = -1;
+ WRITE (fildes) = -1;
+}
+
+/* Attempt to perform the remote tape command specified in BUF
+ on remote tape connection FILDES.
+ Return 0 if successful, -1 on error. */
+
+static int
+command (fildes, buf)
+ int fildes;
+ char *buf;
+{
+ register int buflen;
+ RETSIGTYPE (*pipe_handler) ();
+
+ /* Save the current pipe handler and try to make the request. */
+
+ pipe_handler = signal (SIGPIPE, SIG_IGN);
+ buflen = strlen (buf);
+ if (write (WRITE (fildes), buf, buflen) == buflen)
+ {
+ signal (SIGPIPE, pipe_handler);
+ return 0;
+ }
+
+ /* Something went wrong. Close down and go home. */
+
+ signal (SIGPIPE, pipe_handler);
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+}
+
+/* Read and return the status from remote tape connection FILDES.
+ If an error occurred, return -1 and set errno. */
+
+static int
+status (fildes)
+ int fildes;
+{
+ int i;
+ char c, *cp;
+ char buffer[CMDBUFSIZE];
+
+ /* Read the reply command line. */
+
+ for (i = 0, cp = buffer; i < CMDBUFSIZE; i++, cp++)
+ {
+ if (read (READ (fildes), cp, 1) != 1)
+ {
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+ }
+ if (*cp == '\n')
+ {
+ *cp = '\0';
+ break;
+ }
+ }
+
+ if (i == CMDBUFSIZE)
+ {
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+ }
+
+ /* Check the return status. */
+
+ for (cp = buffer; *cp; cp++)
+ if (*cp != ' ')
+ break;
+
+ if (*cp == 'E' || *cp == 'F')
+ {
+ errno = atoi (cp + 1);
+ /* Skip the error message line. */
+ while (read (READ (fildes), &c, 1) == 1)
+ if (c == '\n')
+ break;
+
+ if (*cp == 'F')
+ _rmt_shutdown (fildes);
+
+ return -1;
+ }
+
+ /* Check for mis-synced pipes. */
+
+ if (*cp != 'A')
+ {
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+ }
+
+ /* Got an `A' (success) response. */
+ return atoi (cp + 1);
+}
+
+#ifdef HAVE_NETDB_H
+/* 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 NULL, or an empty string, 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 (host, user)
+ char *host;
+ char *user;
+{
+ struct servent *rexecserv;
+ int save_stdin = dup (fileno (stdin));
+ int save_stdout = dup (fileno (stdout));
+ int tape_fd; /* Return value. */
+
+ /* 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) == NULL)
+ freopen ("/dev/null", "r", stdin);
+ if (freopen ("/dev/tty", "w", stdout) == NULL)
+ freopen ("/dev/null", "w", stdout);
+
+ rexecserv = getservbyname ("exec", "tcp");
+ if (NULL == rexecserv)
+ {
+ fprintf (stderr, "exec/tcp: service not available");
+ exit (1);
+ }
+ if (user != NULL && *user == '\0')
+ user = NULL;
+ tape_fd = rexec (&host, rexecserv->s_port, user, NULL,
+ "/etc/rmt", (int *) NULL);
+ fclose (stdin);
+ fdopen (save_stdin, "r");
+ fclose (stdout);
+ fdopen (save_stdout, "w");
+
+ return tape_fd;
+}
+
+#endif /* HAVE_NETDB_H */
+
+/* Open a magtape device on the system specified in PATH, as the given user.
+ PATH has the form `[user@]system:/dev/????'.
+ If COMPAT is defined, it can also have the form `system[.user]:/dev/????'.
+
+ OFLAG is O_RDONLY, O_WRONLY, etc.
+ MODE is ignored; 0666 is always used.
+
+ If successful, return the remote tape pipe number plus BIAS.
+ On error, return -1. */
+
+int
+__rmt_open (path, oflag, mode, bias)
+ char *path;
+ int oflag;
+ int mode;
+ int bias;
+{
+ int i, rc;
+ char buffer[CMDBUFSIZE]; /* Command buffer. */
+ char system[MAXHOSTLEN]; /* The remote host name. */
+ char device[CMDBUFSIZE]; /* The remote device name. */
+ char login[CMDBUFSIZE]; /* The remote user name. */
+ char *sys, *dev, *user; /* For copying into the above buffers. */
+
+ sys = system;
+ dev = device;
+ user = login;
+
+ /* Find an unused pair of file descriptors. */
+
+ for (i = 0; i < MAXUNIT; i++)
+ if (READ (i) == -1 && WRITE (i) == -1)
+ break;
+
+ if (i == MAXUNIT)
+ {
+ errno = EMFILE;
+ return -1;
+ }
+
+ /* Pull apart the system and device, and optional user.
+ Don't munge the original string. */
+
+ while (*path != '@'
+#ifdef COMPAT
+ && *path != '.'
+#endif
+ && *path != ':')
+ {
+ *sys++ = *path++;
+ }
+ *sys = '\0';
+ path++;
+
+ if (*(path - 1) == '@')
+ {
+ /* Saw user part of user@host. Start over. */
+ strcpy (user, system);
+ sys = system;
+ while (*path != ':')
+ {
+ *sys++ = *path++;
+ }
+ *sys = '\0';
+ path++;
+ }
+#ifdef COMPAT
+ else if (*(path - 1) == '.')
+ {
+ while (*path != ':')
+ {
+ *user++ = *path++;
+ }
+ *user = '\0';
+ path++;
+ }
+#endif
+ else
+ *user = '\0';
+
+ while (*path)
+ {
+ *dev++ = *path++;
+ }
+ *dev = '\0';
+
+#ifdef HAVE_NETDB_H
+ /* Execute the remote command using rexec. */
+ READ (i) = WRITE (i) = _rmt_rexec (system, login);
+ if (READ (i) < 0)
+ return -1;
+#else /* !HAVE_NETDB_H */
+ /* Set up the pipes for the `rsh' command, and fork. */
+
+ if (pipe (to_rmt[i]) == -1 || pipe (from_rmt[i]) == -1)
+ return -1;
+
+ rc = fork ();
+ if (rc == -1)
+ return -1;
+
+ if (rc == 0)
+ {
+ /* Child. */
+ close (0);
+ dup (to_rmt[i][0]);
+ close (to_rmt[i][0]);
+ close (to_rmt[i][1]);
+
+ close (1);
+ dup (from_rmt[i][1]);
+ close (from_rmt[i][0]);
+ close (from_rmt[i][1]);
+
+ setuid (getuid ());
+ setgid (getgid ());
+
+ if (*login)
+ {
+ execl ("/usr/ucb/rsh", "rsh", system, "-l", login,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bin/remsh", "remsh", system, "-l", login,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bin/rsh", "rsh", system, "-l", login,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bsd/rsh", "rsh", system, "-l", login,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bin/nsh", "nsh", system, "-l", login,
+ "/etc/rmt", (char *) 0);
+ }
+ else
+ {
+ execl ("/usr/ucb/rsh", "rsh", system,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bin/remsh", "remsh", system,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bin/rsh", "rsh", system,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bsd/rsh", "rsh", system,
+ "/etc/rmt", (char *) 0);
+ execl ("/usr/bin/nsh", "nsh", system,
+ "/etc/rmt", (char *) 0);
+ }
+
+ /* Bad problems if we get here. */
+
+ perror ("cannot execute remote shell");
+ _exit (1);
+ }
+
+ /* Parent. */
+ close (to_rmt[i][0]);
+ close (from_rmt[i][1]);
+#endif /* !HAVE_NETDB_H */
+
+ /* Attempt to open the tape device. */
+
+ sprintf (buffer, "O%s\n%d\n", device, oflag);
+ if (command (i, buffer) == -1 || status (i) == -1)
+ return -1;
+
+ return i + bias;
+}
+
+/* Close remote tape connection FILDES and shut down.
+ Return 0 if successful, -1 on error. */
+
+int
+__rmt_close (fildes)
+ int fildes;
+{
+ int rc;
+
+ if (command (fildes, "C\n") == -1)
+ return -1;
+
+ rc = status (fildes);
+ _rmt_shutdown (fildes);
+ return rc;
+}
+
+/* Read up to NBYTE bytes into BUF from remote tape connection FILDES.
+ Return the number of bytes read on success, -1 on error. */
+
+int
+__rmt_read (fildes, buf, nbyte)
+ int fildes;
+ char *buf;
+ unsigned int nbyte;
+{
+ int rc, i;
+ char buffer[CMDBUFSIZE];
+
+ sprintf (buffer, "R%d\n", nbyte);
+ if (command (fildes, buffer) == -1 || (rc = status (fildes)) == -1)
+ return -1;
+
+ for (i = 0; i < rc; i += nbyte, buf += nbyte)
+ {
+ nbyte = read (READ (fildes), buf, rc - i);
+ if (nbyte <= 0)
+ {
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+ }
+ }
+
+ return rc;
+}
+
+/* Write NBYTE bytes from BUF to remote tape connection FILDES.
+ Return the number of bytes written on success, -1 on error. */
+
+int
+__rmt_write (fildes, buf, nbyte)
+ int fildes;
+ char *buf;
+ unsigned int nbyte;
+{
+ char buffer[CMDBUFSIZE];
+ RETSIGTYPE (*pipe_handler) ();
+
+ sprintf (buffer, "W%d\n", nbyte);
+ if (command (fildes, buffer) == -1)
+ return -1;
+
+ pipe_handler = signal (SIGPIPE, SIG_IGN);
+ if (write (WRITE (fildes), buf, nbyte) == nbyte)
+ {
+ signal (SIGPIPE, pipe_handler);
+ return status (fildes);
+ }
+
+ /* Write error. */
+ signal (SIGPIPE, pipe_handler);
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+}
+
+/* Perform an imitation lseek operation on remote tape connection FILDES.
+ Return the new file offset if successful, -1 if on error. */
+
+long
+__rmt_lseek (fildes, offset, whence)
+ int fildes;
+ long offset;
+ int whence;
+{
+ char buffer[CMDBUFSIZE];
+
+ sprintf (buffer, "L%ld\n%d\n", offset, whence);
+ if (command (fildes, buffer) == -1)
+ return -1;
+
+ return status (fildes);
+}
+
+/* Perform a raw tape operation on remote tape connection FILDES.
+ Return the results of the ioctl, or -1 on error. */
+
+#ifdef MTIOCTOP
+int
+__rmt_ioctl (fildes, op, arg)
+ int fildes, op;
+ char *arg;
+{
+ char c;
+ int rc, cnt;
+ char buffer[CMDBUFSIZE];
+
+ switch (op)
+ {
+ default:
+ errno = EINVAL;
+ return -1;
+
+ case MTIOCTOP:
+ /* MTIOCTOP is the easy one. Nothing is transfered in binary. */
+ sprintf (buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
+ ((struct mtop *) arg)->mt_count);
+ if (command (fildes, buffer) == -1)
+ return -1;
+ return status (fildes); /* Return the count. */
+
+ case MTIOCGET:
+ /* 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 (command (fildes, "S") == -1 || (rc = status (fildes)) == -1)
+ return -1;
+
+ for (; rc > 0; rc -= cnt, arg += cnt)
+ {
+ cnt = read (READ (fildes), arg, rc);
+ if (cnt <= 0)
+ {
+ _rmt_shutdown (fildes);
+ errno = EIO;
+ return -1;
+ }
+ }
+
+ /* Check for byte position. mt_type 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 *) arg)->mt_type < 256)
+ return 0;
+
+ for (cnt = 0; cnt < rc; cnt += 2)
+ {
+ c = arg[cnt];
+ arg[cnt] = arg[cnt + 1];
+ arg[cnt + 1] = c;
+ }
+
+ return 0;
+ }
+}
+
+#endif
diff --git a/contrib/cpio/safe-stat.h b/contrib/cpio/safe-stat.h
new file mode 100644
index 0000000..3a37970
--- /dev/null
+++ b/contrib/cpio/safe-stat.h
@@ -0,0 +1 @@
+#define SAFE_STAT(path,pbuf) stat(path,pbuf)
diff --git a/contrib/cpio/stripslash.c b/contrib/cpio/stripslash.c
new file mode 100644
index 0000000..67330e5
--- /dev/null
+++ b/contrib/cpio/stripslash.c
@@ -0,0 +1,43 @@
+/* stripslash.c -- remove trailing slashes from a string
+ Copyright (C) 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/* Remove trailing slashes from PATH.
+ This is useful when using filename completion from a shell that
+ adds a "/" after directory names (such as tcsh and bash), because
+ the Unix rename and rmdir system calls return an "Invalid argument" error
+ when given a path that ends in "/" (except for the root directory). */
+
+void
+strip_trailing_slashes (path)
+ char *path;
+{
+ int last;
+
+ last = strlen (path) - 1;
+ while (last > 0 && path[last] == '/')
+ path[last--] = '\0';
+}
diff --git a/contrib/cpio/system.h b/contrib/cpio/system.h
new file mode 100644
index 0000000..e4cf0ff
--- /dev/null
+++ b/contrib/cpio/system.h
@@ -0,0 +1,142 @@
+/* System dependent declarations. Requires sys/types.h.
+ Copyright (C) 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#ifndef index
+#define index strchr
+#endif
+#ifndef rindex
+#define rindex strrchr
+#endif
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n) memset ((s), 0, (n))
+#endif
+#else
+#include <strings.h>
+#endif
+
+#include <time.h>
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+#ifndef _POSIX_VERSION
+#if defined(__MSDOS__) && !defined(__GNUC__)
+typedef long off_t;
+#endif
+off_t lseek ();
+#endif
+
+/* Since major is a function on SVR4, we can't use `ifndef major'. */
+#ifdef MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#define HAVE_MAJOR
+#endif
+
+#ifdef MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#define HAVE_MAJOR
+#endif
+
+#ifdef major /* Might be defined in sys/types.h. */
+#define HAVE_MAJOR
+#endif
+
+#ifndef HAVE_MAJOR
+#define major(dev) (((dev) >> 8) & 0xff)
+#define minor(dev) ((dev) & 0xff)
+#define makedev(ma, mi) (((ma) << 8) | (mi))
+#endif
+#undef HAVE_MAJOR
+
+#if defined(__MSDOS__) || defined(_POSIX_VERSION) || defined(HAVE_FCNTL_H)
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#endif
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#ifdef __EMX__ /* gcc on OS/2. */
+#define EPERM EACCES
+#define ENXIO EIO
+#endif
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#else
+struct utimbuf
+{
+ time_t actime;
+ time_t modtime;
+};
+#endif
+
+#ifdef TRUE
+#undef TRUE
+#endif
+#define TRUE 1
+#ifdef FALSE
+#undef FALSE
+#endif
+#define FALSE 0
+
+#ifndef __MSDOS__
+#define CONSOLE "/dev/tty"
+#else
+#define CONSOLE "con"
+#endif
+
+#if defined(__MSDOS__) && !defined(__GNUC__)
+typedef int uid_t;
+typedef int gid_t;
+#endif
+
+/* On most systems symlink() always creates links with rwxrwxrwx
+ protection modes, but on some (HP/UX 8.07; I think maybe DEC's OSF
+ on MIPS too) symlink() uses the value of umask, so links' protection modes
+ aren't always rwxrwxrwx. There doesn't seem to be any way to change
+ the modes of a link (no system call like, say, lchmod() ), it seems
+ the only way to set the modes right is to set umask before calling
+ symlink(). */
+
+#ifndef SYMLINK_USES_UMASK
+#define UMASKED_SYMLINK(name1,name2,mode) symlink(name1,name2)
+#else
+#define UMASKED_SYMLINK(name1,name2,mode) umasked_symlink(name1,name2,mode)
+#endif /* SYMLINK_USES_UMASK */
+
diff --git a/contrib/cpio/tar.c b/contrib/cpio/tar.c
new file mode 100644
index 0000000..333ec20
--- /dev/null
+++ b/contrib/cpio/tar.c
@@ -0,0 +1,522 @@
+/* tar.c - read in write tar headers for cpio
+ Copyright (C) 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "filetypes.h"
+#include "system.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "rmt.h"
+#include "tarhdr.h"
+
+static void to_oct ();
+static char *stash_tar_linkname ();
+static char *stash_tar_filename ();
+
+/* Compute and return a checksum for TAR_HDR,
+ counting the checksum bytes as if they were spaces. */
+
+unsigned long
+tar_checksum (tar_hdr)
+ struct tar_header *tar_hdr;
+{
+ unsigned long sum = 0;
+ char *p = (char *) tar_hdr;
+ char *q = p + TARRECORDSIZE;
+ int i;
+
+ while (p < tar_hdr->chksum)
+ sum += *p++ & 0xff;
+ for (i = 0; i < 8; ++i)
+ {
+ sum += ' ';
+ ++p;
+ }
+ while (p < q)
+ sum += *p++ & 0xff;
+ return sum;
+}
+
+/* Write out header FILE_HDR, including the file name, to file
+ descriptor OUT_DES. */
+
+void
+write_out_tar_header (file_hdr, out_des)
+ struct new_cpio_header *file_hdr;
+ int out_des;
+{
+ int name_len;
+ union tar_record tar_rec;
+ struct tar_header *tar_hdr = (struct tar_header *) &tar_rec;
+
+ bzero ((char *) &tar_rec, TARRECORDSIZE);
+
+ /* process_copy_out must ensure that file_hdr->c_name is short enough,
+ or we will lose here. */
+
+ name_len = strlen (file_hdr->c_name);
+ if (name_len <= TARNAMESIZE)
+ {
+ strncpy (tar_hdr->name, file_hdr->c_name, name_len);
+ }
+ else
+ {
+ /* Fit as much as we can into `name', the rest into `prefix'. */
+ char *suffix = file_hdr->c_name + name_len - TARNAMESIZE;
+
+ /* We have to put the boundary at a slash. */
+ name_len = TARNAMESIZE;
+ while (*suffix != '/')
+ {
+ --name_len;
+ ++suffix;
+ }
+ strncpy (tar_hdr->name, suffix + 1, name_len);
+ strncpy (tar_hdr->prefix, file_hdr->c_name, suffix - file_hdr->c_name);
+ }
+
+ /* SVR4 seems to want the whole mode, not just protection modes.
+ Nobody else seems to care, so we might as well put it all in. */
+ to_oct (file_hdr->c_mode, 8, tar_hdr->mode);
+ to_oct (file_hdr->c_uid, 8, tar_hdr->uid);
+ to_oct (file_hdr->c_gid, 8, tar_hdr->gid);
+ to_oct (file_hdr->c_filesize, 12, tar_hdr->size);
+ to_oct (file_hdr->c_mtime, 12, tar_hdr->mtime);
+
+ switch (file_hdr->c_mode & CP_IFMT)
+ {
+ case CP_IFREG:
+ if (file_hdr->c_tar_linkname)
+ {
+ /* process_copy_out makes sure that c_tar_linkname is shorter
+ than TARLINKNAMESIZE. */
+ strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname,
+ TARLINKNAMESIZE);
+ tar_hdr->typeflag = LNKTYPE;
+ to_oct (0, 12, tar_hdr->size);
+ }
+ else
+ tar_hdr->typeflag = REGTYPE;
+ break;
+ case CP_IFDIR:
+ tar_hdr->typeflag = DIRTYPE;
+ break;
+#ifndef __MSDOS__
+ case CP_IFCHR:
+ tar_hdr->typeflag = CHRTYPE;
+ break;
+ case CP_IFBLK:
+ tar_hdr->typeflag = BLKTYPE;
+ break;
+#ifdef CP_IFIFO
+ case CP_IFIFO:
+ tar_hdr->typeflag = FIFOTYPE;
+ break;
+#endif /* CP_IFIFO */
+#ifdef CP_IFLNK
+ case CP_IFLNK:
+ tar_hdr->typeflag = SYMTYPE;
+ /* process_copy_out makes sure that c_tar_linkname is shorter
+ than TARLINKNAMESIZE. */
+ strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname,
+ TARLINKNAMESIZE);
+ to_oct (0, 12, tar_hdr->size);
+ break;
+#endif /* CP_IFLNK */
+#endif /* !__MSDOS__ */
+ }
+
+ if (archive_format == arf_ustar)
+ {
+ char *name;
+
+ strncpy (tar_hdr->magic, TMAGIC, TMAGLEN);
+ strncpy (tar_hdr->magic + TMAGLEN, TVERSION, TVERSLEN);
+
+#ifndef __MSDOS__
+ name = getuser (file_hdr->c_uid);
+ if (name)
+ strcpy (tar_hdr->uname, name);
+ name = getgroup (file_hdr->c_gid);
+ if (name)
+ strcpy (tar_hdr->gname, name);
+#endif
+
+ to_oct (file_hdr->c_rdev_maj, 8, tar_hdr->devmajor);
+ to_oct (file_hdr->c_rdev_min, 8, tar_hdr->devminor);
+ }
+
+ to_oct (tar_checksum (tar_hdr), 8, tar_hdr->chksum);
+
+ tape_buffered_write ((char *) &tar_rec, out_des, TARRECORDSIZE);
+}
+
+/* Return nonzero iff all the bytes in BLOCK are NUL.
+ SIZE is the number of bytes to check in BLOCK; it must be a
+ multiple of sizeof (long). */
+
+int
+null_block (block, size)
+ long *block;
+ int size;
+{
+ register long *p = block;
+ register int i = size / sizeof (long);
+
+ while (i--)
+ if (*p++)
+ return 0;
+ return 1;
+}
+
+/* Read a tar header, including the file name, from file descriptor IN_DES
+ into FILE_HDR. */
+
+void
+read_in_tar_header (file_hdr, in_des)
+ struct new_cpio_header *file_hdr;
+ int in_des;
+{
+ long bytes_skipped = 0;
+ int warned = FALSE;
+ union tar_record tar_rec;
+ struct tar_header *tar_hdr = (struct tar_header *) &tar_rec;
+#ifndef __MSDOS__
+ uid_t *uidp;
+ gid_t *gidp;
+#endif
+
+ tape_buffered_read ((char *) &tar_rec, in_des, TARRECORDSIZE);
+
+ /* Check for a block of 0's. */
+ if (null_block ((long *) &tar_rec, TARRECORDSIZE))
+ {
+#if 0
+ /* Found one block of 512 0's. If the next block is also all 0's
+ then this is the end of the archive. If not, assume the
+ previous block was all corruption and continue reading
+ the archive. */
+ /* Commented out because GNU tar sometimes creates archives with
+ only one block of 0's at the end. This happened for the
+ cpio 2.0 distribution! */
+ tape_buffered_read ((char *) &tar_rec, in_des, TARRECORDSIZE);
+ if (null_block ((long *) &tar_rec, TARRECORDSIZE))
+#endif
+ {
+ file_hdr->c_name = "TRAILER!!!";
+ return;
+ }
+#if 0
+ bytes_skipped = TARRECORDSIZE;
+#endif
+ }
+
+ while (1)
+ {
+ otoa (tar_hdr->chksum, &file_hdr->c_chksum);
+
+ if (file_hdr->c_chksum != tar_checksum (tar_hdr))
+ {
+ /* If the checksum is bad, skip 1 byte and try again. When
+ we try again we do not look for an EOF record (all zeros),
+ because when we start skipping bytes in a corrupted archive
+ the chances are pretty good that we might stumble across
+ 2 blocks of 512 zeros (that probably is not really the last
+ record) and it is better to miss the EOF and give the user
+ a "premature EOF" error than to give up too soon on a corrupted
+ archive. */
+ if (!warned)
+ {
+ error (0, 0, "invalid header: checksum error");
+ warned = TRUE;
+ }
+ bcopy (((char *) &tar_rec) + 1, (char *) &tar_rec,
+ TARRECORDSIZE - 1);
+ tape_buffered_read (((char *) &tar_rec) + (TARRECORDSIZE - 1), in_des, 1);
+ ++bytes_skipped;
+ continue;
+ }
+
+ if (archive_format != arf_ustar)
+ file_hdr->c_name = stash_tar_filename (NULL, tar_hdr->name);
+ else
+ file_hdr->c_name = stash_tar_filename (tar_hdr->prefix, tar_hdr->name);
+ file_hdr->c_nlink = 1;
+ otoa (tar_hdr->mode, &file_hdr->c_mode);
+ file_hdr->c_mode = file_hdr->c_mode & 07777;
+#ifndef __MSDOS__
+ if (archive_format == arf_ustar
+ && (uidp = getuidbyname (tar_hdr->uname)))
+ file_hdr->c_uid = *uidp;
+ else
+#endif
+ otoa (tar_hdr->uid, &file_hdr->c_uid);
+#ifndef __MSDOS__
+ if (archive_format == arf_ustar
+ && (gidp = getgidbyname (tar_hdr->gname)))
+ file_hdr->c_gid = *gidp;
+ else
+#endif
+ otoa (tar_hdr->gid, &file_hdr->c_gid);
+ otoa (tar_hdr->size, &file_hdr->c_filesize);
+ otoa (tar_hdr->mtime, &file_hdr->c_mtime);
+ otoa (tar_hdr->devmajor, (unsigned long *) &file_hdr->c_rdev_maj);
+ otoa (tar_hdr->devminor, (unsigned long *) &file_hdr->c_rdev_min);
+ file_hdr->c_tar_linkname = NULL;
+
+ switch (tar_hdr->typeflag)
+ {
+ case REGTYPE:
+ case CONTTYPE: /* For now, punt. */
+ default:
+ file_hdr->c_mode |= CP_IFREG;
+ break;
+ case DIRTYPE:
+ file_hdr->c_mode |= CP_IFDIR;
+ break;
+#ifndef __MSDOS__
+ case CHRTYPE:
+ file_hdr->c_mode |= CP_IFCHR;
+ /* If a POSIX tar header has a valid linkname it's always supposed
+ to set typeflag to be LNKTYPE. System V.4 tar seems to
+ be broken, and for device files with multiple links it
+ puts the name of the link into linkname, but leaves typeflag
+ as CHRTYPE, BLKTYPE, FIFOTYPE, etc. */
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+
+ /* Does POSIX say that the filesize must be 0 for devices? We
+ assume so, but HPUX's POSIX tar sets it to be 1 which causes
+ us problems (when reading an archive we assume we can always
+ skip to the next file by skipping filesize bytes). For
+ now at least, it's easier to clear filesize for devices,
+ rather than check everywhere we skip in copyin.c. */
+ file_hdr->c_filesize = 0;
+ break;
+ case BLKTYPE:
+ file_hdr->c_mode |= CP_IFBLK;
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+ file_hdr->c_filesize = 0;
+ break;
+#ifdef CP_IFIFO
+ case FIFOTYPE:
+ file_hdr->c_mode |= CP_IFIFO;
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+ file_hdr->c_filesize = 0;
+ break;
+#endif
+ case SYMTYPE:
+#ifdef CP_IFLNK
+ file_hdr->c_mode |= CP_IFLNK;
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+ file_hdr->c_filesize = 0;
+ break;
+ /* Else fall through. */
+#endif
+ case LNKTYPE:
+ file_hdr->c_mode |= CP_IFREG;
+ file_hdr->c_tar_linkname = stash_tar_linkname (tar_hdr->linkname);
+ file_hdr->c_filesize = 0;
+ break;
+#endif /* !__MSDOS__ */
+ case AREGTYPE:
+ /* Old tar format; if the last char in filename is '/' then it is
+ a directory, otherwise it's a regular file. */
+ if (file_hdr->c_name[strlen (file_hdr->c_name) - 1] == '/')
+ file_hdr->c_mode |= CP_IFDIR;
+ else
+ file_hdr->c_mode |= CP_IFREG;
+ break;
+ }
+ break;
+ }
+ if (bytes_skipped > 0)
+ error (0, 0, "warning: skipped %ld bytes of junk", bytes_skipped);
+}
+
+/* Stash the tar linkname in static storage. */
+
+static char *
+stash_tar_linkname (linkname)
+ char *linkname;
+{
+ static char hold_tar_linkname[TARLINKNAMESIZE + 1];
+
+ strncpy (hold_tar_linkname, linkname, TARLINKNAMESIZE);
+ hold_tar_linkname[TARLINKNAMESIZE] = '\0';
+ return hold_tar_linkname;
+}
+
+/* Stash the tar filename and optional prefix in static storage. */
+
+static char *
+stash_tar_filename (prefix, filename)
+ char *prefix;
+ char *filename;
+{
+ static char hold_tar_filename[TARNAMESIZE + TARPREFIXSIZE + 2];
+ if (prefix == NULL || *prefix == '\0')
+ {
+ strncpy (hold_tar_filename, filename, TARNAMESIZE);
+ hold_tar_filename[TARNAMESIZE] = '\0';
+ }
+ else
+ {
+ strncpy (hold_tar_filename, prefix, TARPREFIXSIZE);
+ hold_tar_filename[TARPREFIXSIZE] = '\0';
+ strcat (hold_tar_filename, "/");
+ strncat (hold_tar_filename, filename, TARNAMESIZE);
+ hold_tar_filename[TARPREFIXSIZE + TARNAMESIZE] = '\0';
+ }
+ return hold_tar_filename;
+}
+
+/* Convert the string of octal digits S into a number and store
+ it in *N. Return nonzero if the whole string was converted,
+ zero if there was something after the number.
+ Skip leading and trailing spaces. */
+
+int
+otoa (s, n)
+ char *s;
+ unsigned long *n;
+{
+ unsigned long val = 0;
+
+ while (*s == ' ')
+ ++s;
+ while (*s >= '0' && *s <= '7')
+ val = 8 * val + *s++ - '0';
+ while (*s == ' ')
+ ++s;
+ *n = val;
+ return *s == '\0';
+}
+
+/* Convert a number into a string of octal digits.
+ Convert long VALUE into a DIGITS-digit field at WHERE,
+ including a trailing space and room for a NUL. DIGITS==3 means
+ 1 digit, a space, and room for a NUL.
+
+ We assume the trailing NUL is already there and don't fill it in.
+ This fact is used by start_header and finish_header, so don't change it!
+
+ This is be equivalent to:
+ sprintf (where, "%*lo ", digits - 2, value);
+ except that sprintf fills in the trailing NUL and we don't. */
+
+static void
+to_oct (value, digits, where)
+ register long value;
+ register int digits;
+ register char *where;
+{
+ --digits; /* Leave the trailing NUL slot alone. */
+ where[--digits] = ' '; /* Put in the space, though. */
+
+ /* Produce the digits -- at least one. */
+ do
+ {
+ where[--digits] = '0' + (char) (value & 7); /* One octal digit. */
+ value >>= 3;
+ }
+ while (digits > 0 && value != 0);
+
+ /* Add leading spaces, if necessary. */
+ while (digits > 0)
+ where[--digits] = ' ';
+}
+
+/* Return
+ 2 if BUF is a valid POSIX tar header (the checksum is correct
+ and it has the "ustar" magic string),
+ 1 if BUF is a valid old tar header (the checksum is correct),
+ 0 otherwise. */
+
+int
+is_tar_header (buf)
+ char *buf;
+{
+ struct tar_header *tar_hdr = (struct tar_header *) buf;
+ unsigned long chksum;
+
+ otoa (tar_hdr->chksum, &chksum);
+
+ if (chksum != tar_checksum (tar_hdr))
+ return 0;
+
+ /* GNU tar 1.10 and previous set the magic field to be "ustar " instead
+ of "ustar\0". Only look at the first 5 characters of the magic
+ field so we can recognize old GNU tar ustar archives. */
+ if (!strncmp (tar_hdr->magic, TMAGIC, TMAGLEN - 1))
+ return 2;
+ return 1;
+}
+
+/* Return TRUE if the filename is too long to fit in a tar header.
+ For old tar headers, if the filename's length is less than or equal
+ to 100 then it will fit, otherwise it will not. For POSIX tar headers,
+ if the filename's length is less than or equal to 100 then it
+ will definitely fit, and if it is greater than 256 then it
+ will definitely not fit. If the length is between 100 and 256,
+ then the filename will fit only if it is possible to break it
+ into a 155 character "prefix" and 100 character "name". There
+ must be a slash between the "prefix" and the "name", although
+ the slash is not stored or counted in either the "prefix" or
+ the "name", and there must be at least one character in both
+ the "prefix" and the "name". If it is not possible to break down
+ the filename like this then it will not fit. */
+
+int
+is_tar_filename_too_long (name)
+ char *name;
+{
+ int whole_name_len;
+ int prefix_name_len;
+ char *p;
+
+ whole_name_len = strlen (name);
+ if (whole_name_len <= TARNAMESIZE)
+ return FALSE;
+
+ if (archive_format != arf_ustar)
+ return TRUE;
+
+ if (whole_name_len > TARNAMESIZE + TARPREFIXSIZE + 1)
+ return TRUE;
+
+ /* See whether we can split up the name into acceptably-sized
+ `prefix' and `name' (`p') pieces. Start out by making `name'
+ as big as possible, then shrink it by looking for the first '/'. */
+ p = name + whole_name_len - TARNAMESIZE;
+ while (*p != '/' && *p != '\0')
+ ++p;
+ if (*p == '\0')
+ /* The last component of the path is longer than TARNAMESIZE. */
+ return TRUE;
+
+ prefix_name_len = p - name - 1;
+ /* Interestingly, a name consisting of a slash followed by
+ TARNAMESIZE characters can't be stored, because the prefix
+ would be empty, and thus ignored. */
+ if (prefix_name_len > TARPREFIXSIZE || prefix_name_len == 0)
+ return TRUE;
+
+ return FALSE;
+}
diff --git a/contrib/cpio/tar.h b/contrib/cpio/tar.h
new file mode 100644
index 0000000..411579c
--- /dev/null
+++ b/contrib/cpio/tar.h
@@ -0,0 +1,112 @@
+/* Extended tar format from POSIX.1.
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by David J. MacKenzie.
+
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#ifndef _TAR_H
+
+#define _TAR_H 1
+
+
+/* A tar archive consists of 512-byte blocks.
+ Each file in the archive has a header block followed by 0+ data blocks.
+ Two blocks of NUL bytes indicate the end of the archive. */
+
+/* The fields of header blocks:
+ All strings are stored as ISO 646 (approximately ASCII) strings.
+
+ Fields are numeric unless otherwise noted below; numbers are ISO 646
+ representations of octal numbers, with leading zeros as needed.
+
+ linkname is only valid when typeflag==LNKTYPE. It doesn't use prefix;
+ files that are links to pathnames >100 chars long can not be stored
+ in a tar archive.
+
+ If typeflag=={LNKTYPE,SYMTYPE,DIRTYPE} then size must be 0.
+
+ devmajor and devminor are only valid for typeflag=={BLKTYPE,CHRTYPE}.
+
+ chksum contains the sum of all 512 bytes in the header block,
+ treating each byte as an 8-bit unsigned value and treating the
+ 8 bytes of chksum as blank characters.
+
+ uname and gname are used in preference to uid and gid, if those
+ names exist locally.
+
+ Field Name Byte Offset Length in Bytes Field Type
+ name 0 100 NUL-terminated if NUL fits
+ mode 100 8
+ uid 108 8
+ gid 116 8
+ size 124 12
+ mtime 136 12
+ chksum 148 8
+ typeflag 156 1 see below
+ linkname 157 100 NUL-terminated if NUL fits
+ magic 257 6 must be TMAGIC (NUL term.)
+ version 263 2 must be TVERSION
+ uname 265 32 NUL-terminated
+ gname 297 32 NUL-terminated
+ devmajor 329 8
+ devminor 337 8
+ prefix 345 155 NUL-terminated if NUL fits
+
+ If the first character of prefix is '\0', the file name is name;
+ otherwise, it is prefix/name. Files whose pathnames don't fit in that
+ length can not be stored in a tar archive. */
+
+/* The bits in mode: */
+#define TSUID 04000
+#define TSGID 02000
+#define TSVTX 01000
+#define TUREAD 00400
+#define TUWRITE 00200
+#define TUEXEC 00100
+#define TGREAD 00040
+#define TGWRITE 00020
+#define TGEXEC 00010
+#define TOREAD 00004
+#define TOWRITE 00002
+#define TOEXEC 00001
+
+/* The values for typeflag:
+ Values 'A'-'Z' are reserved for custom implementations.
+ All other values are reserved for future POSIX.1 revisions. */
+
+#define REGTYPE '0' /* Regular file (preferred code). */
+#define AREGTYPE '\0' /* Regular file (alternate code). */
+#define LNKTYPE '1' /* Hard link. */
+#define SYMTYPE '2' /* Symbolic link (hard if not supported). */
+#define CHRTYPE '3' /* Character special. */
+#define BLKTYPE '4' /* Block special. */
+#define DIRTYPE '5' /* Directory. */
+#define FIFOTYPE '6' /* Named pipe. */
+#define CONTTYPE '7' /* Contiguous file */
+ /* (regular file if not supported). */
+
+/* Contents of magic field and its length. */
+#define TMAGIC "ustar"
+#define TMAGLEN 6
+
+/* Contents of the version field and its length. */
+#define TVERSION "00"
+#define TVERSLEN 2
+
+
+#endif /* tar.h */
diff --git a/contrib/cpio/tarhdr.h b/contrib/cpio/tarhdr.h
new file mode 100644
index 0000000..54de0d6
--- /dev/null
+++ b/contrib/cpio/tarhdr.h
@@ -0,0 +1,62 @@
+/* Extended tar header from POSIX.1.
+ Copyright (C) 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _TARHDR_H
+
+#define _TARHDR_H 1
+
+#include <tar.h>
+
+/* Size of `name' field. */
+#define TARNAMESIZE 100
+
+/* Size of `linkname' field. */
+#define TARLINKNAMESIZE 100
+
+/* Size of `prefix' field. */
+#define TARPREFIXSIZE 155
+
+/* Size of entire tar header. */
+#define TARRECORDSIZE 512
+
+struct tar_header
+{
+ char name[TARNAMESIZE];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char typeflag;
+ char linkname[TARLINKNAMESIZE];
+ char magic[6];
+ char version[2];
+ char uname[32];
+ char gname[32];
+ char devmajor[8];
+ char devminor[8];
+ char prefix[TARPREFIXSIZE];
+};
+
+union tar_record
+{
+ struct tar_header header;
+ char buffer[TARRECORDSIZE];
+};
+
+#endif /* tarhdr.h */
diff --git a/contrib/cpio/tcexparg.c b/contrib/cpio/tcexparg.c
new file mode 100644
index 0000000..c5d88f0
--- /dev/null
+++ b/contrib/cpio/tcexparg.c
@@ -0,0 +1,240 @@
+/* tcexparg.c - Unix-style command line wildcards for Turbo C 2.0
+
+ This file is in the public domain.
+
+ Compile your main program with -Dmain=_main and link with this file.
+
+ After that, it is just as if the operating system had expanded the
+ arguments, except that they are not sorted. The program name and all
+ arguments that are expanded from wildcards are lowercased.
+
+ Syntax for wildcards:
+ * Matches zero or more of any character (except a '.' at
+ the beginning of a name).
+ ? Matches any single character.
+ [r3z] Matches 'r', '3', or 'z'.
+ [a-d] Matches a single character in the range 'a' through 'd'.
+ [!a-d] Matches any single character except a character in the
+ range 'a' through 'd'.
+
+ The period between the filename root and its extension need not be
+ given explicitly. Thus, the pattern `a*e' will match 'abacus.exe'
+ and 'axyz.e' as well as 'apple'. Comparisons are not case sensitive.
+
+ Authors:
+ The expargs code is a modification of wildcard expansion code
+ written for Turbo C 1.0 by
+ Richard Hargrove
+ Texas Instruments, Inc.
+ P.O. Box 869305, m/s 8473
+ Plano, Texas 75086
+ 214/575-4128
+ and posted to USENET in September, 1987.
+
+ The wild_match code was written by Rich Salz, rsalz@bbn.com,
+ posted to net.sources in November, 1986.
+
+ The code connecting the two is by Mike Slomin, bellcore!lcuxa!mike2,
+ posted to comp.sys.ibm.pc in November, 1988.
+
+ Major performance enhancements and bug fixes, and source cleanup,
+ by David MacKenzie, djm@gnu.ai.mit.edu. */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dos.h>
+#include <dir.h>
+
+/* Number of new arguments to allocate space for at a time. */
+#define ARGS_INCREMENT 10
+
+/* The name this program was run with, for error messages. */
+static char *program_name;
+
+static char **grow_argv (char **new_argv, int new_argc);
+static void fatal_error (const char *message);
+
+int wild_match (char *string, char *pattern);
+char *basename (char *path);
+
+char **expargs (int *, char **);
+
+#ifdef main
+#undef main
+#endif
+
+int
+main (int argc, char **argv, char **envp)
+{
+ argv = expargs (&argc, argv);
+ return _main (argc, argv, envp);
+}
+
+char **
+expargs (int *pargc, char **argv)
+{
+ char path[MAXPATH + 1];
+ char **new_argv;
+ struct ffblk block;
+ char *path_base;
+ char *arg_base;
+ int argind;
+ int new_argc;
+ int path_length;
+ int matched;
+
+ program_name = argv[0];
+ if (program_name && *program_name)
+ strlwr (program_name);
+ new_argv = grow_argv (NULL, 0);
+ new_argv[0] = argv[0];
+ new_argc = 1;
+
+ for (argind = 1; argind < *pargc; ++argind)
+ {
+ matched = 0;
+ if (strpbrk (argv[argind], "?*[") != NULL)
+ {
+ strncpy (path, argv[argind], MAXPATH - 3);
+ path_base = basename (path);
+ strcpy (path_base, "*.*");
+ arg_base = argv[argind] + (path_base - path);
+
+ if (!findfirst (path, &block, FA_DIREC))
+ {
+ strlwr (path);
+ do
+ {
+ /* Only match "." and ".." explicitly. */
+ if (*block.ff_name == '.' && *arg_base != '.')
+ continue;
+ path_length = stpcpy (path_base, block.ff_name) - path + 1;
+ strlwr (path_base);
+ if (wild_match (path, argv[argind]))
+ {
+ matched = 1;
+ new_argv[new_argc] = (char *) malloc (path_length);
+ if (new_argv[new_argc] == NULL)
+ fatal_error ("memory exhausted");
+ strcpy (new_argv[new_argc++], path);
+ new_argv = grow_argv (new_argv, new_argc);
+ }
+ } while (!findnext (&block));
+ }
+ }
+ if (matched == 0)
+ new_argv[new_argc++] = argv[argind];
+ new_argv = grow_argv (new_argv, new_argc);
+ }
+
+ *pargc = new_argc;
+ new_argv[new_argc] = NULL;
+ return &new_argv[0];
+}
+
+/* Return a pointer to the last element of PATH. */
+
+char *
+basename (char *path)
+{
+ char *tail;
+
+ for (tail = path; *path; ++path)
+ if (*path == ':' || *path == '\\')
+ tail = path + 1;
+ return tail;
+}
+
+static char **
+grow_argv (char **new_argv, int new_argc)
+{
+ if (new_argc % ARGS_INCREMENT == 0)
+ {
+ new_argv = (char **) realloc
+ (new_argv, sizeof (char *) * (new_argc + ARGS_INCREMENT));
+ if (new_argv == NULL)
+ fatal_error ("memory exhausted");
+ }
+ return new_argv;
+}
+
+static void
+fatal_error (const char *message)
+{
+ putc ('\n', stderr);
+ if (program_name && *program_name)
+ {
+ fputs (program_name, stderr);
+ fputs (": ", stderr);
+ }
+ fputs (message, stderr);
+ putc ('\n', stderr);
+ exit (1);
+}
+
+/* Shell-style pattern matching for ?, \, [], and * characters.
+ I'm putting this replacement in the public domain.
+
+ Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. */
+
+/* The character that inverts a character class; '!' or '^'. */
+#define INVERT '!'
+
+static int star (char *string, char *pattern);
+
+/* Return nonzero if `string' matches Unix-style wildcard pattern
+ `pattern'; zero if not. */
+
+int
+wild_match (char *string, char *pattern)
+{
+ int prev; /* Previous character in character class. */
+ int matched; /* If 1, character class has been matched. */
+ int reverse; /* If 1, character class is inverted. */
+
+ for (; *pattern; string++, pattern++)
+ switch (*pattern)
+ {
+ case '\\':
+ /* Literal match with following character; fall through. */
+ pattern++;
+ default:
+ if (*string != *pattern)
+ return 0;
+ continue;
+ case '?':
+ /* Match anything. */
+ if (*string == '\0')
+ return 0;
+ continue;
+ case '*':
+ /* Trailing star matches everything. */
+ return *++pattern ? star (string, pattern) : 1;
+ case '[':
+ /* Check for inverse character class. */
+ reverse = pattern[1] == INVERT;
+ if (reverse)
+ pattern++;
+ for (prev = 256, matched = 0; *++pattern && *pattern != ']';
+ prev = *pattern)
+ if (*pattern == '-'
+ ? *string <= *++pattern && *string >= prev
+ : *string == *pattern)
+ matched = 1;
+ if (matched == reverse)
+ return 0;
+ continue;
+ }
+
+ return *string == '\0';
+}
+
+static int
+star (char *string, char *pattern)
+{
+ while (wild_match (string, pattern) == 0)
+ if (*++string == '\0')
+ return 0;
+ return 1;
+}
diff --git a/contrib/cpio/userspec.c b/contrib/cpio/userspec.c
new file mode 100644
index 0000000..67f1583
--- /dev/null
+++ b/contrib/cpio/userspec.c
@@ -0,0 +1,277 @@
+/* userspec.c -- Parse a user and group string.
+ Copyright (C) 1989, 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#ifndef index
+#define index strchr
+#endif
+#else
+#include <strings.h>
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef _POSIX_VERSION
+struct passwd *getpwnam ();
+struct group *getgrnam ();
+struct group *getgrgid ();
+#endif
+
+#ifdef _POSIX_SOURCE
+#define endpwent()
+#define endgrent()
+#endif
+
+/* Perform the equivalent of the statement `dest = strdup (src);',
+ but obtaining storage via alloca instead of from the heap. */
+
+#define V_STRDUP(dest, src) \
+ do \
+ { \
+ int _len = strlen ((src)); \
+ (dest) = (char *) alloca (_len + 1); \
+ strcpy (dest, src); \
+ } \
+ while (0)
+
+#define isdigit(c) ((c) >= '0' && (c) <= '9')
+
+char *strdup ();
+
+/* Return nonzero if STR represents an unsigned decimal integer,
+ otherwise return 0. */
+
+static int
+isnumber (str)
+ const char *str;
+{
+ for (; *str; str++)
+ if (!isdigit (*str))
+ return 0;
+ return 1;
+}
+
+/* Extract from NAME, which has the form "[user][:.][group]",
+ a USERNAME, UID U, GROUPNAME, and GID G.
+ Either user or group, or both, must be present.
+ If the group is omitted but the ":" or "." separator is given,
+ use the given user's login group.
+
+ USERNAME and GROUPNAME will be in newly malloc'd memory.
+ Either one might be NULL instead, indicating that it was not
+ given and the corresponding numeric ID was left unchanged.
+
+ Return NULL if successful, a static error message string if not. */
+
+const char *
+parse_user_spec (spec_arg, uid, gid, username_arg, groupname_arg)
+ const char *spec_arg;
+ uid_t *uid;
+ gid_t *gid;
+ char **username_arg, **groupname_arg;
+{
+ static const char *tired = "virtual memory exhausted";
+ const char *error_msg;
+ char *spec; /* A copy we can write on. */
+ struct passwd *pwd;
+ struct group *grp;
+ char *g, *u, *separator;
+ char *groupname;
+
+ error_msg = NULL;
+ *username_arg = *groupname_arg = NULL;
+ groupname = NULL;
+
+ V_STRDUP (spec, spec_arg);
+
+ /* Find the separator if there is one. */
+ separator = index (spec, ':');
+ if (separator == NULL)
+ separator = index (spec, '.');
+
+ /* Replace separator with a NUL. */
+ if (separator != NULL)
+ *separator = '\0';
+
+ /* Set U and G to non-zero length strings corresponding to user and
+ group specifiers or to NULL. */
+ u = (*spec == '\0' ? NULL : spec);
+
+ g = (separator == NULL || *(separator + 1) == '\0'
+ ? NULL
+ : separator + 1);
+
+ if (u == NULL && g == NULL)
+ return "can not omit both user and group";
+
+ if (u != NULL)
+ {
+ pwd = getpwnam (u);
+ if (pwd == NULL)
+ {
+
+ if (!isnumber (u))
+ error_msg = "invalid user";
+ else
+ {
+ int use_login_group;
+ use_login_group = (separator != NULL && g == NULL);
+ if (use_login_group)
+ error_msg = "cannot get the login group of a numeric UID";
+ else
+ *uid = atoi (u);
+ }
+ }
+ else
+ {
+ *uid = pwd->pw_uid;
+ if (g == NULL && separator != NULL)
+ {
+ /* A separator was given, but a group was not specified,
+ so get the login group. */
+ *gid = pwd->pw_gid;
+ grp = getgrgid (pwd->pw_gid);
+ if (grp == NULL)
+ {
+ /* This is enough room to hold the unsigned decimal
+ representation of any 32-bit quantity and the trailing
+ zero byte. */
+ char uint_buf[21];
+ sprintf (uint_buf, "%u", (unsigned) (pwd->pw_gid));
+ V_STRDUP (groupname, uint_buf);
+ }
+ else
+ {
+ V_STRDUP (groupname, grp->gr_name);
+ }
+ endgrent ();
+ }
+ }
+ endpwent ();
+ }
+
+ if (g != NULL && error_msg == NULL)
+ {
+ /* Explicit group. */
+ grp = getgrnam (g);
+ if (grp == NULL)
+ {
+ if (!isnumber (g))
+ error_msg = "invalid group";
+ else
+ *gid = atoi (g);
+ }
+ else
+ *gid = grp->gr_gid;
+ endgrent (); /* Save a file descriptor. */
+
+ if (error_msg == NULL)
+ V_STRDUP (groupname, g);
+ }
+
+ if (error_msg == NULL)
+ {
+ if (u != NULL)
+ {
+ *username_arg = strdup (u);
+ if (*username_arg == NULL)
+ error_msg = tired;
+ }
+
+ if (groupname != NULL && error_msg == NULL)
+ {
+ *groupname_arg = strdup (groupname);
+ if (*groupname_arg == NULL)
+ {
+ if (*username_arg != NULL)
+ {
+ free (*username_arg);
+ *username_arg = NULL;
+ }
+ error_msg = tired;
+ }
+ }
+ }
+
+ return error_msg;
+}
+
+#ifdef TEST
+
+#define NULL_CHECK(s) ((s) == NULL ? "(null)" : (s))
+
+int
+main (int argc, char **argv)
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ {
+ const char *e;
+ char *username, *groupname;
+ uid_t uid;
+ gid_t gid;
+ char *tmp;
+
+ tmp = strdup (argv[i]);
+ e = parse_user_spec (tmp, &uid, &gid, &username, &groupname);
+ free (tmp);
+ printf ("%s: %u %u %s %s %s\n",
+ argv[i],
+ (unsigned int) uid,
+ (unsigned int) gid,
+ NULL_CHECK (username),
+ NULL_CHECK (groupname),
+ NULL_CHECK (e));
+ }
+
+ exit (0);
+}
+
+#endif
diff --git a/contrib/cpio/util.c b/contrib/cpio/util.c
new file mode 100644
index 0000000..ab2d298
--- /dev/null
+++ b/contrib/cpio/util.c
@@ -0,0 +1,1343 @@
+/* util.c - Several utility routines for cpio.
+ Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef HPUX_CDF
+#include <sys/stat.h>
+#endif
+#include "system.h"
+#include "cpiohdr.h"
+#include "dstring.h"
+#include "extern.h"
+#include "rmt.h"
+
+#ifndef __MSDOS__
+#include <sys/ioctl.h>
+#else
+#include <io.h>
+#endif
+
+#ifdef HAVE_SYS_MTIO_H
+#ifdef HAVE_SYS_IO_TRIOCTL_H
+#include <sys/io/trioctl.h>
+#endif
+#include <sys/mtio.h>
+#endif
+
+static void tape_fill_input_buffer P_((int in_des, int num_bytes));
+static int disk_fill_input_buffer P_((int in_des, int num_bytes));
+static void hash_insert ();
+static void write_nuls_to_file P_((long num_bytes, int out_des));
+
+/* Write `output_size' bytes of `output_buffer' to file
+ descriptor OUT_DES and reset `output_size' and `out_buff'. */
+
+void
+tape_empty_output_buffer (out_des)
+ int out_des;
+{
+ int bytes_written;
+
+#ifdef BROKEN_LONG_TAPE_DRIVER
+ static long output_bytes_before_lseek = 0;
+
+ /* Some tape drivers seem to have a signed internal seek pointer and
+ they lose if it overflows and becomes negative (e.g. when writing
+ tapes > 2Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
+ seek pointer and prevent it from overflowing. */
+ if (output_is_special
+ && ( (output_bytes_before_lseek += output_size) >= 1073741824L) )
+ {
+ lseek(out_des, 0L, SEEK_SET);
+ output_bytes_before_lseek = 0;
+ }
+#endif
+
+ bytes_written = rmtwrite (out_des, output_buffer, output_size);
+ if (bytes_written != output_size)
+ {
+ int rest_bytes_written;
+ int rest_output_size;
+
+ if (output_is_special
+ && (bytes_written >= 0
+ || (bytes_written < 0
+ && (errno == ENOSPC || errno == EIO || errno == ENXIO))))
+ {
+ get_next_reel (out_des);
+ if (bytes_written > 0)
+ rest_output_size = output_size - bytes_written;
+ else
+ rest_output_size = output_size;
+ rest_bytes_written = rmtwrite (out_des, output_buffer,
+ rest_output_size);
+ if (rest_bytes_written != rest_output_size)
+ error (1, errno, "write error");
+ }
+ else
+ error (1, errno, "write error");
+ }
+ output_bytes += output_size;
+ out_buff = output_buffer;
+ output_size = 0;
+}
+
+/* Write `output_size' bytes of `output_buffer' to file
+ descriptor OUT_DES and reset `output_size' and `out_buff'.
+ If `swapping_halfwords' or `swapping_bytes' is set,
+ do the appropriate swapping first. Our callers have
+ to make sure to only set these flags if `output_size'
+ is appropriate (a multiple of 4 for `swapping_halfwords',
+ 2 for `swapping_bytes'). The fact that DISK_IO_BLOCK_SIZE
+ must always be a multiple of 4 helps us (and our callers)
+ insure this. */
+
+void
+disk_empty_output_buffer (out_des)
+ int out_des;
+{
+ int bytes_written;
+
+ if (swapping_halfwords || swapping_bytes)
+ {
+ if (swapping_halfwords)
+ {
+ int complete_words;
+ complete_words = output_size / 4;
+ swahw_array (output_buffer, complete_words);
+ if (swapping_bytes)
+ swab_array (output_buffer, 2 * complete_words);
+ }
+ else
+ {
+ int complete_halfwords;
+ complete_halfwords = output_size /2;
+ swab_array (output_buffer, complete_halfwords);
+ }
+ }
+
+ if (sparse_flag)
+ bytes_written = sparse_write (out_des, output_buffer, output_size);
+ else
+ bytes_written = write (out_des, output_buffer, output_size);
+
+ if (bytes_written != output_size)
+ {
+ error (1, errno, "write error");
+ }
+ output_bytes += output_size;
+ out_buff = output_buffer;
+ output_size = 0;
+}
+
+/* Exchange the halfwords of each element of the array of COUNT longs
+ starting at PTR. PTR does not have to be aligned at a word
+ boundary. */
+
+void
+swahw_array (ptr, count)
+ char *ptr;
+ int count;
+{
+ char tmp;
+
+ for (; count > 0; --count)
+ {
+ tmp = *ptr;
+ *ptr = *(ptr + 2);
+ *(ptr + 2) = tmp;
+ ++ptr;
+ tmp = *ptr;
+ *ptr = *(ptr + 2);
+ *(ptr + 2) = tmp;
+ ptr += 3;
+ }
+}
+
+/* Read at most NUM_BYTES or `io_block_size' bytes, whichever is smaller,
+ into the start of `input_buffer' from file descriptor IN_DES.
+ Set `input_size' to the number of bytes read and reset `in_buff'.
+ Exit with an error if end of file is reached. */
+
+#ifdef BROKEN_LONG_TAPE_DRIVER
+static long input_bytes_before_lseek = 0;
+#endif
+
+static void
+tape_fill_input_buffer (in_des, num_bytes)
+ int in_des;
+ int num_bytes;
+{
+#ifdef BROKEN_LONG_TAPE_DRIVER
+ /* Some tape drivers seem to have a signed internal seek pointer and
+ they lose if it overflows and becomes negative (e.g. when writing
+ tapes > 4Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
+ seek pointer and prevent it from overflowing. */
+ if (input_is_special
+ && ( (input_bytes_before_lseek += num_bytes) >= 1073741824L) )
+ {
+ lseek(in_des, 0L, SEEK_SET);
+ input_bytes_before_lseek = 0;
+ }
+#endif
+ in_buff = input_buffer;
+ num_bytes = (num_bytes < io_block_size) ? num_bytes : io_block_size;
+ input_size = rmtread (in_des, input_buffer, num_bytes);
+ if (input_size == 0 && input_is_special)
+ {
+ get_next_reel (in_des);
+ input_size = rmtread (in_des, input_buffer, num_bytes);
+ }
+ if (input_size < 0)
+ error (1, errno, "read error");
+ if (input_size == 0)
+ {
+ error (0, 0, "premature end of file");
+ exit (1);
+ }
+ input_bytes += input_size;
+}
+
+/* Read at most NUM_BYTES or `DISK_IO_BLOCK_SIZE' bytes, whichever is smaller,
+ into the start of `input_buffer' from file descriptor IN_DES.
+ Set `input_size' to the number of bytes read and reset `in_buff'.
+ Exit with an error if end of file is reached. */
+
+static int
+disk_fill_input_buffer (in_des, num_bytes)
+ int in_des;
+ int num_bytes;
+{
+ in_buff = input_buffer;
+ num_bytes = (num_bytes < DISK_IO_BLOCK_SIZE) ? num_bytes : DISK_IO_BLOCK_SIZE;
+ input_size = read (in_des, input_buffer, num_bytes);
+ if (input_size < 0)
+ {
+ input_size = 0;
+ return (-1);
+ }
+ else if (input_size == 0)
+ return (1);
+ input_bytes += input_size;
+ return (0);
+}
+
+/* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full.
+ When `out_buff' fills up, flush it to file descriptor OUT_DES. */
+
+void
+tape_buffered_write (in_buf, out_des, num_bytes)
+ char *in_buf;
+ int out_des;
+ long num_bytes;
+{
+ register long bytes_left = num_bytes; /* Bytes needing to be copied. */
+ register long space_left; /* Room left in output buffer. */
+
+ while (bytes_left > 0)
+ {
+ space_left = io_block_size - output_size;
+ if (space_left == 0)
+ tape_empty_output_buffer (out_des);
+ else
+ {
+ if (bytes_left < space_left)
+ space_left = bytes_left;
+ bcopy (in_buf, out_buff, (unsigned) space_left);
+ out_buff += space_left;
+ output_size += space_left;
+ in_buf += space_left;
+ bytes_left -= space_left;
+ }
+ }
+}
+
+/* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full.
+ When `out_buff' fills up, flush it to file descriptor OUT_DES. */
+
+void
+disk_buffered_write (in_buf, out_des, num_bytes)
+ char *in_buf;
+ int out_des;
+ long num_bytes;
+{
+ register long bytes_left = num_bytes; /* Bytes needing to be copied. */
+ register long space_left; /* Room left in output buffer. */
+
+ while (bytes_left > 0)
+ {
+ space_left = DISK_IO_BLOCK_SIZE - output_size;
+ if (space_left == 0)
+ disk_empty_output_buffer (out_des);
+ else
+ {
+ if (bytes_left < space_left)
+ space_left = bytes_left;
+ bcopy (in_buf, out_buff, (unsigned) space_left);
+ out_buff += space_left;
+ output_size += space_left;
+ in_buf += space_left;
+ bytes_left -= space_left;
+ }
+ }
+}
+
+/* Copy NUM_BYTES of buffer `in_buff' into IN_BUF.
+ `in_buff' may be partly full.
+ When `in_buff' is exhausted, refill it from file descriptor IN_DES. */
+
+void
+tape_buffered_read (in_buf, in_des, num_bytes)
+ char *in_buf;
+ int in_des;
+ long num_bytes;
+{
+ register long bytes_left = num_bytes; /* Bytes needing to be copied. */
+ register long space_left; /* Bytes to copy from input buffer. */
+
+ while (bytes_left > 0)
+ {
+ if (input_size == 0)
+ tape_fill_input_buffer (in_des, io_block_size);
+ if (bytes_left < input_size)
+ space_left = bytes_left;
+ else
+ space_left = input_size;
+ bcopy (in_buff, in_buf, (unsigned) space_left);
+ in_buff += space_left;
+ in_buf += space_left;
+ input_size -= space_left;
+ bytes_left -= space_left;
+ }
+}
+
+/* Copy the the next NUM_BYTES bytes of `input_buffer' into PEEK_BUF.
+ If NUM_BYTES bytes are not available, read the next `io_block_size' bytes
+ into the end of `input_buffer' and update `input_size'.
+
+ Return the number of bytes copied into PEEK_BUF.
+ If the number of bytes returned is less than NUM_BYTES,
+ then EOF has been reached. */
+
+int
+tape_buffered_peek (peek_buf, in_des, num_bytes)
+ char *peek_buf;
+ int in_des;
+ int num_bytes;
+{
+ long tmp_input_size;
+ long got_bytes;
+ char *append_buf;
+
+#ifdef BROKEN_LONG_TAPE_DRIVER
+ /* Some tape drivers seem to have a signed internal seek pointer and
+ they lose if it overflows and becomes negative (e.g. when writing
+ tapes > 4Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
+ seek pointer and prevent it from overflowing. */
+ if (input_is_special
+ && ( (input_bytes_before_lseek += num_bytes) >= 1073741824L) )
+ {
+ lseek(in_des, 0L, SEEK_SET);
+ input_bytes_before_lseek = 0;
+ }
+#endif
+
+ while (input_size < num_bytes)
+ {
+ append_buf = in_buff + input_size;
+ if ( (append_buf - input_buffer) >= input_buffer_size)
+ {
+ /* We can keep up to 2 "blocks" (either the physical block size
+ or 512 bytes(the size of a tar record), which ever is
+ larger) in the input buffer when we are peeking. We
+ assume that our caller will never be interested in peeking
+ ahead at more than 512 bytes, so we know that by the time
+ we need a 3rd "block" in the buffer we can throw away the
+ first block to make room. */
+ int half;
+ half = input_buffer_size / 2;
+ bcopy (input_buffer + half, input_buffer, half);
+ in_buff = in_buff - half;
+ append_buf = append_buf - half;
+ }
+ tmp_input_size = rmtread (in_des, append_buf, io_block_size);
+ if (tmp_input_size == 0)
+ {
+ if (input_is_special)
+ {
+ get_next_reel (in_des);
+ tmp_input_size = rmtread (in_des, append_buf, io_block_size);
+ }
+ else
+ break;
+ }
+ if (tmp_input_size < 0)
+ error (1, errno, "read error");
+ input_bytes += tmp_input_size;
+ input_size += tmp_input_size;
+ }
+ if (num_bytes <= input_size)
+ got_bytes = num_bytes;
+ else
+ got_bytes = input_size;
+ bcopy (in_buff, peek_buf, (unsigned) got_bytes);
+ return got_bytes;
+}
+
+/* Skip the next NUM_BYTES bytes of file descriptor IN_DES. */
+
+void
+tape_toss_input (in_des, num_bytes)
+ int in_des;
+ long num_bytes;
+{
+ register long bytes_left = num_bytes; /* Bytes needing to be copied. */
+ register long space_left; /* Bytes to copy from input buffer. */
+
+ while (bytes_left > 0)
+ {
+ if (input_size == 0)
+ tape_fill_input_buffer (in_des, io_block_size);
+ if (bytes_left < input_size)
+ space_left = bytes_left;
+ else
+ space_left = input_size;
+
+ if (crc_i_flag && only_verify_crc_flag)
+ {
+ int k;
+ for (k = 0; k < space_left; ++k)
+ crc += in_buff[k] & 0xff;
+ }
+
+ in_buff += space_left;
+ input_size -= space_left;
+ bytes_left -= space_left;
+ }
+}
+
+/* Copy a file using the input and output buffers, which may start out
+ partly full. After the copy, the files are not closed nor the last
+ block flushed to output, and the input buffer may still be partly
+ full. If `crc_i_flag' is set, add each byte to `crc'.
+ IN_DES is the file descriptor for input;
+ OUT_DES is the file descriptor for output;
+ NUM_BYTES is the number of bytes to copy. */
+
+void
+copy_files_tape_to_disk (in_des, out_des, num_bytes)
+ int in_des;
+ int out_des;
+ long num_bytes;
+{
+ long size;
+ long k;
+
+ while (num_bytes > 0)
+ {
+ if (input_size == 0)
+ tape_fill_input_buffer (in_des, io_block_size);
+ size = (input_size < num_bytes) ? input_size : num_bytes;
+ if (crc_i_flag)
+ {
+ for (k = 0; k < size; ++k)
+ crc += in_buff[k] & 0xff;
+ }
+ disk_buffered_write (in_buff, out_des, size);
+ num_bytes -= size;
+ input_size -= size;
+ in_buff += size;
+ }
+}
+/* Copy a file using the input and output buffers, which may start out
+ partly full. After the copy, the files are not closed nor the last
+ block flushed to output, and the input buffer may still be partly
+ full. If `crc_i_flag' is set, add each byte to `crc'.
+ IN_DES is the file descriptor for input;
+ OUT_DES is the file descriptor for output;
+ NUM_BYTES is the number of bytes to copy. */
+
+void
+copy_files_disk_to_tape (in_des, out_des, num_bytes, filename)
+ int in_des;
+ int out_des;
+ long num_bytes;
+ char *filename;
+{
+ long size;
+ long k;
+ int rc;
+ long original_num_bytes;
+
+ original_num_bytes = num_bytes;
+
+ while (num_bytes > 0)
+ {
+ if (input_size == 0)
+ if (rc = disk_fill_input_buffer (in_des, DISK_IO_BLOCK_SIZE))
+ {
+ if (rc > 0)
+ error (0, 0, "File %s shrunk by %ld bytes, padding with zeros",
+ filename, num_bytes);
+ else
+ error (0, 0, "Read error at byte %ld in file %s, padding with zeros",
+ original_num_bytes - num_bytes, filename);
+ write_nuls_to_file (num_bytes, out_des);
+ break;
+ }
+ size = (input_size < num_bytes) ? input_size : num_bytes;
+ if (crc_i_flag)
+ {
+ for (k = 0; k < size; ++k)
+ crc += in_buff[k] & 0xff;
+ }
+ tape_buffered_write (in_buff, out_des, size);
+ num_bytes -= size;
+ input_size -= size;
+ in_buff += size;
+ }
+}
+/* Copy a file using the input and output buffers, which may start out
+ partly full. After the copy, the files are not closed nor the last
+ block flushed to output, and the input buffer may still be partly
+ full. If `crc_i_flag' is set, add each byte to `crc'.
+ IN_DES is the file descriptor for input;
+ OUT_DES is the file descriptor for output;
+ NUM_BYTES is the number of bytes to copy. */
+
+void
+copy_files_disk_to_disk (in_des, out_des, num_bytes, filename)
+ int in_des;
+ int out_des;
+ long num_bytes;
+ char *filename;
+{
+ long size;
+ long k;
+ long original_num_bytes;
+ int rc;
+
+ original_num_bytes = num_bytes;
+ while (num_bytes > 0)
+ {
+ if (input_size == 0)
+ if (rc = disk_fill_input_buffer (in_des, DISK_IO_BLOCK_SIZE))
+ {
+ if (rc > 0)
+ error (0, 0, "File %s shrunk by %ld bytes, padding with zeros",
+ filename, num_bytes);
+ else
+ error (0, 0, "Read error at byte %ld in file %s, padding with zeros",
+ original_num_bytes - num_bytes, filename);
+ write_nuls_to_file (num_bytes, out_des);
+ break;
+ }
+ size = (input_size < num_bytes) ? input_size : num_bytes;
+ if (crc_i_flag)
+ {
+ for (k = 0; k < size; ++k)
+ crc += in_buff[k] & 0xff;
+ }
+ disk_buffered_write (in_buff, out_des, size);
+ num_bytes -= size;
+ input_size -= size;
+ in_buff += size;
+ }
+}
+
+/* Create all directories up to but not including the last part of NAME.
+ Do not destroy any nondirectories while creating directories. */
+
+void
+create_all_directories (name)
+ char *name;
+{
+ char *dir;
+ int mode;
+#ifdef HPUX_CDF
+ int cdf;
+#endif
+
+ dir = dirname (name);
+ mode = 0700;
+#ifdef HPUX_CDF
+ cdf = islastparentcdf (name);
+ if (cdf)
+ {
+ dir [strlen (dir) - 1] = '\0'; /* remove final + */
+ mode = 04700;
+ }
+
+#endif
+
+ if (dir == NULL)
+ error (2, 0, "virtual memory exhausted");
+
+ if (dir[0] != '.' || dir[1] != '\0')
+ make_path (dir, mode, 0700, -1, -1, (char *) NULL);
+
+ free (dir);
+}
+
+/* Prepare to append to an archive. We have been in
+ process_copy_in, keeping track of the position where
+ the last header started in `last_header_start'. Now we
+ have the starting position of the last header (the TRAILER!!!
+ header, or blank record for tar archives) and we want to start
+ writing (appending) over the last header. The last header may
+ be in the middle of a block, so to keep the buffering in sync
+ we lseek back to the start of the block, read everything up
+ to but not including the last header, lseek back to the start
+ of the block, and then do a copy_buf_out of what we read.
+ Actually, we probably don't have to worry so much about keeping the
+ buffering perfect since you can only append to archives that
+ are disk files. */
+
+void
+prepare_append (out_file_des)
+ int out_file_des;
+{
+ int start_of_header;
+ int start_of_block;
+ int useful_bytes_in_block;
+ char *tmp_buf;
+
+ start_of_header = last_header_start;
+ /* Figure out how many bytes we will rewrite, and where they start. */
+ useful_bytes_in_block = start_of_header % io_block_size;
+ start_of_block = start_of_header - useful_bytes_in_block;
+
+ if (lseek (out_file_des, start_of_block, SEEK_SET) < 0)
+ error (1, errno, "cannot seek on output");
+ if (useful_bytes_in_block > 0)
+ {
+ tmp_buf = (char *) xmalloc (useful_bytes_in_block);
+ read (out_file_des, tmp_buf, useful_bytes_in_block);
+ if (lseek (out_file_des, start_of_block, SEEK_SET) < 0)
+ error (1, errno, "cannot seek on output");
+ /* fix juo -- is this copy_tape_buf_out? or copy_disk? */
+ tape_buffered_write (tmp_buf, out_file_des, useful_bytes_in_block);
+ free (tmp_buf);
+ }
+
+ /* We are done reading the archive, so clear these since they
+ will now be used for reading in files that we are appending
+ to the archive. */
+ input_size = 0;
+ input_bytes = 0;
+ in_buff = input_buffer;
+}
+
+/* Support for remembering inodes with multiple links. Used in the
+ "copy in" and "copy pass" modes for making links instead of copying
+ the file. */
+
+struct inode_val
+{
+ unsigned long inode;
+ unsigned long major_num;
+ unsigned long minor_num;
+ char *file_name;
+};
+
+/* Inode hash table. Allocated by first call to add_inode. */
+static struct inode_val **hash_table = NULL;
+
+/* Size of current hash table. Initial size is 47. (47 = 2*22 + 3) */
+static int hash_size = 22;
+
+/* Number of elements in current hash table. */
+static int hash_num;
+
+/* Find the file name associated with NODE_NUM. If there is no file
+ associated with NODE_NUM, return NULL. */
+
+char *
+find_inode_file (node_num, major_num, minor_num)
+ unsigned long node_num;
+ unsigned long major_num;
+ unsigned long minor_num;
+{
+#ifndef __MSDOS__
+ int start; /* Initial hash location. */
+ int temp; /* Rehash search variable. */
+
+ if (hash_table != NULL)
+ {
+ /* Hash function is node number modulo the table size. */
+ start = node_num % hash_size;
+
+ /* Initial look into the table. */
+ if (hash_table[start] == NULL)
+ return NULL;
+ if (hash_table[start]->inode == node_num
+ && hash_table[start]->major_num == major_num
+ && hash_table[start]->minor_num == minor_num)
+ return hash_table[start]->file_name;
+
+ /* The home position is full with a different inode record.
+ Do a linear search terminated by a NULL pointer. */
+ for (temp = (start + 1) % hash_size;
+ hash_table[temp] != NULL && temp != start;
+ temp = (temp + 1) % hash_size)
+ {
+ if (hash_table[temp]->inode == node_num
+ && hash_table[start]->major_num == major_num
+ && hash_table[start]->minor_num == minor_num)
+ return hash_table[temp]->file_name;
+ }
+ }
+#endif
+ return NULL;
+}
+
+/* Associate FILE_NAME with the inode NODE_NUM. (Insert into hash table.) */
+
+void
+add_inode (node_num, file_name, major_num, minor_num)
+ unsigned long node_num;
+ char *file_name;
+ unsigned long major_num;
+ unsigned long minor_num;
+{
+#ifndef __MSDOS__
+ struct inode_val *temp;
+
+ /* Create new inode record. */
+ temp = (struct inode_val *) xmalloc (sizeof (struct inode_val));
+ temp->inode = node_num;
+ temp->major_num = major_num;
+ temp->minor_num = minor_num;
+ temp->file_name = xstrdup (file_name);
+
+ /* Do we have to increase the size of (or initially allocate)
+ the hash table? */
+ if (hash_num == hash_size || hash_table == NULL)
+ {
+ struct inode_val **old_table; /* Pointer to old table. */
+ int i; /* Index for re-insert loop. */
+
+ /* Save old table. */
+ old_table = hash_table;
+ if (old_table == NULL)
+ hash_num = 0;
+
+ /* Calculate new size of table and allocate it.
+ Sequence of table sizes is 47, 97, 197, 397, 797, 1597, 3197, 6397 ...
+ where 3197 and most of the sizes after 6397 are not prime. The other
+ numbers listed are prime. */
+ hash_size = 2 * hash_size + 3;
+ hash_table = (struct inode_val **)
+ xmalloc (hash_size * sizeof (struct inode_val *));
+ bzero (hash_table, hash_size * sizeof (struct inode_val *));
+
+ /* Insert the values from the old table into the new table. */
+ for (i = 0; i < hash_num; i++)
+ hash_insert (old_table[i]);
+
+ if (old_table != NULL)
+ free (old_table);
+ }
+
+ /* Insert the new record and increment the count of elements in the
+ hash table. */
+ hash_insert (temp);
+ hash_num++;
+#endif /* __MSDOS__ */
+}
+
+/* Do the hash insert. Used in normal inserts and resizing the hash
+ table. It is guaranteed that there is room to insert the item.
+ NEW_VALUE is the pointer to the previously allocated inode, file
+ name association record. */
+
+static void
+hash_insert (new_value)
+ struct inode_val *new_value;
+{
+ int start; /* Home position for the value. */
+ int temp; /* Used for rehashing. */
+
+ /* Hash function is node number modulo the table size. */
+ start = new_value->inode % hash_size;
+
+ /* Do the initial look into the table. */
+ if (hash_table[start] == NULL)
+ {
+ hash_table[start] = new_value;
+ return;
+ }
+
+ /* If we get to here, the home position is full with a different inode
+ record. Do a linear search for the first NULL pointer and insert
+ the new item there. */
+ temp = (start + 1) % hash_size;
+ while (hash_table[temp] != NULL)
+ temp = (temp + 1) % hash_size;
+
+ /* Insert at the NULL. */
+ hash_table[temp] = new_value;
+}
+
+/* Open FILE in the mode specified by the command line options
+ and return an open file descriptor for it,
+ or -1 if it can't be opened. */
+
+int
+open_archive (file)
+ char *file;
+{
+ int fd;
+ void (*copy_in) (); /* Workaround for pcc bug. */
+
+ copy_in = process_copy_in;
+
+ if (copy_function == copy_in)
+ fd = rmtopen (file, O_RDONLY | O_BINARY, 0666);
+ else
+ {
+ if (!append_flag)
+ fd = rmtopen (file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+ else
+ fd = rmtopen (file, O_RDWR | O_BINARY, 0666);
+ }
+
+ return fd;
+}
+
+/* Attempt to rewind the tape drive on file descriptor TAPE_DES
+ and take it offline. */
+
+void
+tape_offline (tape_des)
+ int tape_des;
+{
+#if defined(MTIOCTOP) && defined(MTOFFL)
+ struct mtop control;
+
+ control.mt_op = MTOFFL;
+ control.mt_count = 1;
+ rmtioctl (tape_des, MTIOCTOP, &control); /* Don't care if it fails. */
+#endif
+}
+
+/* The file on file descriptor TAPE_DES is assumed to be magnetic tape
+ (or floppy disk or other device) and the end of the medium
+ has been reached. Ask the user for to mount a new "tape" to continue
+ the processing. If the user specified the device name on the
+ command line (with the -I, -O, -F or --file options), then we can
+ automatically re-open the same device to use the next medium. If the
+ user did not specify the device name, then we have to ask them which
+ device to use. */
+
+void
+get_next_reel (tape_des)
+ int tape_des;
+{
+ static int reel_number = 1;
+ FILE *tty_in; /* File for interacting with user. */
+ FILE *tty_out; /* File for interacting with user. */
+ int old_tape_des;
+ char *next_archive_name;
+ dynamic_string new_name;
+ char *str_res;
+
+ ds_init (&new_name, 128);
+
+ /* Open files for interactive communication. */
+ tty_in = fopen (CONSOLE, "r");
+ if (tty_in == NULL)
+ error (2, errno, CONSOLE);
+ tty_out = fopen (CONSOLE, "w");
+ if (tty_out == NULL)
+ error (2, errno, CONSOLE);
+
+ old_tape_des = tape_des;
+ tape_offline (tape_des);
+ rmtclose (tape_des);
+
+ /* Give message and wait for carrage return. User should hit carrage return
+ only after loading the next tape. */
+ ++reel_number;
+ if (new_media_message)
+ fprintf (tty_out, "%s", new_media_message);
+ else if (new_media_message_with_number)
+ fprintf (tty_out, "%s%d%s", new_media_message_with_number, reel_number,
+ new_media_message_after_number);
+ else if (archive_name)
+ fprintf (tty_out, "Found end of tape. Load next tape and press RETURN. ");
+ else
+ fprintf (tty_out, "Found end of tape. To continue, type device/file name when ready.\n");
+
+ fflush (tty_out);
+
+ if (archive_name)
+ {
+ int c;
+
+ do
+ c = getc (tty_in);
+ while (c != EOF && c != '\n');
+
+ tape_des = open_archive (archive_name);
+ if (tape_des == -1)
+ error (1, errno, "%s", archive_name);
+ }
+ else
+ {
+ do
+ {
+ if (tape_des < 0)
+ {
+ fprintf (tty_out,
+ "To continue, type device/file name when ready.\n");
+ fflush (tty_out);
+ }
+
+ str_res = ds_fgets (tty_in, &new_name);
+ if (str_res == NULL || str_res[0] == '\0')
+ exit (1);
+ next_archive_name = str_res;
+
+ tape_des = open_archive (next_archive_name);
+ if (tape_des == -1)
+ error (0, errno, "%s", next_archive_name);
+ }
+ while (tape_des < 0);
+ }
+
+ /* We have to make sure that `tape_des' has not changed its value even
+ though we closed it and reopened it, since there are local
+ copies of it in other routines. This works fine on Unix (even with
+ rmtread and rmtwrite) since open will always return the lowest
+ available file descriptor and we haven't closed any files (e.g.,
+ stdin, stdout or stderr) that were opened before we originally opened
+ the archive. */
+
+ if (tape_des != old_tape_des)
+ error (1, 0, "internal error: tape descriptor changed from %d to %d",
+ old_tape_des, tape_des);
+
+ free (new_name.ds_string);
+ fclose (tty_in);
+ fclose (tty_out);
+}
+
+/* If MESSAGE does not contain the string "%d", make `new_media_message'
+ a copy of MESSAGE. If MESSAGES does contain the string "%d", make
+ `new_media_message_with_number' a copy of MESSAGE up to, but
+ not including, the string "%d", and make `new_media_message_after_number'
+ a copy of MESSAGE after the string "%d". */
+
+void
+set_new_media_message (message)
+ char *message;
+{
+ char *p;
+ int prev_was_percent;
+
+ p = message;
+ prev_was_percent = 0;
+ while (*p != '\0')
+ {
+ if (*p == 'd' && prev_was_percent)
+ break;
+ prev_was_percent = (*p == '%');
+ ++p;
+ }
+ if (*p == '\0')
+ {
+ new_media_message = xstrdup (message);
+ }
+ else
+ {
+ int length = p - message - 1;
+
+ new_media_message_with_number = xmalloc (length + 1);
+ strncpy (new_media_message_with_number, message, length);
+ new_media_message_with_number[length] = '\0';
+ length = strlen (p + 1);
+ new_media_message_after_number = xmalloc (length + 1);
+ strcpy (new_media_message_after_number, p + 1);
+ }
+}
+
+#ifdef SYMLINK_USES_UMASK
+/* Most machines always create symlinks with rwxrwxrwx protection,
+ but some (HP/UX 8.07; maybe DEC's OSF on MIPS, too?) use the
+ umask when creating symlinks, so if your umask is 022 you end
+ up with rwxr-xr-x symlinks (although HP/UX seems to completely
+ ignore the protection). There doesn't seem to be any way to
+ manipulate the modes once the symlinks are created (e.g.
+ a hypothetical "lchmod"), so to create them with the right
+ modes we have to set the umask first. */
+
+int
+umasked_symlink (name1, name2, mode)
+ char *name1;
+ char *name2;
+ int mode;
+{
+ int old_umask;
+ int rc;
+ mode = ~(mode & 0777) & 0777;
+ old_umask = umask (mode);
+ rc = symlink (name1, name2);
+ umask (old_umask);
+ return rc;
+}
+#endif /* SYMLINK_USES_UMASK */
+
+#if defined(__MSDOS__) && !defined(__GNUC__)
+int
+chown (path, owner, group)
+ char *path;
+ int owner, group;
+{
+ return 0;
+}
+#endif
+
+#ifdef __TURBOC__
+#include <time.h>
+#include <fcntl.h>
+#include <io.h>
+
+int
+utime (char *filename, struct utimbuf *utb)
+{
+ extern int errno;
+ struct tm *tm;
+ struct ftime filetime;
+ time_t when;
+ int fd;
+ int status;
+
+ if (utb == 0)
+ when = time (0);
+ else
+ when = utb->modtime;
+
+ fd = _open (filename, O_RDWR);
+ if (fd == -1)
+ return -1;
+
+ tm = localtime (&when);
+ if (tm->tm_year < 80)
+ filetime.ft_year = 0;
+ else
+ filetime.ft_year = tm->tm_year - 80;
+ filetime.ft_month = tm->tm_mon + 1;
+ filetime.ft_day = tm->tm_mday;
+ if (tm->tm_hour < 0)
+ filetime.ft_hour = 0;
+ else
+ filetime.ft_hour = tm->tm_hour;
+ filetime.ft_min = tm->tm_min;
+ filetime.ft_tsec = tm->tm_sec / 2;
+
+ status = setftime (fd, &filetime);
+ _close (fd);
+ return status;
+}
+#endif
+#ifdef HPUX_CDF
+/* When we create a cpio archive we mark CDF's by putting an extra `/'
+ after their component name so we can distinguish the CDF's when we
+ extract the archive (in case the "hidden" directory's files appear
+ in the archive before the directory itself). E.g., in the path
+ "a/b+/c", if b+ is a CDF, we will write this path as "a/b+//c" in
+ the archive so when we extract the archive we will know that b+
+ is actually a CDF, and not an ordinary directory whose name happens
+ to end in `+'. We also do the same thing internally in copypass.c. */
+
+
+/* Take an input pathname and check it for CDF's. Insert an extra
+ `/' in the pathname after each "hidden" directory. If we add
+ any `/'s, return a malloced string (which it will reuse for
+ later calls so our caller doesn't have to worry about freeing
+ the string) instead of the original input string. */
+
+char *
+add_cdf_double_slashes (input_name)
+ char *input_name;
+{
+ static char *ret_name = NULL; /* re-usuable return buffer (malloc'ed) */
+ static int ret_size = -1; /* size of return buffer. */
+ char *p;
+ char *q;
+ int n;
+ struct stat dir_stat;
+
+ /* Search for a `/' preceeded by a `+'. */
+
+ for (p = input_name; *p != '\0'; ++p)
+ {
+ if ( (*p == '+') && (*(p + 1) == '/') )
+ break;
+ }
+
+ /* If we didn't find a `/' preceeded by a `+' then there are
+ no CDF's in this pathname. Return the original pathname. */
+
+ if (*p == '\0')
+ return input_name;
+
+ /* There was a `/' preceeded by a `+' in the pathname. If it is a CDF
+ then we will need to copy the input pathname to our return
+ buffer so we can insert the extra `/'s. Since we can't tell
+ yet whether or not it is a CDF we will just always copy the
+ string to the return buffer. First we have to make sure the
+ buffer is large enough to hold the string and any number of
+ extra `/'s we might add. */
+
+ n = 2 * (strlen (input_name) + 1);
+ if (n >= ret_size)
+ {
+ if (ret_size < 0)
+ ret_name = (char *) malloc (n);
+ else
+ ret_name = (char *)realloc (ret_name, n);
+ ret_size = n;
+ }
+
+ /* Clear the `/' after this component, so we can stat the pathname
+ up to and including this component. */
+ ++p;
+ *p = '\0';
+ if ((*xstat) (input_name, &dir_stat) < 0)
+ {
+ error (0, errno, "%s", input_name);
+ return input_name;
+ }
+
+ /* Now put back the `/' after this component and copy the pathname up to
+ and including this component and its trailing `/' to the return
+ buffer. */
+ *p++ = '/';
+ strncpy (ret_name, input_name, p - input_name);
+ q = ret_name + (p - input_name);
+
+ /* If it was a CDF, add another `/'. */
+ if (S_ISDIR (dir_stat.st_mode) && (dir_stat.st_mode & 04000) )
+ *q++ = '/';
+
+ /* Go through the rest of the input pathname, copying it to the
+ return buffer, and adding an extra `/' after each CDF. */
+ while (*p != '\0')
+ {
+ if ( (*p == '+') && (*(p + 1) == '/') )
+ {
+ *q++ = *p++;
+
+ *p = '\0';
+ if ((*xstat) (input_name, &dir_stat) < 0)
+ {
+ error (0, errno, "%s", input_name);
+ return input_name;
+ }
+ *p = '/';
+
+ if (S_ISDIR (dir_stat.st_mode) && (dir_stat.st_mode & 04000) )
+ *q++ = '/';
+ }
+ *q++ = *p++;
+ }
+ *q = '\0';
+
+ return ret_name;
+}
+
+/* Is the last parent directory (e.g., c in a/b/c/d) a CDF? If the
+ directory name ends in `+' and is followed by 2 `/'s instead of 1
+ then it is. This is only the case for cpio archives, but we don't
+ have to worry about tar because tar always has the directory before
+ its files (or else we lose). */
+
+islastparentcdf(path)
+ char *path;
+{
+ char *newpath;
+ char *slash;
+ int slash_count;
+ int length; /* Length of result, not including NUL. */
+
+ slash = rindex (path, '/');
+ if (slash == 0)
+ return 0;
+ else
+ {
+ slash_count = 0;
+ while (slash > path && *slash == '/')
+ {
+ ++slash_count;
+ --slash;
+ }
+
+
+ if ( (*slash == '+') && (slash_count >= 2) )
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+#define DISKBLOCKSIZE (512)
+
+enum sparse_write_states { begin, in_zeros, not_in_zeros };
+
+
+static int
+buf_all_zeros (buf, bufsize)
+ char *buf;
+ int bufsize;
+{
+ int i;
+ for (i = 0; i < bufsize; ++i)
+ {
+ if (*buf++ != '\0')
+ return 0;
+ }
+ return 1;
+}
+
+int delayed_seek_count = 0;
+
+/* Write NBYTE bytes from BUF to remote tape connection FILDES.
+ Return the number of bytes written on success, -1 on error. */
+
+int
+sparse_write (fildes, buf, nbyte)
+ int fildes;
+ char *buf;
+ unsigned int nbyte;
+{
+ int complete_block_count;
+ int leftover_bytes_count;
+ int seek_count;
+ int write_count;
+ char *cur_write_start;
+ int lseek_rc;
+ int write_rc;
+ int i;
+ enum sparse_write_states state;
+
+ complete_block_count = nbyte / DISKBLOCKSIZE;
+ leftover_bytes_count = nbyte % DISKBLOCKSIZE;
+
+ if (delayed_seek_count != 0)
+ state = in_zeros;
+ else
+ state = begin;
+
+ seek_count = delayed_seek_count;
+
+ for (i = 0; i < complete_block_count; ++i)
+ {
+ switch (state)
+ {
+ case begin :
+ if (buf_all_zeros (buf, DISKBLOCKSIZE))
+ {
+ seek_count = DISKBLOCKSIZE;
+ state = in_zeros;
+ }
+ else
+ {
+ cur_write_start = buf;
+ write_count = DISKBLOCKSIZE;
+ state = not_in_zeros;
+ }
+ buf += DISKBLOCKSIZE;
+ break;
+ case in_zeros :
+ if (buf_all_zeros (buf, DISKBLOCKSIZE))
+ {
+ seek_count += DISKBLOCKSIZE;
+ }
+ else
+ {
+ lseek (fildes, seek_count, SEEK_CUR);
+ cur_write_start = buf;
+ write_count = DISKBLOCKSIZE;
+ state = not_in_zeros;
+ }
+ buf += DISKBLOCKSIZE;
+ break;
+ case not_in_zeros :
+ if (buf_all_zeros (buf, DISKBLOCKSIZE))
+ {
+ write_rc = write (fildes, cur_write_start, write_count);
+ seek_count = DISKBLOCKSIZE;
+ state = in_zeros;
+ }
+ else
+ {
+ write_count += DISKBLOCKSIZE;
+ }
+ buf += DISKBLOCKSIZE;
+ break;
+ }
+ }
+
+ switch (state)
+ {
+ case begin :
+ case in_zeros :
+ delayed_seek_count = seek_count;
+ break;
+ case not_in_zeros :
+ write_rc = write (fildes, cur_write_start, write_count);
+ delayed_seek_count = 0;
+ break;
+ }
+
+ if (leftover_bytes_count != 0)
+ {
+ if (delayed_seek_count != 0)
+ {
+ lseek_rc = lseek (fildes, delayed_seek_count, SEEK_CUR);
+ delayed_seek_count = 0;
+ }
+ write_rc = write (fildes, buf, leftover_bytes_count);
+ }
+ return nbyte;
+}
+
+static void
+write_nuls_to_file (num_bytes, out_des)
+ long num_bytes;
+ int out_des;
+{
+ long blocks;
+ long extra_bytes;
+ long i;
+
+ blocks = num_bytes / 512;
+ extra_bytes = num_bytes % 512;
+ for (i = 0; i < extra_bytes; ++i)
+ {
+ if (write (out_des, zeros_512, 512) != 512)
+ error (1, errno, "error writing NUL's");
+ }
+ if (extra_bytes != 0)
+ {
+ if (write (out_des, zeros_512, extra_bytes) != extra_bytes)
+ error (1, errno, "error writing NUL's");
+ }
+}
diff --git a/contrib/cpio/version.c b/contrib/cpio/version.c
new file mode 100644
index 0000000..c641a3a
--- /dev/null
+++ b/contrib/cpio/version.c
@@ -0,0 +1,2 @@
+/* The version number of cpio and mt. */
+char *version_string = "version 2.4.2\n";
diff --git a/contrib/cpio/xmalloc.c b/contrib/cpio/xmalloc.c
new file mode 100644
index 0000000..bad831f
--- /dev/null
+++ b/contrib/cpio/xmalloc.c
@@ -0,0 +1,103 @@
+/* xmalloc.c -- malloc with out of memory checking
+ Copyright (C) 1990, 91, 92, 93, 94 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if __STDC__
+#define VOID void
+#else
+#define VOID char
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#else
+VOID *malloc ();
+VOID *realloc ();
+void free ();
+#endif
+
+/* This is for other GNU distributions with internationalized messages.
+ The GNU C Library itself does not yet support such messages. */
+#if HAVE_LIBINTL_H
+# include <libintl.h>
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+/* Exit value when the requested amount of memory is not available.
+ The caller may set it to some other value. */
+int xmalloc_exit_failure = EXIT_FAILURE;
+
+#if __STDC__ && (HAVE_VPRINTF || HAVE_DOPRNT)
+void error (int, int, const char *, ...);
+#else
+void error ();
+#endif
+
+static VOID *
+fixup_null_alloc (n)
+ size_t n;
+{
+ VOID *p;
+
+ p = 0;
+ if (n == 0)
+ p = malloc ((size_t) 1);
+ if (p == 0)
+ error (xmalloc_exit_failure, 0, gettext ("Memory exhausted"));
+ return p;
+}
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+
+VOID *
+xmalloc (n)
+ size_t n;
+{
+ VOID *p;
+
+ p = malloc (n);
+ if (p == 0)
+ p = fixup_null_alloc (n);
+ return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking.
+ If P is NULL, run xmalloc. */
+
+VOID *
+xrealloc (p, n)
+ VOID *p;
+ size_t n;
+{
+ if (p == 0)
+ return xmalloc (n);
+ p = realloc (p, n);
+ if (p == 0)
+ p = fixup_null_alloc (n);
+ return p;
+}
diff --git a/contrib/cpio/xstrdup.c b/contrib/cpio/xstrdup.c
new file mode 100644
index 0000000..27cd0c6
--- /dev/null
+++ b/contrib/cpio/xstrdup.c
@@ -0,0 +1,36 @@
+/* xstrdup.c -- copy a string with out of memory checking
+ Copyright (C) 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+char *xmalloc ();
+
+/* Return a newly allocated copy of STRING. */
+
+char *
+xstrdup (string)
+ char *string;
+{
+ return strcpy (xmalloc (strlen (string) + 1), string);
+}
OpenPOWER on IntegriCloud