This is GNU cpio 2.3. It handles tar files and is fully compatible
authorJordan K. Hubbard <jkh@FreeBSD.org>
Sat, 7 Aug 1993 22:33:48 +0000 (22:33 +0000)
committerJordan K. Hubbard <jkh@FreeBSD.org>
Sat, 7 Aug 1993 22:33:48 +0000 (22:33 +0000)
with SYSV cpio.  It's also supposed to integrate rmt support, though
I haven't tried this.

46 files changed:
gnu/usr.bin/cpio/COPYING [new file with mode: 0644]
gnu/usr.bin/cpio/COPYING.LIB [new file with mode: 0644]
gnu/usr.bin/cpio/ChangeLog [new file with mode: 0644]
gnu/usr.bin/cpio/Makefile [new file with mode: 0644]
gnu/usr.bin/cpio/NEWS [new file with mode: 0644]
gnu/usr.bin/cpio/README [new file with mode: 0644]
gnu/usr.bin/cpio/alloca.c [new file with mode: 0644]
gnu/usr.bin/cpio/copyin.c [new file with mode: 0644]
gnu/usr.bin/cpio/copyout.c [new file with mode: 0644]
gnu/usr.bin/cpio/copypass.c [new file with mode: 0644]
gnu/usr.bin/cpio/cpio.1 [new file with mode: 0644]
gnu/usr.bin/cpio/cpio.h [new file with mode: 0644]
gnu/usr.bin/cpio/cpiohdr.h [new file with mode: 0644]
gnu/usr.bin/cpio/defer.c [new file with mode: 0644]
gnu/usr.bin/cpio/defer.h [new file with mode: 0644]
gnu/usr.bin/cpio/dirname.c [new file with mode: 0644]
gnu/usr.bin/cpio/dstring.c [new file with mode: 0644]
gnu/usr.bin/cpio/dstring.h [new file with mode: 0644]
gnu/usr.bin/cpio/error.c [new file with mode: 0644]
gnu/usr.bin/cpio/extern.h [new file with mode: 0644]
gnu/usr.bin/cpio/filemode.c [new file with mode: 0644]
gnu/usr.bin/cpio/filetypes.h [new file with mode: 0644]
gnu/usr.bin/cpio/fnmatch.c [new file with mode: 0644]
gnu/usr.bin/cpio/fnmatch.h [new file with mode: 0644]
gnu/usr.bin/cpio/getopt.c [new file with mode: 0644]
gnu/usr.bin/cpio/getopt.h [new file with mode: 0644]
gnu/usr.bin/cpio/getopt1.c [new file with mode: 0644]
gnu/usr.bin/cpio/global.c [new file with mode: 0644]
gnu/usr.bin/cpio/idcache.c [new file with mode: 0644]
gnu/usr.bin/cpio/main.c [new file with mode: 0644]
gnu/usr.bin/cpio/makepath.c [new file with mode: 0644]
gnu/usr.bin/cpio/mt.1 [new file with mode: 0644]
gnu/usr.bin/cpio/rmt.c [new file with mode: 0644]
gnu/usr.bin/cpio/rmt.h [new file with mode: 0644]
gnu/usr.bin/cpio/rtapelib.c [new file with mode: 0644]
gnu/usr.bin/cpio/stripslash.c [new file with mode: 0644]
gnu/usr.bin/cpio/system.h [new file with mode: 0644]
gnu/usr.bin/cpio/tar.c [new file with mode: 0644]
gnu/usr.bin/cpio/tar.h [new file with mode: 0644]
gnu/usr.bin/cpio/tarhdr.h [new file with mode: 0644]
gnu/usr.bin/cpio/tcexparg.c [new file with mode: 0644]
gnu/usr.bin/cpio/userspec.c [new file with mode: 0644]
gnu/usr.bin/cpio/util.c [new file with mode: 0644]
gnu/usr.bin/cpio/version.c [new file with mode: 0644]
gnu/usr.bin/cpio/xmalloc.c [new file with mode: 0644]
gnu/usr.bin/cpio/xstrdup.c [new file with mode: 0644]

diff --git a/gnu/usr.bin/cpio/COPYING b/gnu/usr.bin/cpio/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
@@ -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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+       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/gnu/usr.bin/cpio/COPYING.LIB b/gnu/usr.bin/cpio/COPYING.LIB
new file mode 100644 (file)
index 0000000..eb685a5
--- /dev/null
@@ -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.
+\f
+  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.
+\f
+                 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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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
+\f
+     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/gnu/usr.bin/cpio/ChangeLog b/gnu/usr.bin/cpio/ChangeLog
new file mode 100644 (file)
index 0000000..9b18d4f
--- /dev/null
@@ -0,0 +1,781 @@
+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.
+\f
+Local Variables:
+mode: indented-text
+left-margin: 8
+version-control: never
+End:
diff --git a/gnu/usr.bin/cpio/Makefile b/gnu/usr.bin/cpio/Makefile
new file mode 100644 (file)
index 0000000..104fe3c
--- /dev/null
@@ -0,0 +1,9 @@
+PROG= cpio
+CFLAGS+= -I${.CURDIR} -DRETSIGTYPE=void -DHAVE_SYS_MTIO_H=1 -DSTDC_HEADERS=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_FCNTL_H=1 -DHAVE_UTIME_H=1 -DHAVE_STRERROR=1 -DHAVE_VPRINTF=1 -DDIRENT=1
+
+SRCS = copyin.c copyout.c copypass.c defer.c dstring.c fnmatch.c global.c \
+       main.c tar.c util.c error.c filemode.c getopt.c getopt1.c version.c \
+       rtapelib.c dirname.c idcache.c makepath.c xmalloc.c stripslash.c \
+       userspec.c xstrdup.c
+
+.include <bsd.prog.mk>
diff --git a/gnu/usr.bin/cpio/NEWS b/gnu/usr.bin/cpio/NEWS
new file mode 100644 (file)
index 0000000..2648c84
--- /dev/null
@@ -0,0 +1,55 @@
+\f
+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
+\f
+Major changes in version 2.2:
+
+* handle link counts correctly when reading binary cpio archives
+* configure checks for some libraries that SVR4 needs
+\f
+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
+\f
+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/gnu/usr.bin/cpio/README b/gnu/usr.bin/cpio/README
new file mode 100644 (file)
index 0000000..83b5228
--- /dev/null
@@ -0,0 +1,56 @@
+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.
+
+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/gnu/usr.bin/cpio/alloca.c b/gnu/usr.bin/cpio/alloca.c
new file mode 100644 (file)
index 0000000..c04c0ef
--- /dev/null
@@ -0,0 +1,475 @@
+/* alloca.c -- allocate automatically reclaimed memory
+   (Mostly) portable public-domain implementation -- D A Gwyn
+
+   This implementation of the PWB library alloca function,
+   which is used to allocate space off the run-time stack so
+   that it is automatically reclaimed upon procedure exit,
+   was inspired by discussions with J. Q. Johnson of Cornell.
+   J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+   There are some preprocessor constants that can
+   be defined when compiling for your specific system, for
+   improved efficiency; however, the defaults should be okay.
+
+   The general concept of this implementation is to keep
+   track of all alloca-allocated blocks, and reclaim any
+   that are found to be deeper in the stack than the current
+   invocation.  This heuristic does not reclaim storage as
+   soon as it becomes invalid, but it will do so eventually.
+
+   As a special case, alloca(0) reclaims storage without
+   allocating any.  It is a good idea to use alloca(0) in
+   your main control loop, etc. to force garbage collection.  */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* If compiling with GCC, this file's not needed.  */
+#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.  */
+
+#ifdef CRAY
+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
+extern pointer xmalloc ();
+#endif
+
+/* 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.  */
+
+    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.  */
+  }
+
+  if (size == 0)
+    return NULL;               /* No allocation required.  */
+
+  /* Allocate combined header + user data storage.  */
+
+  {
+    register pointer new = malloc (sizeof (header) + size);
+    /* Address of header.  */
+
+    ((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));
+  }
+}
+
+#ifdef CRAY
+
+#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 */
diff --git a/gnu/usr.bin/cpio/copyin.c b/gnu/usr.bin/cpio/copyin.c
new file mode 100644 (file)
index 0000000..5196c5d
--- /dev/null
@@ -0,0 +1,1272 @@
+/* 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 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 = peek_in_buf (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
+           {
+             copy_in_buf ((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;
+
+  copy_in_buf ((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);
+      copy_in_buf ((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;
+
+  copy_in_buf (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);
+  copy_in_buf (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];
+
+  copy_in_buf (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);
+  copy_in_buf (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.  */
+  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;
+  copy_in_buf (((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);
+  copy_in_buf (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)
+    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.  */
+  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));
+
+  /* Open interactive file pair for rename operation.  */
+  if (rename_flag)
+    {
+      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;
+       }
+
+      /* 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)
+       {
+         toss_input (in_file_des, file_hdr.c_filesize);
+         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';
+                     copy_in_buf (link_name, in_file_des, file_hdr.c_filesize);
+                     long_format (&file_hdr, link_name);
+                     free (link_name);
+                     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);
+
+         toss_input (in_file_des, file_hdr.c_filesize);
+         skip_padding (in_file_des, file_hdr.c_filesize);
+       }
+      else if (append_flag)
+       {
+         toss_input (in_file_des, file_hdr.c_filesize);
+         skip_padding (in_file_des, file_hdr.c_filesize);
+       }
+      else
+       {
+         /* Copy the input file into the directory structure.  */
+
+         /* Do we need to rename the file? */
+         if (rename_flag)
+           {
+             fprintf (tty_out, "rename %s -> ", file_hdr.c_name);
+             fflush (tty_out);
+             str_res = ds_fgets (tty_in, &new_name);
+             if (str_res == NULL || str_res[0] == 0)
+               {
+                 toss_input (in_file_des, file_hdr.c_filesize);
+                 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);
+                 toss_input (in_file_des, file_hdr.c_filesize);
+                 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);
+                 toss_input (in_file_des, file_hdr.c_filesize);
+                 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);
+                     toss_input (in_file_des, file_hdr.c_filesize);
+                     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)
+                   {
+                     toss_input (in_file_des, file_hdr.c_filesize);
+                     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)
+                   {
+                     toss_input (in_file_des, file_hdr.c_filesize);
+                     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);
+                     toss_input (in_file_des, file_hdr.c_filesize);
+                     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 (in_file_des, out_file_des, file_hdr.c_filesize);
+                 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);
+                   }
+                 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)
+               {
+                 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';
+                   copy_in_buf (link_name, in_file_des, file_hdr.c_filesize);
+                   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);
+             toss_input (in_file_des, file_hdr.c_filesize);
+             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 ();
+  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);
+}
+\f
+/* 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
+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)
+    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;
+  struct deferment *d_prev;
+  struct new_cpio_header *h;
+  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/gnu/usr.bin/cpio/copyout.c b/gnu/usr.bin/cpio/copyout.c
new file mode 100644 (file)
index 0000000..f763f2b
--- /dev/null
@@ -0,0 +1,801 @@
+/* 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 clear_rest_of_block ();
+static void 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);
+      copy_buf_out (ascii_header, out_des, 110L);
+
+      /* Write file name to output.  */
+      copy_buf_out (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
+      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,
+              "%06lo%06lo%06lo%06lo%06lo%06lo%06lo%06lo%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);
+      copy_buf_out (ascii_header, out_des, 76L);
+
+      /* Write file name to output.  */
+      copy_buf_out (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.  */
+      copy_buf_out ((char *) &short_hdr, out_des, 26L);
+
+      /* Write file name to output.  */
+      copy_buf_out (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
+
+      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 (in_file_des, out_file_des, file_hdr.c_filesize);
+
+#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
+
+             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);
+
+               if (readlink (input_name.ds_string, link_name,
+                             file_stat.st_size) < 0)
+                 {
+                   error (0, errno, "%s", input_name.ds_string);
+                   free (link_name);
+                   continue;
+                 }
+               if (archive_format == arf_tar || archive_format == arf_ustar)
+                 {
+                   if (file_stat.st_size + 1 > 100)
+                     {
+                       error (0, 0, "%s: symbolic link too long",
+                              file_hdr.c_name);
+                     }
+                   else
+                     {
+                       link_name[file_stat.st_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);
+                   copy_buf_out (link_name, out_file_des, file_stat.st_size);
+                   pad_output (out_file_des, file_hdr.c_filesize);
+                 }
+               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
+    {
+      copy_buf_out (zeros_512, out_file_des, 512);
+      copy_buf_out (zeros_512, out_file_des, 512);
+    }
+
+  /* Fill up the output block.  */
+  clear_rest_of_block (out_file_des);
+  empty_output_buffer (out_file_des);
+  if (dot_flag)
+    fputc ('\n', stderr);
+  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
+clear_rest_of_block (out_file_des)
+     int out_file_des;
+{
+  while (output_size < io_block_size)
+    {
+      if ((io_block_size - output_size) > 512)
+       copy_buf_out (zeros_512, out_file_des, 512);
+      else
+       copy_buf_out (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
+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)
+    copy_buf_out (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;
+  int  count;
+  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 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 (in_file_des, out_file_des, file_hdr.c_filesize);
+
+#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
+
+  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/gnu/usr.bin/cpio/copypass.c b/gnu/usr.bin/cpio/copypass.c
new file mode 100644 (file)
index 0000000..afd5753
--- /dev/null
@@ -0,0 +1,449 @@
+/* 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 (in_file_des, out_file_des, in_file_stat.st_size);
+             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)
+           {
+             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;
+         link_name = (char *) xmalloc ((unsigned int) in_file_stat.st_size + 1);
+
+         if (readlink (input_name.ds_string, link_name,
+                       in_file_stat.st_size) < 0)
+           {
+             error (0, errno, "%s", input_name.ds_string);
+             free (link_name);
+             continue;
+           }
+         link_name[in_file_stat.st_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);
+  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);
+}
+\f
+/* 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;
+}
+\f
+/* 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/gnu/usr.bin/cpio/cpio.1 b/gnu/usr.bin/cpio/cpio.1
new file mode 100644 (file)
index 0000000..7ef74c4
--- /dev/null
@@ -0,0 +1,310 @@
+.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]
+[\-\-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]
+[\-\-help] [\-\-version] [pattern...] [< archive]
+
+.B cpio
+{\-p|\-\-pass-through} [\-0adlmuvLV] [\-R [user][:.][group]]
+[\-\-null] [\-\-reset-access-time] [\-\-make-directories] [\-\-link]
+[\-\-preserve-modification-time] [\-\-unconditional] [\-\-verbose] [\-\-dot]
+[\-\-dereference] [\-\-owner=[user][:.][group]] [\-\-no-preserve-owner]
+[\-\-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
+pathname, 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-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 "\-p, \-\-pass-through"
+Run in copy-pass mode.
+.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 "\-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/gnu/usr.bin/cpio/cpio.h b/gnu/usr.bin/cpio/cpio.h
new file mode 100644 (file)
index 0000000..537da72
--- /dev/null
@@ -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/gnu/usr.bin/cpio/cpiohdr.h b/gnu/usr.bin/cpio/cpiohdr.h
new file mode 100644 (file)
index 0000000..9694af6
--- /dev/null
@@ -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/gnu/usr.bin/cpio/defer.c b/gnu/usr.bin/cpio/defer.c
new file mode 100644 (file)
index 0000000..efe60e0
--- /dev/null
@@ -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/gnu/usr.bin/cpio/defer.h b/gnu/usr.bin/cpio/defer.h
new file mode 100644 (file)
index 0000000..89abffe
--- /dev/null
@@ -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/gnu/usr.bin/cpio/dirname.c b/gnu/usr.bin/cpio/dirname.c
new file mode 100644 (file)
index 0000000..5a92ce5
--- /dev/null
@@ -0,0 +1,66 @@
+/* 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 STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+#endif
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#ifndef rindex
+#define rindex strrchr
+#endif
+#else
+#include <strings.h>
+#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 = rindex (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 = malloc (length + 1);
+  if (newpath == 0)
+    return 0;
+  strncpy (newpath, path, length);
+  newpath[length] = 0;
+  return newpath;
+}
diff --git a/gnu/usr.bin/cpio/dstring.c b/gnu/usr.bin/cpio/dstring.c
new file mode 100644 (file)
index 0000000..26d6bbc
--- /dev/null
@@ -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/gnu/usr.bin/cpio/dstring.h b/gnu/usr.bin/cpio/dstring.h
new file mode 100644 (file)
index 0000000..369da0b
--- /dev/null
@@ -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/gnu/usr.bin/cpio/error.c b/gnu/usr.bin/cpio/error.c
new file mode 100644 (file)
index 0000000..e849c5b
--- /dev/null
@@ -0,0 +1,106 @@
+/* error.c -- error handler for noninteractive utilities
+   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 David MacKenzie.  */
+
+#include <stdio.h>
+
+#ifdef HAVE_VPRINTF
+
+#if __STDC__
+#include <stdarg.h>
+#define VA_START(args, lastarg) va_start(args, lastarg)
+#else /* !__STDC__ */
+#include <varargs.h>
+#define VA_START(args, lastarg) va_start(args)
+#endif /* !__STDC__ */
+
+#else /* !HAVE_VPRINTF */
+
+#ifdef HAVE_DOPRNT
+#define va_alist args
+#define va_dcl int args;
+#else /* !HAVE_DOPRNT */
+#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif /* !HAVE_DOPRNT */
+
+#endif /* !HAVE_VPRINTF */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else /* !STDC_HEADERS */
+void exit ();
+#endif /* !STDC_HEADERS */
+
+extern char *program_name;
+
+#ifndef HAVE_STRERROR
+static char *
+private_strerror (errnum)
+     int errnum;
+{
+  extern char *sys_errlist[];
+  extern int sys_nerr;
+
+  if (errnum > 0 && errnum <= sys_nerr)
+    return sys_errlist[errnum];
+  return "Unknown system error";
+}
+#define strerror private_strerror
+#endif /* !HAVE_STRERROR */
+
+/* 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 (HAVE_VPRINTF) && __STDC__
+error (int status, int errnum, char *message, ...)
+#else /* !HAVE_VPRINTF or !__STDC__ */
+error (status, errnum, message, va_alist)
+     int status;
+     int errnum;
+     char *message;
+     va_dcl
+#endif /* !HAVE_VPRINTF or !__STDC__ */
+{
+#ifdef HAVE_VPRINTF
+  va_list args;
+#endif /* HAVE_VPRINTF */
+
+  fprintf (stderr, "%s: ", program_name);
+#ifdef HAVE_VPRINTF
+  VA_START (args, message);
+  vfprintf (stderr, message, args);
+  va_end (args);
+#else /* !HAVE_VPRINTF */
+#ifdef HAVE_DOPRNT
+  _doprnt (message, &args, stderr);
+#else /* !HAVE_DOPRNT */
+  fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif /* !HAVE_DOPRNT */
+#endif /* !HAVE_VPRINTF */
+  if (errnum)
+    fprintf (stderr, ": %s", strerror (errnum));
+  putc ('\n', stderr);
+  fflush (stderr);
+  if (status)
+    exit (status);
+}
diff --git a/gnu/usr.bin/cpio/extern.h b/gnu/usr.bin/cpio/extern.h
new file mode 100644 (file)
index 0000000..50b152c
--- /dev/null
@@ -0,0 +1,176 @@
+/* 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 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 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_size, output_size;
+extern long input_bytes, output_bytes;
+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) ();
+\f
+#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));
+
+/* 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 empty_output_buffer P_((int out_des));
+void swahw_array P_((char *ptr, int count));
+void fill_input_buffer P_((int in_des, int num_bytes));
+void copy_buf_out P_((char *in_buf, int out_des, long num_bytes));
+void copy_in_buf P_((char *in_buf, int in_des, long num_bytes));
+int peek_in_buf P_((char *peek_buf, int in_des, int num_bytes));
+void toss_input P_((int in_des, long num_bytes));
+void copy_files P_((int in_des, int out_des, long num_bytes));
+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));
+#ifdef __MSDOS__
+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));
diff --git a/gnu/usr.bin/cpio/filemode.c b/gnu/usr.bin/cpio/filemode.c
new file mode 100644 (file)
index 0000000..9293af6
--- /dev/null
@@ -0,0 +1,229 @@
+/* filemode.c -- make a string describing file modes
+   Copyright (C) 1985, 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.  */
+\f
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef S_IREAD
+#define S_IREAD S_IRUSR
+#define S_IWRITE S_IWUSR
+#define S_IEXEC S_IXUSR
+#endif
+
+#if !defined(S_ISREG) || defined(NO_MODE_T)
+/* Doesn't have POSIX.1 stat stuff or doesn't have mode_t.  */
+#define mode_t unsigned short
+#endif
+
+#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 (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)
+     mode_t 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_IREAD) ? 'r' : '-';
+  chars[1] = (bits & S_IWRITE) ? 'w' : '-';
+  chars[2] = (bits & S_IEXEC) ? '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/gnu/usr.bin/cpio/filetypes.h b/gnu/usr.bin/cpio/filetypes.h
new file mode 100644 (file)
index 0000000..46a79a9
--- /dev/null
@@ -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/gnu/usr.bin/cpio/fnmatch.c b/gnu/usr.bin/cpio/fnmatch.c
new file mode 100644 (file)
index 0000000..8a25a90
--- /dev/null
@@ -0,0 +1,200 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+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; see the file COPYING.LIB.  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 <errno.h>
+#include <fnmatch.h>
+#include <ctype.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__)
+
+
+#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
+extern int errno;
+#endif
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+   it matches, nonzero if not.  */
+int
+fnmatch (pattern, string, flags)
+     const char *pattern;
+     const char *string;
+     int flags;
+{
+  register const char *p = pattern, *n = string;
+  register char c;
+
+/* Note that this evalutes C many times.  */
+#define FOLD(c)        ((flags & FNM_CASEFOLD) && isupper (c) ? tolower (c) : (c))
+
+  while ((c = *p++) != '\0')
+    {
+      c = FOLD (c);
+
+      switch (c)
+       {
+       case '?':
+         if (*n == '\0')
+           return FNM_NOMATCH;
+         else if ((flags & FNM_FILE_NAME) && *n == '/')
+           return FNM_NOMATCH;
+         else if ((flags & FNM_PERIOD) && *n == '.' &&
+                  (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+           return FNM_NOMATCH;
+         break;
+
+       case '\\':
+         if (!(flags & FNM_NOESCAPE))
+           {
+             c = *p++;
+             c = FOLD (c);
+           }
+         if (FOLD (*n) != c)
+           return FNM_NOMATCH;
+         break;
+
+       case '*':
+         if ((flags & FNM_PERIOD) && *n == '.' &&
+             (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+           return FNM_NOMATCH;
+
+         for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
+           if (((flags & FNM_FILE_NAME) && *n == '/') ||
+               (c == '?' && *n == '\0'))
+             return FNM_NOMATCH;
+
+         if (c == '\0')
+           return 0;
+
+         {
+           char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
+           c1 = FOLD (c1);
+           for (--p; *n != '\0'; ++n)
+             if ((c == '[' || FOLD (*n) == c1) &&
+                 fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+               return 0;
+           return FNM_NOMATCH;
+         }
+
+       case '[':
+         {
+           /* Nonzero if the sense of the character class is inverted.  */
+           register int not;
+
+           if (*n == '\0')
+             return FNM_NOMATCH;
+
+           if ((flags & FNM_PERIOD) && *n == '.' &&
+               (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+             return FNM_NOMATCH;
+
+           not = (*p == '!' || *p == '^');
+           if (not)
+             ++p;
+
+           c = *p++;
+           for (;;)
+             {
+               register char cstart = c, cend = c;
+
+               if (!(flags & FNM_NOESCAPE) && c == '\\')
+                 cstart = cend = *p++;
+
+               cstart = cend = FOLD (cstart);
+
+               if (c == '\0')
+                 /* [ (unterminated) loses.  */
+                 return FNM_NOMATCH;
+
+               c = *p++;
+               c = FOLD (c);
+
+               if ((flags & FNM_FILE_NAME) && c == '/')
+                 /* [/] can never match.  */
+                 return FNM_NOMATCH;
+
+               if (c == '-' && *p != ']')
+                 {
+                   cend = *p++;
+                   if (!(flags & FNM_NOESCAPE) && cend == '\\')
+                     cend = *p++;
+                   if (cend == '\0')
+                     return FNM_NOMATCH;
+                   cend = FOLD (cend);
+
+                   c = *p++;
+                 }
+
+               if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
+                 goto matched;
+
+               if (c == ']')
+                 break;
+             }
+           if (!not)
+             return FNM_NOMATCH;
+           break;
+
+         matched:;
+           /* Skip the rest of the [...] that already matched.  */
+           while (c != ']')
+             {
+               if (c == '\0')
+                 /* [... (unterminated) loses.  */
+                 return FNM_NOMATCH;
+
+               c = *p++;
+               if (!(flags & FNM_NOESCAPE) && c == '\\')
+                 /* XXX 1003.2d11 is unclear if this is right.  */
+                 ++p;
+             }
+           if (not)
+             return FNM_NOMATCH;
+         }
+         break;
+
+       default:
+         if (c != FOLD (*n))
+           return FNM_NOMATCH;
+       }
+
+      ++n;
+    }
+
+  if (*n == '\0')
+    return 0;
+
+  if ((flags & FNM_LEADING_DIR) && *n == '/')
+    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
+    return 0;
+
+  return FNM_NOMATCH;
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
diff --git a/gnu/usr.bin/cpio/fnmatch.h b/gnu/usr.bin/cpio/fnmatch.h
new file mode 100644 (file)
index 0000000..5c94813
--- /dev/null
@@ -0,0 +1,60 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+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; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef        _FNMATCH_H
+
+#define        _FNMATCH_H      1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+#undef __P
+#define        __P(args)       args
+#else /* Not C++ or ANSI C.  */
+#undef __P
+#define        __P(args)       ()
+/* We can get away without defining `const' here only because in this file
+   it is used only inside the prototype for `fnmatch', which is elided in
+   non-ANSI C where `const' is problematical.  */
+#endif /* C++ or ANSI C.  */
+
+/* Bits set in the FLAGS argument to `fnmatch'.  */
+#define        FNM_PATHNAME    (1 << 0) /* No wildcard can ever match `/'.  */
+#define        FNM_NOESCAPE    (1 << 1) /* Backslashes don't quote special chars.  */
+#define        FNM_PERIOD      (1 << 2) /* Leading `.' is matched only explicitly.  */
+
+#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE)
+#define        FNM_FILE_NAME   FNM_PATHNAME /* Preferred GNU name.  */
+#define        FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match.  */
+#define        FNM_CASEFOLD    (1 << 4) /* Compare without regard to case.  */
+#endif
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN.  */
+#define        FNM_NOMATCH     1
+
+/* Match STRING against the filename pattern PATTERN,
+   returning zero if it matches, FNM_NOMATCH if not.  */
+extern int fnmatch __P ((const char *__pattern, const char *__string,
+                        int __flags));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* fnmatch.h */
diff --git a/gnu/usr.bin/cpio/getopt.c b/gnu/usr.bin/cpio/getopt.c
new file mode 100644 (file)
index 0000000..2867a90
--- /dev/null
@@ -0,0 +1,744 @@
+/* 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#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.  */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+   long-named option.  Because this is not POSIX.2 compliant, it is
+   being phased out.  */
+/* #define GETOPT_COMPAT */
+
+/* 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 = 0;
+
+/* 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;
+\f
+#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__
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+extern size_t strlen (const char *);
+#endif
+
+#endif                         /* GNU C library.  */
+\f
+/* 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;
+}
+\f
+/* 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;
+{
+  int option_index;
+
+  optarg = 0;
+
+  /* Initialize the internal data when the first call is made.
+     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.  */
+
+  if (optind == 0)
+    {
+      first_nonopt = last_nonopt = optind = 1;
+
+      nextchar = NULL;
+
+      /* 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 (getenv ("POSIXLY_CORRECT") != NULL)
+       ordering = REQUIRE_ORDER;
+      else
+       ordering = PERMUTE;
+    }
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      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;
+
+         /* Now skip any additional non-options
+            and extend the range of non-options previously skipped.  */
+
+         while (optind < argc
+                && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+                && (longopts == NULL
+                    || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif                         /* GETOPT_COMPAT */
+                )
+           optind++;
+         last_nonopt = optind;
+       }
+
+      /* 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')
+#ifdef GETOPT_COMPAT
+         && (longopts == NULL
+             || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif                         /* GETOPT_COMPAT */
+         )
+       {
+         if (ordering == REQUIRE_ORDER)
+           return EOF;
+         optarg = argv[optind++];
+         return 1;
+       }
+
+      /* We have found another option-ARGV-element.
+        Start decoding its characters.  */
+
+      nextchar = (argv[optind] + 1
+                 + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  if (longopts != NULL
+      && ((argv[optind][0] == '-'
+          && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+         || argv[optind][0] == '+'
+#endif                         /* GETOPT_COMPAT */
+         ))
+    {
+      const struct option *p;
+      char *s = nextchar;
+      int exact = 0;
+      int ambig = 0;
+      const struct option *pfound = NULL;
+      int indfound;
+
+      while (*s && *s != '=')
+       s++;
+
+      /* Test all options for either exact match or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name;
+          p++, option_index++)
+       if (!strncmp (p->name, nextchar, s - nextchar))
+         {
+           if (s - 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 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 (*s)
+           {
+             /* Don't test has_arg with >, because some C compilers don't
+                allow it to be used on enums.  */
+             if (pfound->has_arg)
+               optarg = s + 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] == '-'
+#ifdef GETOPT_COMPAT
+         || argv[optind][0] == '+'
+#endif                         /* GETOPT_COMPAT */
+         || 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 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 0
+           if (c < 040 || c >= 0177)
+             fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+                      argv[0], c);
+           else
+             fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+           /* 1003.2 specifies the format of this message.  */
+           fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+         }
+       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 = 0;
+           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)
+                 {
+#if 0
+                   fprintf (stderr, "%s: option `-%c' requires an argument\n",
+                            argv[0], c);
+#else
+                   /* 1003.2 specifies the format of this message.  */
+                   fprintf (stderr, "%s: option requires an argument -- %c\n",
+                            argv[0], c);
+#endif
+                 }
+               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__.  */
+\f
+#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/gnu/usr.bin/cpio/getopt.h b/gnu/usr.bin/cpio/getopt.h
new file mode 100644 (file)
index 0000000..45541f5
--- /dev/null
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+   Copyright (C) 1989, 1990, 1991, 1992, 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, 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    __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 __STDC__
+#if defined(__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 /* not __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 /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/gnu/usr.bin/cpio/getopt1.c b/gnu/usr.bin/cpio/getopt1.c
new file mode 100644 (file)
index 0000000..a32615c
--- /dev/null
@@ -0,0 +1,176 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "getopt.h"
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#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__.  */
+\f
+#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/gnu/usr.bin/cpio/global.c b/gnu/usr.bin/cpio/global.c
new file mode 100644 (file)
index 0000000..d4b5441
--- /dev/null
@@ -0,0 +1,168 @@
+/* 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 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;
+
+#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;
+
+/* 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.  */
+long input_bytes, output_bytes;
+
+/* 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/gnu/usr.bin/cpio/idcache.c b/gnu/usr.bin/cpio/idcache.c
new file mode 100644 (file)
index 0000000..dd9c366
--- /dev/null
@@ -0,0 +1,206 @@
+/* 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.  */
+
+#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/gnu/usr.bin/cpio/main.c b/gnu/usr.bin/cpio/main.c
new file mode 100644 (file)
index 0000000..78b5fc5
--- /dev/null
@@ -0,0 +1,479 @@
+/* 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-preserve-owner", 0, 0, 134},
+  {"nonmatching", 0, &copy_matching_files, FALSE},
+  {"numeric-uid-gid", 0, &numeric_uid, TRUE},
+  {"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},
+  {"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]\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] [--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]\n\
+       [--preserve-modification-time] [--unconditional] [--verbose] [--dot]\n\
+       [--dereference] [--owner=[user][:.][group]] [--no-preserve-owner]\n\
+       [--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 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 '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 '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 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
+         || 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))
+         || 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)
+       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 buf_size;
+
+  /* Make sure buffers can always hold 2 blocks and that they
+     are 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)
+    buf_size = 2 * io_block_size;
+  else
+    buf_size = 1024;
+  input_buffer = (char *) xmalloc (buf_size);
+  in_buff = input_buffer;
+  input_size = 0;
+  input_bytes = 0;
+
+  /* Leave space for an `int' sentinel for `empty_output_buffer',
+     in case we ever put back sparseness checking.  */
+  output_buffer = (char *) xmalloc (buf_size + sizeof (int) * 2);
+  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/gnu/usr.bin/cpio/makepath.c b/gnu/usr.bin/cpio/makepath.c
new file mode 100644 (file)
index 0000000..bdf6829
--- /dev/null
@@ -0,0 +1,297 @@
+/* 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
+
+#ifdef STDC_HEADERS
+#include <errno.h>
+#include <stdlib.h>
+#else
+extern int errno;
+#endif
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#define index strchr
+#else
+#include <strings.h>
+#endif
+
+#ifdef __MSDOS__
+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))
+       {
+         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/gnu/usr.bin/cpio/mt.1 b/gnu/usr.bin/cpio/mt.1
new file mode 100644 (file)
index 0000000..fc9cb64
--- /dev/null
@@ -0,0 +1,107 @@
+.TH MT 1L \" -*- nroff -*-
+.SH NAME
+mt \- control magnetic tape drive operation
+.SH SYNOPSIS
+.B mt
+[\-V] [\-f device] [\-\-file=device] [\-\-version]
+operation [count]
+.SH DESCRIPTION
+This manual page
+documents the GNU version of
+.BR mt .
+.B mt
+performs the given
+.IR operation ,
+which must be one of the tape operations listed below, on a tape
+drive.
+.PP
+The default tape device to operate on is taken from the file
+.I /usr/include/sys/mtio.h
+when
+.B mt
+is compiled.  It can be overridden by giving a device file name in
+the environment variable
+.BR TAPE
+or by a command line option (see below), which also overrides the
+environment variable.
+.PP
+The device must be either a character special file or a
+remote tape drive.  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).
+.PP
+The available operations are listed below.  Unique abbreviations are
+accepted.  Not all operations are available on all systems, or work on
+all types of tape drives.
+Some operations optionally take a repeat count, which can be given
+after the operation name and defaults to 1.
+.IP "eof, weof"
+Write
+.I count
+EOF marks at current position.
+.IP fsf
+Forward space
+.I count
+files.
+The tape is positioned on the first block of the next file.
+.IP bsf
+Backward space
+.I count
+files.
+The tape is positioned on the first block of the next file.
+.IP fsr
+Forward space
+.I count
+records.
+.IP bsr
+Backward space
+.I count
+records.
+.IP bsfm
+Backward space
+.I count
+file marks.
+The tape is positioned on the beginning-of-the-tape side of
+the file mark.
+.IP asf
+Absolute space to file number
+.IR count .
+Equivalent to rewind followed by fsf
+.IR count .
+.IP eom
+Space to the end of the recorded media on the tape
+(for appending files onto tapes).
+.IP rewind
+Rewind the tape.
+.IP "offline, rewoffl"
+Rewind the tape and, if applicable, unload the tape.
+.IP status
+Print status information about the tape unit.
+.IP retension
+Rewind the tape, then wind it to the end of the reel,
+then rewind it again.
+.IP erase
+Erase the tape.
+.PP
+.B mt
+exits with a status of 0 if the operation succeeded, 1 if the
+operation or device name given was invalid, or 2 if the operation
+failed.
+.SS OPTIONS
+.TP
+.I "\-f, \-\-file=device"
+Use
+.I device
+as the file name of the tape drive to operate on.
+To use a
+tape drive on another machine, 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 "\-V, \-\-version"
+Print the version number of
+.BR mt .
diff --git a/gnu/usr.bin/cpio/rmt.c b/gnu/usr.bin/cpio/rmt.c
new file mode 100644 (file)
index 0000000..442a831
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * rmt
+ */
+#include <stdio.h>
+#include <sgtty.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_GENTAPE_H      /* e.g., ISC UNIX */
+#include <sys/gentape.h>
+#else
+#include <sys/mtio.h>
+#endif
+#include <errno.h>
+
+#if defined (_I386) && defined (_AIX)
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#else
+long lseek ();
+#endif
+
+#ifdef STDC_HEADERS
+#include <string.h>
+#include <stdlib.h>
+#else
+extern char *malloc ();
+#endif
+
+int tape = -1;
+
+char *record;
+int maxrecsize = -1;
+char *checkbuf ();
+void getstring ();
+void error ();
+
+#define        SSIZE   64
+char device[SSIZE];
+char count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE];
+
+extern errno;
+extern char *sys_errlist[];
+char resp[BUFSIZ];
+
+FILE *debug;
+#define        DEBUG(f)        if (debug) fprintf(debug, f)
+#define        DEBUG1(f,a)     if (debug) fprintf(debug, f, a)
+#define        DEBUG2(f,a1,a2) if (debug) fprintf(debug, f, a1, a2)
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int rval;
+  char c;
+  int n, i, cc;
+
+  argc--, argv++;
+  if (argc > 0)
+    {
+      debug = fopen (*argv, "w");
+      if (debug == 0)
+       exit (1);
+      (void) setbuf (debug, (char *) 0);
+    }
+top:
+  errno = 0;
+  rval = 0;
+  if (read (0, &c, 1) != 1)
+    exit (0);
+  switch (c)
+    {
+
+    case 'O':
+      if (tape >= 0)
+       (void) close (tape);
+      getstring (device);
+      getstring (mode);
+      DEBUG2 ("rmtd: O %s %s\n", device, mode);
+#if defined (i386) && defined (AIX)
+      /* This is alleged to fix a byte ordering problem. */
+      /* I'm quite suspicious if it's right. -- mib */
+      {
+       int oflag = atoi (mode);
+       int nflag = 0;
+       if ((oflag & 3) == 0)
+         nflag |= O_RDONLY;
+       if (oflag & 1)
+         nflag |= O_WRONLY;
+       if (oflag & 2)
+         nflag |= O_RDWR;
+       if (oflag & 0x0008)
+         nflag |= O_APPEND;
+       if (oflag & 0x0200)
+         nflag |= O_CREAT;
+       if (oflag & 0x0400)
+         nflag |= O_TRUNC;
+       if (oflag & 0x0800)
+         nflag |= O_EXCL;
+       tape = open (device, nflag, 0666);
+      }
+#else
+      tape = open (device, atoi (mode), 0666);
+#endif
+      if (tape < 0)
+       goto ioerror;
+      goto respond;
+
+    case 'C':
+      DEBUG ("rmtd: C\n");
+      getstring (device);      /* discard */
+      if (close (tape) < 0)
+       goto ioerror;
+      tape = -1;
+      goto respond;
+
+    case 'L':
+      getstring (count);
+      getstring (pos);
+      DEBUG2 ("rmtd: L %s %s\n", count, pos);
+      rval = lseek (tape, (long) atoi (count), atoi (pos));
+      if (rval < 0)
+       goto ioerror;
+      goto respond;
+
+    case 'W':
+      getstring (count);
+      n = atoi (count);
+      DEBUG1 ("rmtd: W %s\n", count);
+      record = checkbuf (record, n);
+      for (i = 0; i < n; i += cc)
+       {
+         cc = read (0, &record[i], n - i);
+         if (cc <= 0)
+           {
+             DEBUG ("rmtd: premature eof\n");
+             exit (2);
+           }
+       }
+      rval = write (tape, record, n);
+      if (rval < 0)
+       goto ioerror;
+      goto respond;
+
+    case 'R':
+      getstring (count);
+      DEBUG1 ("rmtd: R %s\n", count);
+      n = atoi (count);
+      record = checkbuf (record, n);
+      rval = read (tape, record, n);
+      if (rval < 0)
+       goto ioerror;
+      (void) sprintf (resp, "A%d\n", rval);
+      (void) write (1, resp, strlen (resp));
+      (void) write (1, record, rval);
+      goto top;
+
+    case 'I':
+      getstring (op);
+      getstring (count);
+      DEBUG2 ("rmtd: I %s %s\n", op, count);
+#ifdef MTIOCTOP
+      {
+       struct mtop mtop;
+       mtop.mt_op = atoi (op);
+       mtop.mt_count = atoi (count);
+       if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0)
+         goto ioerror;
+       rval = mtop.mt_count;
+      }
+#endif
+      goto respond;
+
+    case 'S':                  /* status */
+      DEBUG ("rmtd: S\n");
+      {
+#ifdef MTIOCGET
+       struct mtget mtget;
+       if (ioctl (tape, MTIOCGET, (char *) &mtget) < 0)
+         goto ioerror;
+       rval = sizeof (mtget);
+       (void) sprintf (resp, "A%d\n", rval);
+       (void) write (1, resp, strlen (resp));
+       (void) write (1, (char *) &mtget, sizeof (mtget));
+#endif
+       goto top;
+      }
+
+    default:
+      DEBUG1 ("rmtd: garbage command %c\n", c);
+      exit (3);
+    }
+respond:
+  DEBUG1 ("rmtd: A %d\n", rval);
+  (void) sprintf (resp, "A%d\n", rval);
+  (void) write (1, resp, strlen (resp));
+  goto top;
+ioerror:
+  error (errno);
+  goto top;
+}
+
+void
+getstring (bp)
+     char *bp;
+{
+  int i;
+  char *cp = bp;
+
+  for (i = 0; i < SSIZE; i++)
+    {
+      if (read (0, cp + i, 1) != 1)
+       exit (0);
+      if (cp[i] == '\n')
+       break;
+    }
+  cp[i] = '\0';
+}
+
+char *
+checkbuf (record, size)
+     char *record;
+     int size;
+{
+  if (size <= maxrecsize)
+    return (record);
+  if (record != 0)
+    free (record);
+  record = malloc (size);
+  if (record == 0)
+    {
+      DEBUG ("rmtd: cannot allocate buffer space\n");
+      exit (4);
+    }
+  maxrecsize = size;
+#ifdef SO_RCVBUF
+  while (size > 1024 &&
+   setsockopt (0, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (size)) < 0)
+    size -= 1024;
+#else
+  size = 1 + ((size - 1) % 1024);
+#endif
+  return (record);
+}
+
+void
+error (num)
+     int num;
+{
+
+  DEBUG2 ("rmtd: E %d (%s)\n", num, sys_errlist[num]);
+  (void) sprintf (resp, "E%d\n%s\n", num, sys_errlist[num]);
+  (void) write (1, resp, strlen (resp));
+}
diff --git a/gnu/usr.bin/cpio/rmt.h b/gnu/usr.bin/cpio/rmt.h
new file mode 100644 (file)
index 0000000..2155223
--- /dev/null
@@ -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/gnu/usr.bin/cpio/rtapelib.c b/gnu/usr.bin/cpio/rtapelib.c
new file mode 100644 (file)
index 0000000..eece76f
--- /dev/null
@@ -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;
+\f
+/* 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/gnu/usr.bin/cpio/stripslash.c b/gnu/usr.bin/cpio/stripslash.c
new file mode 100644 (file)
index 0000000..2971d4c
--- /dev/null
@@ -0,0 +1,39 @@
+/* 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.  */
+
+#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/gnu/usr.bin/cpio/system.h b/gnu/usr.bin/cpio/system.h
new file mode 100644 (file)
index 0000000..abe732d
--- /dev/null
@@ -0,0 +1,139 @@
+/* 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
+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
+
+#ifdef __MSDOS__
+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/gnu/usr.bin/cpio/tar.c b/gnu/usr.bin/cpio/tar.c
new file mode 100644 (file)
index 0000000..16eeee0
--- /dev/null
@@ -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);
+
+  copy_buf_out ((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
+
+  copy_in_buf ((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!  */
+      copy_in_buf ((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);
+         copy_in_buf (((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/gnu/usr.bin/cpio/tar.h b/gnu/usr.bin/cpio/tar.h
new file mode 100644 (file)
index 0000000..411579c
--- /dev/null
@@ -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/gnu/usr.bin/cpio/tarhdr.h b/gnu/usr.bin/cpio/tarhdr.h
new file mode 100644 (file)
index 0000000..54de0d6
--- /dev/null
@@ -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/gnu/usr.bin/cpio/tcexparg.c b/gnu/usr.bin/cpio/tcexparg.c
new file mode 100644 (file)
index 0000000..c5d88f0
--- /dev/null
@@ -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/gnu/usr.bin/cpio/userspec.c b/gnu/usr.bin/cpio/userspec.c
new file mode 100644 (file)
index 0000000..44d7d91
--- /dev/null
@@ -0,0 +1,180 @@
+/* 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>.  */
+\f
+#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>
+#else
+char *malloc ();
+#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
+
+#define isdigit(c) ((c) >= '0' && (c) <= '9')
+
+char *strdup ();
+static int isnumber ();
+
+/* 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.
+   Might write NULs into NAME.
+
+   Return NULL if successful, a static error message string if not.  */
+
+char *
+parse_user_spec (name, uid, gid, username, groupname)
+     char *name;
+     uid_t *uid;
+     gid_t *gid;
+     char **username, **groupname;
+{
+  static char *tired = "virtual memory exhausted";
+  struct passwd *pwd;
+  struct group *grp;
+  char *cp;
+  int use_login_group = 0;
+
+  *username = *groupname = NULL;
+
+  /* Check whether a group is given.  */
+  cp = index (name, ':');
+  if (cp == NULL)
+    cp = index (name, '.');
+  if (cp != NULL)
+    {
+      *cp++ = '\0';
+      if (*cp == '\0')
+       {
+         if (cp == name + 1)
+           /* Neither user nor group given, just "." or ":".  */
+           return "can not omit both user and group";
+         else
+           /* "user.".  */
+           use_login_group = 1;
+       }
+      else
+       {
+         /* Explicit group.  */
+         *groupname = strdup (cp);
+         if (*groupname == NULL)
+           return tired;
+         grp = getgrnam (cp);
+         if (grp == NULL)
+           {
+             if (!isnumber (cp))
+               return "invalid group";
+             *gid = atoi (cp);
+           }
+         else
+           *gid = grp->gr_gid;
+         endgrent ();          /* Save a file descriptor.  */
+       }
+    }
+
+  /* Parse the user name, now that any group has been removed.  */
+
+  if (name[0] == '\0')
+    /* No user name was given, just a group.  */
+    return NULL;
+
+  *username = strdup (name);
+  if (*username == NULL)
+    return tired;
+
+  pwd = getpwnam (name);
+  if (pwd == NULL)
+    {
+      if (!isnumber (name))
+       return "invalid user";
+      if (use_login_group)
+       return "cannot get the login group of a numeric UID";
+      *uid = atoi (name);
+    }
+  else
+    {
+      *uid = pwd->pw_uid;
+      if (use_login_group)
+       {
+         *gid = pwd->pw_gid;
+         grp = getgrgid (pwd->pw_gid);
+         if (grp == NULL)
+           {
+             *groupname = malloc (15);
+             if (*groupname == NULL)
+               return tired;
+             sprintf (*groupname, "%u", pwd->pw_gid);
+           }
+         else
+           {
+             *groupname = strdup (grp->gr_name);
+             if (*groupname == NULL)
+               return tired;
+           }
+         endgrent ();
+       }
+    }
+  endpwent ();
+  return NULL;
+}
+
+/* Return nonzero if STR represents an unsigned decimal integer,
+   otherwise return 0. */
+
+static int
+isnumber (str)
+     char *str;
+{
+  for (; *str; str++)
+    if (!isdigit (*str))
+      return 0;
+  return 1;
+}
diff --git a/gnu/usr.bin/cpio/util.c b/gnu/usr.bin/cpio/util.c
new file mode 100644 (file)
index 0000000..52e3e85
--- /dev/null
@@ -0,0 +1,1102 @@
+/* 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 empty_output_buffer_swap ();
+static void hash_insert ();
+
+/* Write `output_size' bytes of `output_buffer' to file
+   descriptor OUT_DES and reset `output_size' and `out_buff'.  */
+
+void
+empty_output_buffer (out_des)
+     int out_des;
+{
+  int bytes_written;
+
+#ifdef BROKEN_LONG_TAPE_DRIVER
+  static long output_bytes_before_lseek = 0;
+#endif
+
+  if (swapping_halfwords || swapping_bytes)
+    {
+      empty_output_buffer_swap (out_des);
+      return;
+    }
+
+#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 > 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) < 0L)
+    {
+      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 with byte and/or halfword swapping and reset
+   `output_size' and `out_buff'.  This routine should not be called
+   with `swapping_bytes' set unless the caller knows that the
+   file being written has an even number of bytes, and it should not be
+   called with `swapping_halfwords' set unless the caller knows
+   that the file being written has a length divisible by 4.  If either
+   of those restrictions are not met, bytes may be lost in the output
+   file.  OUT_DES must refer to a file that we are creating during
+   a process_copy_in, so we don't have to check for end of media
+   errors or be careful about only writing in blocks of `output_size'
+   bytes.  */
+
+static void
+empty_output_buffer_swap (out_des)
+     int out_des;
+{
+  /* Since `output_size' might not be divisible by 4 or 2, we might
+     not be able to be able to swap all the bytes and halfwords in
+     `output_buffer' (e.g., if `output_size' is odd), so we might not be
+     able to write them all.  We will swap and write as many bytes as
+     we can, and save the rest in `left_overs' for the next time we are
+     called.  */
+  static char left_overs[4];
+  static int left_over_bytes = 0;
+
+  int bytes_written;
+  int complete_halfwords;
+  int complete_words;
+  int extra_bytes;
+
+  output_bytes += output_size;
+
+  out_buff = output_buffer;
+
+  if (swapping_halfwords)
+    {
+      if (left_over_bytes != 0)
+       {
+         while (output_size > 0 && left_over_bytes < 4)
+           {
+             left_overs[left_over_bytes++] = *out_buff++;
+             --output_size;
+           }
+         if (left_over_bytes < 4)
+           {
+             out_buff = output_buffer;
+             output_size = 0;
+             return;
+           }
+         swahw_array (left_overs, 1);
+         if (swapping_bytes)
+           swab_array (left_overs, 2);
+         bytes_written = rmtwrite (out_des, left_overs, 4);
+         if (bytes_written != 4)
+           error (1, errno, "write error");
+         left_over_bytes = 0;
+       }
+      complete_words = output_size / 4;
+      if (complete_words > 0)
+       {
+         swahw_array (out_buff, complete_words);
+         if (swapping_bytes)
+           swab_array (out_buff, 2 * complete_words);
+         bytes_written = rmtwrite (out_des, out_buff, 4 * complete_words);
+         if (bytes_written != (4 * complete_words))
+           error (1, errno, "write error");
+       }
+      out_buff += (4 * complete_words);
+      extra_bytes = output_size % 4;
+      while (extra_bytes > 0)
+       {
+         left_overs[left_over_bytes++] = *out_buff++;
+         --extra_bytes;
+       }
+
+    }
+  else
+    {
+      if (left_over_bytes != 0)
+       {
+         while (output_size > 0 && left_over_bytes < 2)
+           {
+             left_overs[left_over_bytes++] = *out_buff++;
+             --output_size;
+           }
+         if (left_over_bytes < 2)
+           {
+             out_buff = output_buffer;
+             output_size = 0;
+             return;
+           }
+         swab_array (left_overs, 1);
+         bytes_written = rmtwrite (out_des, left_overs, 2);
+         if (bytes_written != 2)
+           error (1, errno, "write error");
+         left_over_bytes = 0;
+       }
+      complete_halfwords = output_size / 2;
+      if (complete_halfwords > 0)
+       {
+         swab_array (out_buff, complete_halfwords);
+         bytes_written = rmtwrite (out_des, out_buff, 2 * complete_halfwords);
+         if (bytes_written != (2 * complete_halfwords))
+           error (1, errno, "write error");
+       }
+      out_buff += (2 * complete_halfwords);
+      extra_bytes = output_size % 2;
+      while (extra_bytes > 0)
+       {
+         left_overs[left_over_bytes++] = *out_buff++;
+         --extra_bytes;
+       }
+    }
+
+  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
+
+void
+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) < 0L)
+    {
+      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;
+}
+\f
+/* 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
+copy_buf_out (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)
+       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
+copy_in_buf (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)
+       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
+peek_in_buf (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) < 0L)
+    {
+      lseek(in_des, 0L, SEEK_SET);
+      input_bytes_before_lseek = 0;
+    }
+#endif
+
+  while (input_size < num_bytes)
+    {
+      append_buf = in_buff + input_size;
+      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;
+}
+\f
+/* Skip the next NUM_BYTES bytes of file descriptor IN_DES.  */
+
+void
+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)
+       fill_input_buffer (in_des, io_block_size);
+      if (bytes_left < input_size)
+       space_left = bytes_left;
+      else
+       space_left = input_size;
+      in_buff += space_left;
+      input_size -= space_left;
+      bytes_left -= space_left;
+    }
+}
+\f
+/* 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 (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)
+       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;
+       }
+      copy_buf_out (in_buff, out_des, size);
+      num_bytes -= size;
+      input_size -= size;
+      in_buff += size;
+    }
+}
+\f
+/* 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");
+      copy_buf_out (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;
+}
+\f
+/* 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, message);
+    }
+}
+
+#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 */
+
+#ifdef __MSDOS__
+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
diff --git a/gnu/usr.bin/cpio/version.c b/gnu/usr.bin/cpio/version.c
new file mode 100644 (file)
index 0000000..38a63f2
--- /dev/null
@@ -0,0 +1,2 @@
+/* The version number of cpio and mt.  */
+char *version_string = "version 2.3\n";
diff --git a/gnu/usr.bin/cpio/xmalloc.c b/gnu/usr.bin/cpio/xmalloc.c
new file mode 100644 (file)
index 0000000..f989004
--- /dev/null
@@ -0,0 +1,65 @@
+/* xmalloc.c -- malloc with out of memory checking
+   Copyright (C) 1990, 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.  */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+char *malloc ();
+char *realloc ();
+void free ();
+#endif
+
+void error ();
+
+/* Allocate N bytes of memory dynamically, with error checking.  */
+
+char *
+xmalloc (n)
+     unsigned n;
+{
+  char *p;
+
+  p = malloc (n);
+  if (p == 0)
+    /* Must exit with 2 for `cmp'.  */
+    error (2, 0, "virtual memory exhausted");
+  return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+   with error checking.
+   If P is NULL, run xmalloc.
+   If N is 0, run free and return NULL.  */
+
+char *
+xrealloc (p, n)
+     char *p;
+     unsigned n;
+{
+  if (p == 0)
+    return xmalloc (n);
+  if (n == 0)
+    {
+      free (p);
+      return 0;
+    }
+  p = realloc (p, n);
+  if (p == 0)
+    /* Must exit with 2 for `cmp'.  */
+    error (2, 0, "virtual memory exhausted");
+  return p;
+}
diff --git a/gnu/usr.bin/cpio/xstrdup.c b/gnu/usr.bin/cpio/xstrdup.c
new file mode 100644 (file)
index 0000000..9588bc7
--- /dev/null
@@ -0,0 +1,32 @@
+/* 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.  */
+
+#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);
+}