diff options
author | cvs2svn <cvs2svn@FreeBSD.org> | 1993-11-12 07:06:36 +0000 |
---|---|---|
committer | cvs2svn <cvs2svn@FreeBSD.org> | 1993-11-12 07:06:36 +0000 |
commit | 0b7c01234953e742657c32935cc28e28f14d3738 (patch) | |
tree | c4be84a06b643b8028d387d7baa15838f6c8f241 /gnu | |
parent | 0ca877b4a343154d7b89f6b6a282ebaa63bf1275 (diff) | |
download | FreeBSD-src-0b7c01234953e742657c32935cc28e28f14d3738.zip FreeBSD-src-0b7c01234953e742657c32935cc28e28f14d3738.tar.gz |
This commit was manufactured by cvs2svn to create branch 'GNU'.
Diffstat (limited to 'gnu')
47 files changed, 14698 insertions, 0 deletions
diff --git a/gnu/usr.bin/cpio/COPYING b/gnu/usr.bin/cpio/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/gnu/usr.bin/cpio/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gnu/usr.bin/cpio/COPYING.LIB b/gnu/usr.bin/cpio/COPYING.LIB new file mode 100644 index 0000000..eb685a5 --- /dev/null +++ b/gnu/usr.bin/cpio/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/gnu/usr.bin/cpio/ChangeLog b/gnu/usr.bin/cpio/ChangeLog new file mode 100644 index 0000000..9b18d4f --- /dev/null +++ b/gnu/usr.bin/cpio/ChangeLog @@ -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. + +Local Variables: +mode: indented-text +left-margin: 8 +version-control: never +End: diff --git a/gnu/usr.bin/cpio/NEWS b/gnu/usr.bin/cpio/NEWS new file mode 100644 index 0000000..2648c84 --- /dev/null +++ b/gnu/usr.bin/cpio/NEWS @@ -0,0 +1,55 @@ + +Major changes in version 2.3: + +* in newc and crc format archives, only store 1 copy of multiply linked files +* handle multiply linked devices properly +* handle multiply linked files with cpio -pl even when the source and + destination are on different file systems +* support HPUX Context Dependent Files +* read and write HPUX cpio archives +* read System V.4 POSIX tar archives and HPUX POSIX tar archives +* use rmdir, instead of unlink, to delete existing directories + +Major changes in version 2.2: + +* handle link counts correctly when reading binary cpio archives +* configure checks for some libraries that SVR4 needs + +Major changes in version 2.1: + +* cpio can access remote non-device files as well as remote devices +* fix bugs in the MS-DOS port +* add --swap equivalent to -b option + +Version 2.0 adds the following features: + +Support for the SVR4 cpio formats, which can store inodes >65535, and +for traditional and POSIX tar archives. Also adds these options: + +-A --append append to instead of replacing the archive +-V --dot print a dot for each file processed +-H --format select archive format +-C --io-size select I/O block size in bytes +-M --message print a message at end of media volumes +--no-preserve-owner don't change files' owners when extracting +-R --owner set files' owners when extracting +-E --pattern-file list of shell filename patterns to process +-s --swap-bytes handle byte-order differences when extracting files +-S --swap-halfwords ditto +-b like -sS +-I input archive filename +-k recognize corrupted archives (we alawys do it, though) +-O output archive filename + +Some options of previous versions have been renamed in 2.0: + +--binary was replaced by --format=bin +--portability was replaced by --format=odc + +Some options have changed meaning in 2.0, for SVR4 compatibility: + +-O used to select the binary archive format, now selects the output file +-V used to print the version number, now prints a dot for each file + +Version 2.0 also fixes several bugs in the handling of files with +multiple links and of multi-volume archives on floppy disks. diff --git a/gnu/usr.bin/cpio/README b/gnu/usr.bin/cpio/README new file mode 100644 index 0000000..83b5228 --- /dev/null +++ b/gnu/usr.bin/cpio/README @@ -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 index 0000000..c04c0ef --- /dev/null +++ b/gnu/usr.bin/cpio/alloca.c @@ -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 index 0000000..5196c5d --- /dev/null +++ b/gnu/usr.bin/cpio/copyin.c @@ -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 (×, 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 (¤t_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, ×) < 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, ×) < 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, ×) < 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); +} + +/* 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 (×, 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, ×) < 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 index 0000000..f763f2b --- /dev/null +++ b/gnu/usr.bin/cpio/copyout.c @@ -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 (×, 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, ×) < 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 (×, 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, ×) < 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 index 0000000..afd5753 --- /dev/null +++ b/gnu/usr.bin/cpio/copypass.c @@ -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 (×, 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, ×) < 0) + error (0, errno, "%s", input_name.ds_string); + if (utime (output_name.ds_string, ×) < 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, ×) < 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, ×) < 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, ×) < 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); +} + +/* Try and create a hard link from FILE_NAME to another file + with the given major/minor device number and inode. If no other + file with the same major/minor/inode numbers is known, add this file + to the list of known files and associated major/minor/inode numbers + and return -1. If another file with the same major/minor/inode + numbers is found, try and create another link to it using + link_to_name, and return 0 for success and -1 for failure. */ + +int +link_to_maj_min_ino (file_name, st_dev_maj, st_dev_min, st_ino) + char *file_name; + int st_dev_maj; + int st_dev_min; + int st_ino; +{ + int link_res; + char *link_name; + link_res = -1; +#ifndef __MSDOS__ + /* Is the file a link to a previously copied file? */ + link_name = find_inode_file (st_ino, + st_dev_maj, + st_dev_min); + if (link_name == NULL) + add_inode (st_ino, file_name, + st_dev_maj, + st_dev_min); + else + link_res = link_to_name (file_name, link_name); +#endif + return link_res; +} + +/* Try and create a hard link from LINK_NAME to LINK_TARGET. If + `create_dir_flag' is set, any non-existent (parent) directories + needed by LINK_NAME will be created. If the link is successfully + created and `verbose_flag' is set, print "LINK_TARGET linked to LINK_NAME\n". + If the link can not be created and `link_flag' is set, print + "cannot link LINK_TARGET to LINK_NAME\n". Return 0 if the link + is created, -1 otherwise. */ + +int +link_to_name (link_name, link_target) + char *link_name; + char *link_target; +{ + int res; +#ifdef __MSDOS__ + res = -1; +#else /* not __MSDOS__ */ + res = link (link_target, link_name); + if (res < 0 && create_dir_flag) + { + create_all_directories (link_name); + res = link (link_target, link_name); + } + if (res == 0) + { + if (verbose_flag) + error (0, 0, "%s linked to %s", + link_target, link_name); + } + else if (link_flag) + { + error (0, errno, "cannot link %s to %s", + link_target, link_name); + } +#endif /* not __MSDOS__ */ + return res; +} diff --git a/gnu/usr.bin/cpio/cpio.1 b/gnu/usr.bin/cpio/cpio.1 new file mode 100644 index 0000000..7ef74c4 --- /dev/null +++ b/gnu/usr.bin/cpio/cpio.1 @@ -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 index 0000000..537da72 --- /dev/null +++ b/gnu/usr.bin/cpio/cpio.h @@ -0,0 +1,69 @@ +/* Extended cpio format from POSIX.1. + Copyright (C) 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _CPIO_H + +#define _CPIO_H 1 + +/* A cpio archive consists of a sequence of files. + Each file has a 76 byte header, + a variable length, NUL terminated filename, + and variable length file data. + A header for a filename "TRAILER!!!" indicates the end of the archive. */ + +/* All the fields in the header are ISO 646 (approximately ASCII) strings + of octal numbers, left padded, not NUL terminated. + + Field Name Length in Bytes Notes + c_magic 6 must be "070707" + c_dev 6 + c_ino 6 + c_mode 6 see below for value + c_uid 6 + c_gid 6 + c_nlink 6 + c_rdev 6 only valid for chr and blk special files + c_mtime 11 + c_namesize 6 count includes terminating NUL in pathname + c_filesize 11 must be 0 for FIFOs and directories */ + +/* Values for c_mode, OR'd together: */ + +#define C_IRUSR 000400 +#define C_IWUSR 000200 +#define C_IXUSR 000100 +#define C_IRGRP 000040 +#define C_IWGRP 000020 +#define C_IXGRP 000010 +#define C_IROTH 000004 +#define C_IWOTH 000002 +#define C_IXOTH 000001 + +#define C_ISUID 004000 +#define C_ISGID 002000 +#define C_ISVTX 001000 + +#define C_ISBLK 060000 +#define C_ISCHR 020000 +#define C_ISDIR 040000 +#define C_ISFIFO 010000 +#define C_ISSOCK 0140000 +#define C_ISLNK 0120000 +#define C_ISCTG 0110000 +#define C_ISREG 0100000 + +#endif /* cpio.h */ diff --git a/gnu/usr.bin/cpio/cpiohdr.h b/gnu/usr.bin/cpio/cpiohdr.h new file mode 100644 index 0000000..9694af6 --- /dev/null +++ b/gnu/usr.bin/cpio/cpiohdr.h @@ -0,0 +1,90 @@ +/* Extended cpio header from POSIX.1. + Copyright (C) 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _CPIOHDR_H + +#define _CPIOHDR_H 1 + +#include <cpio.h> + +struct old_cpio_header +{ + unsigned short c_magic; + short c_dev; + unsigned short c_ino; + unsigned short c_mode; + unsigned short c_uid; + unsigned short c_gid; + unsigned short c_nlink; + short c_rdev; + unsigned short c_mtimes[2]; + unsigned short c_namesize; + unsigned short c_filesizes[2]; + unsigned long c_mtime; /* Long-aligned copy of `c_mtimes'. */ + unsigned long c_filesize; /* Long-aligned copy of `c_filesizes'. */ + char *c_name; +}; + +/* "New" portable format and CRC format: + + Each file has a 110 byte header, + a variable length, NUL terminated filename, + and variable length file data. + A header for a filename "TRAILER!!!" indicates the end of the archive. */ + +/* All the fields in the header are ISO 646 (approximately ASCII) strings + of hexadecimal numbers, left padded, not NUL terminated. + + Field Name Length in Bytes Notes + c_magic 6 "070701" for "new" portable format + "070702" for CRC format + c_ino 8 + c_mode 8 + c_uid 8 + c_gid 8 + c_nlink 8 + c_mtime 8 + c_filesize 8 must be 0 for FIFOs and directories + c_maj 8 + c_min 8 + c_rmaj 8 only valid for chr and blk special files + c_rmin 8 only valid for chr and blk special files + c_namesize 8 count includes terminating NUL in pathname + c_chksum 8 0 for "new" portable format; for CRC format + the sum of all the bytes in the file */ + +struct new_cpio_header +{ + unsigned short c_magic; + unsigned long c_ino; + unsigned long c_mode; + unsigned long c_uid; + unsigned long c_gid; + unsigned long c_nlink; + unsigned long c_mtime; + unsigned long c_filesize; + long c_dev_maj; + long c_dev_min; + long c_rdev_maj; + long c_rdev_min; + unsigned long c_namesize; + unsigned long c_chksum; + char *c_name; + char *c_tar_linkname; +}; + +#endif /* cpiohdr.h */ diff --git a/gnu/usr.bin/cpio/defer.c b/gnu/usr.bin/cpio/defer.c new file mode 100644 index 0000000..efe60e0 --- /dev/null +++ b/gnu/usr.bin/cpio/defer.c @@ -0,0 +1,43 @@ +/* defer.c - handle "defered" links in newc and crc archives + Copyright (C) 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include <sys/types.h> +#include "system.h" +#include "cpiohdr.h" +#include "extern.h" +#include "defer.h" + +struct deferment * +create_deferment (file_hdr) + struct new_cpio_header *file_hdr; +{ + struct deferment *d; + d = (struct deferment *) xmalloc (sizeof (struct deferment) ); + d->header = *file_hdr; + d->header.c_name = (char *) xmalloc (strlen (file_hdr->c_name) + 1); + strcpy (d->header.c_name, file_hdr->c_name); + return d; +} + +void +free_deferment (d) + struct deferment *d; +{ + free (d->header.c_name); + free (d); +} diff --git a/gnu/usr.bin/cpio/defer.h b/gnu/usr.bin/cpio/defer.h new file mode 100644 index 0000000..89abffe --- /dev/null +++ b/gnu/usr.bin/cpio/defer.h @@ -0,0 +1,8 @@ +struct deferment + { + struct deferment *next; + struct new_cpio_header header; + }; + +struct deferment *create_deferment P_((struct new_cpio_header *file_hdr)); +void free_deferment P_((struct deferment *d)); diff --git a/gnu/usr.bin/cpio/dirname.c b/gnu/usr.bin/cpio/dirname.c new file mode 100644 index 0000000..5a92ce5 --- /dev/null +++ b/gnu/usr.bin/cpio/dirname.c @@ -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 index 0000000..26d6bbc --- /dev/null +++ b/gnu/usr.bin/cpio/dstring.c @@ -0,0 +1,114 @@ +/* dstring.c - The dynamic string handling routines used by cpio. + Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#if defined(HAVE_STRING_H) || defined(STDC_HEADERS) +#include <string.h> +#else +#include <strings.h> +#endif +#include "dstring.h" + +#if __STDC__ +# define P_(s) s +#else +# define P_(s) () +#endif +char *xmalloc P_((unsigned n)); +char *xrealloc P_((char *p, unsigned n)); + +/* Initialiaze dynamic string STRING with space for SIZE characters. */ + +void +ds_init (string, size) + dynamic_string *string; + int size; +{ + string->ds_length = size; + string->ds_string = (char *) xmalloc (size); +} + +/* Expand dynamic string STRING, if necessary, to hold SIZE characters. */ + +void +ds_resize (string, size) + dynamic_string *string; + int size; +{ + if (size > string->ds_length) + { + string->ds_length = size; + string->ds_string = (char *) xrealloc ((char *) string->ds_string, size); + } +} + +/* Dynamic string S gets a string terminated by the EOS character + (which is removed) from file F. S will increase + in size during the function if the string from F is longer than + the current size of S. + Return NULL if end of file is detected. Otherwise, + Return a pointer to the null-terminated string in S. */ + +char * +ds_fgetstr (f, s, eos) + FILE *f; + dynamic_string *s; + char eos; +{ + int insize; /* Amount needed for line. */ + int strsize; /* Amount allocated for S. */ + int next_ch; + + /* Initialize. */ + insize = 0; + strsize = s->ds_length; + + /* Read the input string. */ + next_ch = getc (f); + while (next_ch != eos && next_ch != EOF) + { + if (insize >= strsize - 1) + { + ds_resize (s, strsize * 2 + 2); + strsize = s->ds_length; + } + s->ds_string[insize++] = next_ch; + next_ch = getc (f); + } + s->ds_string[insize++] = '\0'; + + if (insize == 1 && next_ch == EOF) + return NULL; + else + return s->ds_string; +} + +char * +ds_fgets (f, s) + FILE *f; + dynamic_string *s; +{ + return ds_fgetstr (f, s, '\n'); +} + +char * +ds_fgetname (f, s) + FILE *f; + dynamic_string *s; +{ + return ds_fgetstr (f, s, '\0'); +} diff --git a/gnu/usr.bin/cpio/dstring.h b/gnu/usr.bin/cpio/dstring.h new file mode 100644 index 0000000..369da0b --- /dev/null +++ b/gnu/usr.bin/cpio/dstring.h @@ -0,0 +1,49 @@ +/* dstring.h - Dynamic string handling include file. Requires strings.h. + Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef NULL +#define NULL 0 +#endif + +/* A dynamic string consists of record that records the size of an + allocated string and the pointer to that string. The actual string + is a normal zero byte terminated string that can be used with the + usual string functions. The major difference is that the + dynamic_string routines know how to get more space if it is needed + by allocating new space and copying the current string. */ + +typedef struct +{ + int ds_length; /* Actual amount of storage allocated. */ + char *ds_string; /* String. */ +} dynamic_string; + + +/* Macros that look similar to the original string functions. + WARNING: These macros work only on pointers to dynamic string records. + If used with a real record, an "&" must be used to get the pointer. */ +#define ds_strlen(s) strlen ((s)->ds_string) +#define ds_strcmp(s1, s2) strcmp ((s1)->ds_string, (s2)->ds_string) +#define ds_strncmp(s1, s2, n) strncmp ((s1)->ds_string, (s2)->ds_string, n) +#define ds_index(s, c) index ((s)->ds_string, c) +#define ds_rindex(s, c) rindex ((s)->ds_string, c) + +void ds_init (); +void ds_resize (); +char *ds_fgetname (); +char *ds_fgets (); +char *ds_fgetstr (); diff --git a/gnu/usr.bin/cpio/error.c b/gnu/usr.bin/cpio/error.c new file mode 100644 index 0000000..e849c5b --- /dev/null +++ b/gnu/usr.bin/cpio/error.c @@ -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 index 0000000..50b152c --- /dev/null +++ b/gnu/usr.bin/cpio/extern.h @@ -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) (); + +#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 index 0000000..9293af6 --- /dev/null +++ b/gnu/usr.bin/cpio/filemode.c @@ -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. */ + +#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 index 0000000..46a79a9 --- /dev/null +++ b/gnu/usr.bin/cpio/filetypes.h @@ -0,0 +1,84 @@ +/* filetypes.h - deal with POSIX annoyances + Copyright (C) 1991 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Include sys/types.h and sys/stat.h before this file. */ + +#ifndef S_ISREG /* Doesn't have POSIX.1 stat stuff. */ +#define mode_t unsigned short +#endif + +/* Define the POSIX macros for systems that lack them. */ +#if !defined(S_ISBLK) && defined(S_IFBLK) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#endif +#if !defined(S_ISCHR) && defined(S_IFCHR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISDIR) && defined(S_IFDIR) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) && defined(S_IFREG) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISFIFO) && defined(S_IFIFO) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISLNK) && defined(S_IFLNK) +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) && defined(S_IFSOCK) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX network special */ +#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) +#endif + +/* Define the file type bits used in cpio archives. + They have the same values as the S_IF bits in traditional Unix. */ + +#define CP_IFMT 0170000 /* Mask for all file type bits. */ + +#if defined(S_ISBLK) +#define CP_IFBLK 0060000 +#endif +#if defined(S_ISCHR) +#define CP_IFCHR 0020000 +#endif +#if defined(S_ISDIR) +#define CP_IFDIR 0040000 +#endif +#if defined(S_ISREG) +#define CP_IFREG 0100000 +#endif +#if defined(S_ISFIFO) +#define CP_IFIFO 0010000 +#endif +#if defined(S_ISLNK) +#define CP_IFLNK 0120000 +#endif +#if defined(S_ISSOCK) +#define CP_IFSOCK 0140000 +#endif +#if defined(S_ISNWK) +#define CP_IFNWK 0110000 +#endif + +#ifndef S_ISLNK +#define lstat stat +#endif +int lstat (); +int stat (); diff --git a/gnu/usr.bin/cpio/getopt.c b/gnu/usr.bin/cpio/getopt.c new file mode 100644 index 0000000..2867a90 --- /dev/null +++ b/gnu/usr.bin/cpio/getopt.c @@ -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. */ + +#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; + +#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. */ + +/* 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; +} + +/* 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__. */ + +#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 index 0000000..45541f5 --- /dev/null +++ b/gnu/usr.bin/cpio/getopt.h @@ -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 index 0000000..a32615c --- /dev/null +++ b/gnu/usr.bin/cpio/getopt1.c @@ -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. */ + +#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__. */ + +#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 index 0000000..d4b5441 --- /dev/null +++ b/gnu/usr.bin/cpio/global.c @@ -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 index 0000000..dd9c366 --- /dev/null +++ b/gnu/usr.bin/cpio/idcache.c @@ -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 index 0000000..78b5fc5 --- /dev/null +++ b/gnu/usr.bin/cpio/main.c @@ -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, ©_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 index 0000000..bdf6829 --- /dev/null +++ b/gnu/usr.bin/cpio/makepath.c @@ -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/rmt.h b/gnu/usr.bin/cpio/rmt.h new file mode 100644 index 0000000..2155223 --- /dev/null +++ b/gnu/usr.bin/cpio/rmt.h @@ -0,0 +1,98 @@ +/* Definitions for communicating with a remote tape drive. + Copyright (C) 1988, 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#if !defined(_POSIX_VERSION) +#ifdef __MSDOS__ +#include <io.h> +#else /* !__MSDOS__ */ +extern off_t lseek (); +#endif /* __MSDOS__ */ +#endif /* _POSIX_VERSION */ + +#ifdef NO_REMOTE +#define _isrmt(f) 0 +#define rmtopen open +#define rmtaccess access +#define rmtstat stat +#define rmtcreat creat +#define rmtlstat lstat +#define rmtread read +#define rmtwrite write +#define rmtlseek lseek +#define rmtclose close +#define rmtioctl ioctl +#define rmtdup dup +#define rmtfstat fstat +#define rmtfcntl fcntl +#define rmtisatty isatty + +#else /* !NO_REMOTE */ + +#define __REM_BIAS 128 +#define RMTIOCTL + +#ifndef O_CREAT +#define O_CREAT 01000 +#endif + +extern char *__rmt_path; + +#if defined(STDC_HEADERS) || defined(HAVE_STRING_H) +#include <string.h> +#ifndef index +#define index strchr +#endif +#else +extern char *index (); +#endif + +#define _remdev(path) (!f_force_local && (__rmt_path=index(path, ':'))) +#define _isrmt(fd) ((fd) >= __REM_BIAS) + +#define rmtopen(path,oflag,mode) (_remdev(path) ? __rmt_open(path, oflag, mode, __REM_BIAS) : open(path, oflag, mode)) +#define rmtaccess(path, amode) (_remdev(path) ? 0 : access(path, amode)) +#define rmtstat(path, buf) (_remdev(path) ? (errno = EOPNOTSUPP), -1 : stat(path, buf)) +#define rmtcreat(path, mode) (_remdev(path) ? __rmt_open (path, 1 | O_CREAT, mode, __REM_BIAS) : creat(path, mode)) +#define rmtlstat(path,buf) (_remdev(path) ? (errno = EOPNOTSUPP), -1 : lstat(path,buf)) + +#define rmtread(fd, buf, n) (_isrmt(fd) ? __rmt_read(fd - __REM_BIAS, buf, n) : read(fd, buf, n)) +#define rmtwrite(fd, buf, n) (_isrmt(fd) ? __rmt_write(fd - __REM_BIAS, buf, n) : write(fd, buf, n)) +#define rmtlseek(fd, off, wh) (_isrmt(fd) ? __rmt_lseek(fd - __REM_BIAS, off, wh) : lseek(fd, off, wh)) +#define rmtclose(fd) (_isrmt(fd) ? __rmt_close(fd - __REM_BIAS) : close(fd)) +#ifdef RMTIOCTL +#define rmtioctl(fd,req,arg) (_isrmt(fd) ? __rmt_ioctl(fd - __REM_BIAS, req, arg) : ioctl(fd, req, arg)) +#else +#define rmtioctl(fd,req,arg) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : ioctl(fd, req, arg)) +#endif +#define rmtdup(fd) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : dup(fd)) +#define rmtfstat(fd, buf) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : fstat(fd, buf)) +#define rmtfcntl(fd,cmd,arg) (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : fcntl (fd, cmd, arg)) +#define rmtisatty(fd) (_isrmt(fd) ? 0 : isatty(fd)) + +#undef RMTIOCTL + +int __rmt_open (); +int __rmt_close (); +int __rmt_read (); +int __rmt_write (); +long __rmt_lseek (); +int __rmt_ioctl (); +#endif /* !NO_REMOTE */ diff --git a/gnu/usr.bin/cpio/rtapelib.c b/gnu/usr.bin/cpio/rtapelib.c new file mode 100644 index 0000000..eece76f --- /dev/null +++ b/gnu/usr.bin/cpio/rtapelib.c @@ -0,0 +1,582 @@ +/* Functions for communicating with a remote tape drive. + Copyright (C) 1988, 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* The man page rmt(8) for /etc/rmt documents the remote mag tape + protocol which rdump and rrestore use. Unfortunately, the man + page is *WRONG*. The author of the routines I'm including originally + wrote his code just based on the man page, and it didn't work, so he + went to the rdump source to figure out why. The only thing he had to + change was to check for the 'F' return code in addition to the 'E', + and to separate the various arguments with \n instead of a space. I + personally don't think that this is much of a problem, but I wanted to + point it out. -- Arnold Robbins + + Originally written by Jeff Lee, modified some by Arnold Robbins. + Redone as a library that can replace open, read, write, etc., by + Fred Fish, with some additional work by Arnold Robbins. + Modified to make all rmtXXX calls into macros for speed by Jay Fenlason. + Use -DHAVE_NETDB_H for rexec code, courtesy of Dan Kegel, srs!dan. */ + +#include <stdio.h> +#include <sys/types.h> +#include <signal.h> + +#ifdef HAVE_SYS_MTIO_H +#include <sys/ioctl.h> +#include <sys/mtio.h> +#endif + +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif + +#include <errno.h> +#include <setjmp.h> +#include <sys/stat.h> + +#ifndef errno +extern int errno; +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef STDC_HEADERS +#include <string.h> +#include <stdlib.h> +#endif + +/* Maximum size of a fully qualified host name. */ +#define MAXHOSTLEN 257 + +/* Size of buffers for reading and writing commands to rmt. + (An arbitrary limit.) */ +#define CMDBUFSIZE 64 + +#ifndef RETSIGTYPE +#define RETSIGTYPE void +#endif + +/* Maximum number of simultaneous remote tape connections. + (Another arbitrary limit.) */ +#define MAXUNIT 4 + +/* Return the parent's read side of remote tape connection FILDES. */ +#define READ(fildes) (from_rmt[fildes][0]) + +/* Return the parent's write side of remote tape connection FILDES. */ +#define WRITE(fildes) (to_rmt[fildes][1]) + +/* The pipes for receiving data from remote tape drives. */ +static int from_rmt[MAXUNIT][2] = +{-1, -1, -1, -1, -1, -1, -1, -1}; + +/* The pipes for sending data to remote tape drives. */ +static int to_rmt[MAXUNIT][2] = +{-1, -1, -1, -1, -1, -1, -1, -1}; + +/* Temporary variable used by macros in rmt.h. */ +char *__rmt_path; + +/* Close remote tape connection FILDES. */ + +static void +_rmt_shutdown (fildes) + int fildes; +{ + close (READ (fildes)); + close (WRITE (fildes)); + READ (fildes) = -1; + WRITE (fildes) = -1; +} + +/* Attempt to perform the remote tape command specified in BUF + on remote tape connection FILDES. + Return 0 if successful, -1 on error. */ + +static int +command (fildes, buf) + int fildes; + char *buf; +{ + register int buflen; + RETSIGTYPE (*pipe_handler) (); + + /* Save the current pipe handler and try to make the request. */ + + pipe_handler = signal (SIGPIPE, SIG_IGN); + buflen = strlen (buf); + if (write (WRITE (fildes), buf, buflen) == buflen) + { + signal (SIGPIPE, pipe_handler); + return 0; + } + + /* Something went wrong. Close down and go home. */ + + signal (SIGPIPE, pipe_handler); + _rmt_shutdown (fildes); + errno = EIO; + return -1; +} + +/* Read and return the status from remote tape connection FILDES. + If an error occurred, return -1 and set errno. */ + +static int +status (fildes) + int fildes; +{ + int i; + char c, *cp; + char buffer[CMDBUFSIZE]; + + /* Read the reply command line. */ + + for (i = 0, cp = buffer; i < CMDBUFSIZE; i++, cp++) + { + if (read (READ (fildes), cp, 1) != 1) + { + _rmt_shutdown (fildes); + errno = EIO; + return -1; + } + if (*cp == '\n') + { + *cp = '\0'; + break; + } + } + + if (i == CMDBUFSIZE) + { + _rmt_shutdown (fildes); + errno = EIO; + return -1; + } + + /* Check the return status. */ + + for (cp = buffer; *cp; cp++) + if (*cp != ' ') + break; + + if (*cp == 'E' || *cp == 'F') + { + errno = atoi (cp + 1); + /* Skip the error message line. */ + while (read (READ (fildes), &c, 1) == 1) + if (c == '\n') + break; + + if (*cp == 'F') + _rmt_shutdown (fildes); + + return -1; + } + + /* Check for mis-synced pipes. */ + + if (*cp != 'A') + { + _rmt_shutdown (fildes); + errno = EIO; + return -1; + } + + /* Got an `A' (success) response. */ + return atoi (cp + 1); +} + +#ifdef HAVE_NETDB_H +/* Execute /etc/rmt as user USER on remote system HOST using rexec. + Return a file descriptor of a bidirectional socket for stdin and stdout. + If USER is NULL, or an empty string, use the current username. + + By default, this code is not used, since it requires that + the user have a .netrc file in his/her home directory, or that the + application designer be willing to have rexec prompt for login and + password info. This may be unacceptable, and .rhosts files for use + with rsh are much more common on BSD systems. */ + +static int +_rmt_rexec (host, user) + char *host; + char *user; +{ + struct servent *rexecserv; + int save_stdin = dup (fileno (stdin)); + int save_stdout = dup (fileno (stdout)); + int tape_fd; /* Return value. */ + + /* When using cpio -o < filename, stdin is no longer the tty. + But the rexec subroutine reads the login and the passwd on stdin, + to allow remote execution of the command. + So, reopen stdin and stdout on /dev/tty before the rexec and + give them back their original value after. */ + if (freopen ("/dev/tty", "r", stdin) == NULL) + freopen ("/dev/null", "r", stdin); + if (freopen ("/dev/tty", "w", stdout) == NULL) + freopen ("/dev/null", "w", stdout); + + rexecserv = getservbyname ("exec", "tcp"); + if (NULL == rexecserv) + { + fprintf (stderr, "exec/tcp: service not available"); + exit (1); + } + if (user != NULL && *user == '\0') + user = NULL; + tape_fd = rexec (&host, rexecserv->s_port, user, NULL, + "/etc/rmt", (int *) NULL); + fclose (stdin); + fdopen (save_stdin, "r"); + fclose (stdout); + fdopen (save_stdout, "w"); + + return tape_fd; +} + +#endif /* HAVE_NETDB_H */ + +/* Open a magtape device on the system specified in PATH, as the given user. + PATH has the form `[user@]system:/dev/????'. + If COMPAT is defined, it can also have the form `system[.user]:/dev/????'. + + OFLAG is O_RDONLY, O_WRONLY, etc. + MODE is ignored; 0666 is always used. + + If successful, return the remote tape pipe number plus BIAS. + On error, return -1. */ + +int +__rmt_open (path, oflag, mode, bias) + char *path; + int oflag; + int mode; + int bias; +{ + int i, rc; + char buffer[CMDBUFSIZE]; /* Command buffer. */ + char system[MAXHOSTLEN]; /* The remote host name. */ + char device[CMDBUFSIZE]; /* The remote device name. */ + char login[CMDBUFSIZE]; /* The remote user name. */ + char *sys, *dev, *user; /* For copying into the above buffers. */ + + sys = system; + dev = device; + user = login; + + /* Find an unused pair of file descriptors. */ + + for (i = 0; i < MAXUNIT; i++) + if (READ (i) == -1 && WRITE (i) == -1) + break; + + if (i == MAXUNIT) + { + errno = EMFILE; + return -1; + } + + /* Pull apart the system and device, and optional user. + Don't munge the original string. */ + + while (*path != '@' +#ifdef COMPAT + && *path != '.' +#endif + && *path != ':') + { + *sys++ = *path++; + } + *sys = '\0'; + path++; + + if (*(path - 1) == '@') + { + /* Saw user part of user@host. Start over. */ + strcpy (user, system); + sys = system; + while (*path != ':') + { + *sys++ = *path++; + } + *sys = '\0'; + path++; + } +#ifdef COMPAT + else if (*(path - 1) == '.') + { + while (*path != ':') + { + *user++ = *path++; + } + *user = '\0'; + path++; + } +#endif + else + *user = '\0'; + + while (*path) + { + *dev++ = *path++; + } + *dev = '\0'; + +#ifdef HAVE_NETDB_H + /* Execute the remote command using rexec. */ + READ (i) = WRITE (i) = _rmt_rexec (system, login); + if (READ (i) < 0) + return -1; +#else /* !HAVE_NETDB_H */ + /* Set up the pipes for the `rsh' command, and fork. */ + + if (pipe (to_rmt[i]) == -1 || pipe (from_rmt[i]) == -1) + return -1; + + rc = fork (); + if (rc == -1) + return -1; + + if (rc == 0) + { + /* Child. */ + close (0); + dup (to_rmt[i][0]); + close (to_rmt[i][0]); + close (to_rmt[i][1]); + + close (1); + dup (from_rmt[i][1]); + close (from_rmt[i][0]); + close (from_rmt[i][1]); + + setuid (getuid ()); + setgid (getgid ()); + + if (*login) + { + execl ("/usr/ucb/rsh", "rsh", system, "-l", login, + "/etc/rmt", (char *) 0); + execl ("/usr/bin/remsh", "remsh", system, "-l", login, + "/etc/rmt", (char *) 0); + execl ("/usr/bin/rsh", "rsh", system, "-l", login, + "/etc/rmt", (char *) 0); + execl ("/usr/bsd/rsh", "rsh", system, "-l", login, + "/etc/rmt", (char *) 0); + execl ("/usr/bin/nsh", "nsh", system, "-l", login, + "/etc/rmt", (char *) 0); + } + else + { + execl ("/usr/ucb/rsh", "rsh", system, + "/etc/rmt", (char *) 0); + execl ("/usr/bin/remsh", "remsh", system, + "/etc/rmt", (char *) 0); + execl ("/usr/bin/rsh", "rsh", system, + "/etc/rmt", (char *) 0); + execl ("/usr/bsd/rsh", "rsh", system, + "/etc/rmt", (char *) 0); + execl ("/usr/bin/nsh", "nsh", system, + "/etc/rmt", (char *) 0); + } + + /* Bad problems if we get here. */ + + perror ("cannot execute remote shell"); + _exit (1); + } + + /* Parent. */ + close (to_rmt[i][0]); + close (from_rmt[i][1]); +#endif /* !HAVE_NETDB_H */ + + /* Attempt to open the tape device. */ + + sprintf (buffer, "O%s\n%d\n", device, oflag); + if (command (i, buffer) == -1 || status (i) == -1) + return -1; + + return i + bias; +} + +/* Close remote tape connection FILDES and shut down. + Return 0 if successful, -1 on error. */ + +int +__rmt_close (fildes) + int fildes; +{ + int rc; + + if (command (fildes, "C\n") == -1) + return -1; + + rc = status (fildes); + _rmt_shutdown (fildes); + return rc; +} + +/* Read up to NBYTE bytes into BUF from remote tape connection FILDES. + Return the number of bytes read on success, -1 on error. */ + +int +__rmt_read (fildes, buf, nbyte) + int fildes; + char *buf; + unsigned int nbyte; +{ + int rc, i; + char buffer[CMDBUFSIZE]; + + sprintf (buffer, "R%d\n", nbyte); + if (command (fildes, buffer) == -1 || (rc = status (fildes)) == -1) + return -1; + + for (i = 0; i < rc; i += nbyte, buf += nbyte) + { + nbyte = read (READ (fildes), buf, rc - i); + if (nbyte <= 0) + { + _rmt_shutdown (fildes); + errno = EIO; + return -1; + } + } + + return rc; +} + +/* Write NBYTE bytes from BUF to remote tape connection FILDES. + Return the number of bytes written on success, -1 on error. */ + +int +__rmt_write (fildes, buf, nbyte) + int fildes; + char *buf; + unsigned int nbyte; +{ + char buffer[CMDBUFSIZE]; + RETSIGTYPE (*pipe_handler) (); + + sprintf (buffer, "W%d\n", nbyte); + if (command (fildes, buffer) == -1) + return -1; + + pipe_handler = signal (SIGPIPE, SIG_IGN); + if (write (WRITE (fildes), buf, nbyte) == nbyte) + { + signal (SIGPIPE, pipe_handler); + return status (fildes); + } + + /* Write error. */ + signal (SIGPIPE, pipe_handler); + _rmt_shutdown (fildes); + errno = EIO; + return -1; +} + +/* Perform an imitation lseek operation on remote tape connection FILDES. + Return the new file offset if successful, -1 if on error. */ + +long +__rmt_lseek (fildes, offset, whence) + int fildes; + long offset; + int whence; +{ + char buffer[CMDBUFSIZE]; + + sprintf (buffer, "L%ld\n%d\n", offset, whence); + if (command (fildes, buffer) == -1) + return -1; + + return status (fildes); +} + +/* Perform a raw tape operation on remote tape connection FILDES. + Return the results of the ioctl, or -1 on error. */ + +#ifdef MTIOCTOP +int +__rmt_ioctl (fildes, op, arg) + int fildes, op; + char *arg; +{ + char c; + int rc, cnt; + char buffer[CMDBUFSIZE]; + + switch (op) + { + default: + errno = EINVAL; + return -1; + + case MTIOCTOP: + /* MTIOCTOP is the easy one. Nothing is transfered in binary. */ + sprintf (buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op, + ((struct mtop *) arg)->mt_count); + if (command (fildes, buffer) == -1) + return -1; + return status (fildes); /* Return the count. */ + + case MTIOCGET: + /* Grab the status and read it directly into the structure. + This assumes that the status buffer is not padded + and that 2 shorts fit in a long without any word + alignment problems; i.e., the whole struct is contiguous. + NOTE - this is probably NOT a good assumption. */ + + if (command (fildes, "S") == -1 || (rc = status (fildes)) == -1) + return -1; + + for (; rc > 0; rc -= cnt, arg += cnt) + { + cnt = read (READ (fildes), arg, rc); + if (cnt <= 0) + { + _rmt_shutdown (fildes); + errno = EIO; + return -1; + } + } + + /* Check for byte position. mt_type is a small integer field + (normally) so we will check its magnitude. If it is larger than + 256, we will assume that the bytes are swapped and go through + and reverse all the bytes. */ + + if (((struct mtget *) arg)->mt_type < 256) + return 0; + + for (cnt = 0; cnt < rc; cnt += 2) + { + c = arg[cnt]; + arg[cnt] = arg[cnt + 1]; + arg[cnt + 1] = c; + } + + return 0; + } +} + +#endif diff --git a/gnu/usr.bin/cpio/stripslash.c b/gnu/usr.bin/cpio/stripslash.c new file mode 100644 index 0000000..2971d4c --- /dev/null +++ b/gnu/usr.bin/cpio/stripslash.c @@ -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 index 0000000..abe732d --- /dev/null +++ b/gnu/usr.bin/cpio/system.h @@ -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 index 0000000..16eeee0 --- /dev/null +++ b/gnu/usr.bin/cpio/tar.c @@ -0,0 +1,522 @@ +/* tar.c - read in write tar headers for cpio + Copyright (C) 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "filetypes.h" +#include "system.h" +#include "cpiohdr.h" +#include "dstring.h" +#include "extern.h" +#include "rmt.h" +#include "tarhdr.h" + +static void to_oct (); +static char *stash_tar_linkname (); +static char *stash_tar_filename (); + +/* Compute and return a checksum for TAR_HDR, + counting the checksum bytes as if they were spaces. */ + +unsigned long +tar_checksum (tar_hdr) + struct tar_header *tar_hdr; +{ + unsigned long sum = 0; + char *p = (char *) tar_hdr; + char *q = p + TARRECORDSIZE; + int i; + + while (p < tar_hdr->chksum) + sum += *p++ & 0xff; + for (i = 0; i < 8; ++i) + { + sum += ' '; + ++p; + } + while (p < q) + sum += *p++ & 0xff; + return sum; +} + +/* Write out header FILE_HDR, including the file name, to file + descriptor OUT_DES. */ + +void +write_out_tar_header (file_hdr, out_des) + struct new_cpio_header *file_hdr; + int out_des; +{ + int name_len; + union tar_record tar_rec; + struct tar_header *tar_hdr = (struct tar_header *) &tar_rec; + + bzero ((char *) &tar_rec, TARRECORDSIZE); + + /* process_copy_out must ensure that file_hdr->c_name is short enough, + or we will lose here. */ + + name_len = strlen (file_hdr->c_name); + if (name_len <= TARNAMESIZE) + { + strncpy (tar_hdr->name, file_hdr->c_name, name_len); + } + else + { + /* Fit as much as we can into `name', the rest into `prefix'. */ + char *suffix = file_hdr->c_name + name_len - TARNAMESIZE; + + /* We have to put the boundary at a slash. */ + name_len = TARNAMESIZE; + while (*suffix != '/') + { + --name_len; + ++suffix; + } + strncpy (tar_hdr->name, suffix + 1, name_len); + strncpy (tar_hdr->prefix, file_hdr->c_name, suffix - file_hdr->c_name); + } + + /* SVR4 seems to want the whole mode, not just protection modes. + Nobody else seems to care, so we might as well put it all in. */ + to_oct (file_hdr->c_mode, 8, tar_hdr->mode); + to_oct (file_hdr->c_uid, 8, tar_hdr->uid); + to_oct (file_hdr->c_gid, 8, tar_hdr->gid); + to_oct (file_hdr->c_filesize, 12, tar_hdr->size); + to_oct (file_hdr->c_mtime, 12, tar_hdr->mtime); + + switch (file_hdr->c_mode & CP_IFMT) + { + case CP_IFREG: + if (file_hdr->c_tar_linkname) + { + /* process_copy_out makes sure that c_tar_linkname is shorter + than TARLINKNAMESIZE. */ + strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname, + TARLINKNAMESIZE); + tar_hdr->typeflag = LNKTYPE; + to_oct (0, 12, tar_hdr->size); + } + else + tar_hdr->typeflag = REGTYPE; + break; + case CP_IFDIR: + tar_hdr->typeflag = DIRTYPE; + break; +#ifndef __MSDOS__ + case CP_IFCHR: + tar_hdr->typeflag = CHRTYPE; + break; + case CP_IFBLK: + tar_hdr->typeflag = BLKTYPE; + break; +#ifdef CP_IFIFO + case CP_IFIFO: + tar_hdr->typeflag = FIFOTYPE; + break; +#endif /* CP_IFIFO */ +#ifdef CP_IFLNK + case CP_IFLNK: + tar_hdr->typeflag = SYMTYPE; + /* process_copy_out makes sure that c_tar_linkname is shorter + than TARLINKNAMESIZE. */ + strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname, + TARLINKNAMESIZE); + to_oct (0, 12, tar_hdr->size); + break; +#endif /* CP_IFLNK */ +#endif /* !__MSDOS__ */ + } + + if (archive_format == arf_ustar) + { + char *name; + + strncpy (tar_hdr->magic, TMAGIC, TMAGLEN); + strncpy (tar_hdr->magic + TMAGLEN, TVERSION, TVERSLEN); + +#ifndef __MSDOS__ + name = getuser (file_hdr->c_uid); + if (name) + strcpy (tar_hdr->uname, name); + name = getgroup (file_hdr->c_gid); + if (name) + strcpy (tar_hdr->gname, name); +#endif + + to_oct (file_hdr->c_rdev_maj, 8, tar_hdr->devmajor); + to_oct (file_hdr->c_rdev_min, 8, tar_hdr->devminor); + } + + to_oct (tar_checksum (tar_hdr), 8, tar_hdr->chksum); + + 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 index 0000000..411579c --- /dev/null +++ b/gnu/usr.bin/cpio/tar.h @@ -0,0 +1,112 @@ +/* Extended tar format from POSIX.1. + Copyright (C) 1992 Free Software Foundation, Inc. + Written by David J. MacKenzie. + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _TAR_H + +#define _TAR_H 1 + + +/* A tar archive consists of 512-byte blocks. + Each file in the archive has a header block followed by 0+ data blocks. + Two blocks of NUL bytes indicate the end of the archive. */ + +/* The fields of header blocks: + All strings are stored as ISO 646 (approximately ASCII) strings. + + Fields are numeric unless otherwise noted below; numbers are ISO 646 + representations of octal numbers, with leading zeros as needed. + + linkname is only valid when typeflag==LNKTYPE. It doesn't use prefix; + files that are links to pathnames >100 chars long can not be stored + in a tar archive. + + If typeflag=={LNKTYPE,SYMTYPE,DIRTYPE} then size must be 0. + + devmajor and devminor are only valid for typeflag=={BLKTYPE,CHRTYPE}. + + chksum contains the sum of all 512 bytes in the header block, + treating each byte as an 8-bit unsigned value and treating the + 8 bytes of chksum as blank characters. + + uname and gname are used in preference to uid and gid, if those + names exist locally. + + Field Name Byte Offset Length in Bytes Field Type + name 0 100 NUL-terminated if NUL fits + mode 100 8 + uid 108 8 + gid 116 8 + size 124 12 + mtime 136 12 + chksum 148 8 + typeflag 156 1 see below + linkname 157 100 NUL-terminated if NUL fits + magic 257 6 must be TMAGIC (NUL term.) + version 263 2 must be TVERSION + uname 265 32 NUL-terminated + gname 297 32 NUL-terminated + devmajor 329 8 + devminor 337 8 + prefix 345 155 NUL-terminated if NUL fits + + If the first character of prefix is '\0', the file name is name; + otherwise, it is prefix/name. Files whose pathnames don't fit in that + length can not be stored in a tar archive. */ + +/* The bits in mode: */ +#define TSUID 04000 +#define TSGID 02000 +#define TSVTX 01000 +#define TUREAD 00400 +#define TUWRITE 00200 +#define TUEXEC 00100 +#define TGREAD 00040 +#define TGWRITE 00020 +#define TGEXEC 00010 +#define TOREAD 00004 +#define TOWRITE 00002 +#define TOEXEC 00001 + +/* The values for typeflag: + Values 'A'-'Z' are reserved for custom implementations. + All other values are reserved for future POSIX.1 revisions. */ + +#define REGTYPE '0' /* Regular file (preferred code). */ +#define AREGTYPE '\0' /* Regular file (alternate code). */ +#define LNKTYPE '1' /* Hard link. */ +#define SYMTYPE '2' /* Symbolic link (hard if not supported). */ +#define CHRTYPE '3' /* Character special. */ +#define BLKTYPE '4' /* Block special. */ +#define DIRTYPE '5' /* Directory. */ +#define FIFOTYPE '6' /* Named pipe. */ +#define CONTTYPE '7' /* Contiguous file */ + /* (regular file if not supported). */ + +/* Contents of magic field and its length. */ +#define TMAGIC "ustar" +#define TMAGLEN 6 + +/* Contents of the version field and its length. */ +#define TVERSION "00" +#define TVERSLEN 2 + + +#endif /* tar.h */ diff --git a/gnu/usr.bin/cpio/tarhdr.h b/gnu/usr.bin/cpio/tarhdr.h new file mode 100644 index 0000000..54de0d6 --- /dev/null +++ b/gnu/usr.bin/cpio/tarhdr.h @@ -0,0 +1,62 @@ +/* Extended tar header from POSIX.1. + Copyright (C) 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _TARHDR_H + +#define _TARHDR_H 1 + +#include <tar.h> + +/* Size of `name' field. */ +#define TARNAMESIZE 100 + +/* Size of `linkname' field. */ +#define TARLINKNAMESIZE 100 + +/* Size of `prefix' field. */ +#define TARPREFIXSIZE 155 + +/* Size of entire tar header. */ +#define TARRECORDSIZE 512 + +struct tar_header +{ + char name[TARNAMESIZE]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char typeflag; + char linkname[TARLINKNAMESIZE]; + char magic[6]; + char version[2]; + char uname[32]; + char gname[32]; + char devmajor[8]; + char devminor[8]; + char prefix[TARPREFIXSIZE]; +}; + +union tar_record +{ + struct tar_header header; + char buffer[TARRECORDSIZE]; +}; + +#endif /* tarhdr.h */ diff --git a/gnu/usr.bin/cpio/tcexparg.c b/gnu/usr.bin/cpio/tcexparg.c new file mode 100644 index 0000000..c5d88f0 --- /dev/null +++ b/gnu/usr.bin/cpio/tcexparg.c @@ -0,0 +1,240 @@ +/* tcexparg.c - Unix-style command line wildcards for Turbo C 2.0 + + This file is in the public domain. + + Compile your main program with -Dmain=_main and link with this file. + + After that, it is just as if the operating system had expanded the + arguments, except that they are not sorted. The program name and all + arguments that are expanded from wildcards are lowercased. + + Syntax for wildcards: + * Matches zero or more of any character (except a '.' at + the beginning of a name). + ? Matches any single character. + [r3z] Matches 'r', '3', or 'z'. + [a-d] Matches a single character in the range 'a' through 'd'. + [!a-d] Matches any single character except a character in the + range 'a' through 'd'. + + The period between the filename root and its extension need not be + given explicitly. Thus, the pattern `a*e' will match 'abacus.exe' + and 'axyz.e' as well as 'apple'. Comparisons are not case sensitive. + + Authors: + The expargs code is a modification of wildcard expansion code + written for Turbo C 1.0 by + Richard Hargrove + Texas Instruments, Inc. + P.O. Box 869305, m/s 8473 + Plano, Texas 75086 + 214/575-4128 + and posted to USENET in September, 1987. + + The wild_match code was written by Rich Salz, rsalz@bbn.com, + posted to net.sources in November, 1986. + + The code connecting the two is by Mike Slomin, bellcore!lcuxa!mike2, + posted to comp.sys.ibm.pc in November, 1988. + + Major performance enhancements and bug fixes, and source cleanup, + by David MacKenzie, djm@gnu.ai.mit.edu. */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <dos.h> +#include <dir.h> + +/* Number of new arguments to allocate space for at a time. */ +#define ARGS_INCREMENT 10 + +/* The name this program was run with, for error messages. */ +static char *program_name; + +static char **grow_argv (char **new_argv, int new_argc); +static void fatal_error (const char *message); + +int wild_match (char *string, char *pattern); +char *basename (char *path); + +char **expargs (int *, char **); + +#ifdef main +#undef main +#endif + +int +main (int argc, char **argv, char **envp) +{ + argv = expargs (&argc, argv); + return _main (argc, argv, envp); +} + +char ** +expargs (int *pargc, char **argv) +{ + char path[MAXPATH + 1]; + char **new_argv; + struct ffblk block; + char *path_base; + char *arg_base; + int argind; + int new_argc; + int path_length; + int matched; + + program_name = argv[0]; + if (program_name && *program_name) + strlwr (program_name); + new_argv = grow_argv (NULL, 0); + new_argv[0] = argv[0]; + new_argc = 1; + + for (argind = 1; argind < *pargc; ++argind) + { + matched = 0; + if (strpbrk (argv[argind], "?*[") != NULL) + { + strncpy (path, argv[argind], MAXPATH - 3); + path_base = basename (path); + strcpy (path_base, "*.*"); + arg_base = argv[argind] + (path_base - path); + + if (!findfirst (path, &block, FA_DIREC)) + { + strlwr (path); + do + { + /* Only match "." and ".." explicitly. */ + if (*block.ff_name == '.' && *arg_base != '.') + continue; + path_length = stpcpy (path_base, block.ff_name) - path + 1; + strlwr (path_base); + if (wild_match (path, argv[argind])) + { + matched = 1; + new_argv[new_argc] = (char *) malloc (path_length); + if (new_argv[new_argc] == NULL) + fatal_error ("memory exhausted"); + strcpy (new_argv[new_argc++], path); + new_argv = grow_argv (new_argv, new_argc); + } + } while (!findnext (&block)); + } + } + if (matched == 0) + new_argv[new_argc++] = argv[argind]; + new_argv = grow_argv (new_argv, new_argc); + } + + *pargc = new_argc; + new_argv[new_argc] = NULL; + return &new_argv[0]; +} + +/* Return a pointer to the last element of PATH. */ + +char * +basename (char *path) +{ + char *tail; + + for (tail = path; *path; ++path) + if (*path == ':' || *path == '\\') + tail = path + 1; + return tail; +} + +static char ** +grow_argv (char **new_argv, int new_argc) +{ + if (new_argc % ARGS_INCREMENT == 0) + { + new_argv = (char **) realloc + (new_argv, sizeof (char *) * (new_argc + ARGS_INCREMENT)); + if (new_argv == NULL) + fatal_error ("memory exhausted"); + } + return new_argv; +} + +static void +fatal_error (const char *message) +{ + putc ('\n', stderr); + if (program_name && *program_name) + { + fputs (program_name, stderr); + fputs (": ", stderr); + } + fputs (message, stderr); + putc ('\n', stderr); + exit (1); +} + +/* Shell-style pattern matching for ?, \, [], and * characters. + I'm putting this replacement in the public domain. + + Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. */ + +/* The character that inverts a character class; '!' or '^'. */ +#define INVERT '!' + +static int star (char *string, char *pattern); + +/* Return nonzero if `string' matches Unix-style wildcard pattern + `pattern'; zero if not. */ + +int +wild_match (char *string, char *pattern) +{ + int prev; /* Previous character in character class. */ + int matched; /* If 1, character class has been matched. */ + int reverse; /* If 1, character class is inverted. */ + + for (; *pattern; string++, pattern++) + switch (*pattern) + { + case '\\': + /* Literal match with following character; fall through. */ + pattern++; + default: + if (*string != *pattern) + return 0; + continue; + case '?': + /* Match anything. */ + if (*string == '\0') + return 0; + continue; + case '*': + /* Trailing star matches everything. */ + return *++pattern ? star (string, pattern) : 1; + case '[': + /* Check for inverse character class. */ + reverse = pattern[1] == INVERT; + if (reverse) + pattern++; + for (prev = 256, matched = 0; *++pattern && *pattern != ']'; + prev = *pattern) + if (*pattern == '-' + ? *string <= *++pattern && *string >= prev + : *string == *pattern) + matched = 1; + if (matched == reverse) + return 0; + continue; + } + + return *string == '\0'; +} + +static int +star (char *string, char *pattern) +{ + while (wild_match (string, pattern) == 0) + if (*++string == '\0') + return 0; + return 1; +} diff --git a/gnu/usr.bin/cpio/userspec.c b/gnu/usr.bin/cpio/userspec.c new file mode 100644 index 0000000..44d7d91 --- /dev/null +++ b/gnu/usr.bin/cpio/userspec.c @@ -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>. */ + +#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 index 0000000..52e3e85 --- /dev/null +++ b/gnu/usr.bin/cpio/util.c @@ -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; +} + +/* 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; +} + +/* 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; + } +} + +/* 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; + } +} + +/* 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; +} + +/* 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 index 0000000..38a63f2 --- /dev/null +++ b/gnu/usr.bin/cpio/version.c @@ -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 index 0000000..f989004 --- /dev/null +++ b/gnu/usr.bin/cpio/xmalloc.c @@ -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 index 0000000..9588bc7 --- /dev/null +++ b/gnu/usr.bin/cpio/xstrdup.c @@ -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); +} diff --git a/gnu/usr.bin/diff/COPYING b/gnu/usr.bin/diff/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/gnu/usr.bin/diff/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gnu/usr.bin/diff/cmpbuf.c b/gnu/usr.bin/diff/cmpbuf.c new file mode 100644 index 0000000..e95a8f9 --- /dev/null +++ b/gnu/usr.bin/diff/cmpbuf.c @@ -0,0 +1,40 @@ +/* Buffer primitives for comparison operations. + 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 "system.h" +#include "cmpbuf.h" + +/* Least common multiple of two buffer sizes A and B. */ + +size_t +buffer_lcm (a, b) + size_t a, b; +{ + size_t m, n, r; + + /* Yield reasonable values if buffer sizes are zero. */ + if (!a) + return b ? b : 8 * 1024; + if (!b) + return a; + + /* n = gcd (a, b) */ + for (m = a, n = b; (r = m % n) != 0; m = n, n = r) + continue; + + return a/n * b; +} diff --git a/gnu/usr.bin/diff/cmpbuf.h b/gnu/usr.bin/diff/cmpbuf.h new file mode 100644 index 0000000..e3852b7 --- /dev/null +++ b/gnu/usr.bin/diff/cmpbuf.h @@ -0,0 +1,20 @@ +/* Buffer primitives for comparison operations. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU DIFF. + +GNU DIFF is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU DIFF is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU DIFF; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +size_t buffer_lcm PARAMS((size_t, size_t)); diff --git a/gnu/usr.bin/diff/config.h b/gnu/usr.bin/diff/config.h new file mode 100644 index 0000000..ed8e8ef --- /dev/null +++ b/gnu/usr.bin/diff/config.h @@ -0,0 +1,112 @@ +/* config.h. Generated automatically by configure. */ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if using alloca.c. */ +/* #undef C_ALLOCA */ + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +/* #undef CRAY_STACKSEG_END */ + +/* Define if you have dirent.h. */ +#define DIRENT 1 + +/* Define if you have alloca.h and it should be used (not Ultrix). */ +/* #undef HAVE_ALLOCA_H */ + +/* Define if you don't have vprintf but do have _doprnt. */ +/* #undef HAVE_DOPRNT */ + +/* Define if your struct stat has st_blksize. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define if you have vfork.h. */ +/* #undef HAVE_VFORK_H */ + +/* Define if you have the vprintf function. */ +#define HAVE_VPRINTF 1 + +/* Define if on MINIX. */ +/* #undef _MINIX */ + +/* Define if you don't have dirent.h, but have ndir.h. */ +/* #undef NDIR */ + +/* Define to `int' if <sys/types.h> doesn't define. */ +/* #undef pid_t */ + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define if you need to in order for stat and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* If using the C implementation of alloca, define 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 + */ +/* #undef STACK_DIRECTION */ + +/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you don't have dirent.h, but have sys/dir.h. */ +/* #undef SYSDIR */ + +/* Define if you don't have dirent.h, but have sys/ndir.h. */ +/* #undef SYSNDIR */ + +/* Define vfork as fork if vfork does not work. */ +/* #undef vfork */ + +/* Define if the closedir function returns void instead of int. */ +/* #undef VOID_CLOSEDIR */ + +/* Define if you have dup2. */ +#define HAVE_DUP2 1 + +/* Define if you have memchr. */ +#define HAVE_MEMCHR 1 + +/* Define if you have sigaction. */ +#define HAVE_SIGACTION 1 + +/* Define if you have strerror. */ +#define HAVE_STRERROR 1 + +/* Define if you have waitpid. */ +#define HAVE_WAITPID 1 + +/* Define if you have the <fcntl.h> header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the <limits.h> header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the <sys/wait.h> header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define if you have the <time.h> header file. */ +#define HAVE_TIME_H 1 + +/* Define if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 diff --git a/gnu/usr.bin/diff/diff3.c b/gnu/usr.bin/diff/diff3.c new file mode 100644 index 0000000..b9952fc --- /dev/null +++ b/gnu/usr.bin/diff/diff3.c @@ -0,0 +1,1693 @@ +/* Three way file comparison program (diff3) for Project GNU. + Copyright (C) 1988, 1989, 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 Randy Smith */ + +#if __STDC__ +#define VOID void +#else +#define VOID char +#endif + +#include <stdio.h> +#include <ctype.h> +#include "getopt.h" +#include "system.h" + +/* + * Internal data structures and macros for the diff3 program; includes + * data structures for both diff3 diffs and normal diffs. + */ + +/* Different files within a three way diff. */ +#define FILE0 0 +#define FILE1 1 +#define FILE2 2 + +/* + * A three way diff is built from two two-way diffs; the file which + * the two two-way diffs share is: + */ +#define FILEC FILE2 + +/* + * Different files within a two way diff. + * FC is the common file, FO the other file. + */ +#define FO 0 +#define FC 1 + +/* The ranges are indexed by */ +#define START 0 +#define END 1 + +enum diff_type { + ERROR, /* Should not be used */ + ADD, /* Two way diff add */ + CHANGE, /* Two way diff change */ + DELETE, /* Two way diff delete */ + DIFF_ALL, /* All three are different */ + DIFF_1ST, /* Only the first is different */ + DIFF_2ND, /* Only the second */ + DIFF_3RD /* Only the third */ +}; + +/* Two way diff */ +struct diff_block { + int ranges[2][2]; /* Ranges are inclusive */ + char **lines[2]; /* The actual lines (may contain nulls) */ + int *lengths[2]; /* Line lengths (including newlines, if any) */ + struct diff_block *next; +}; + +/* Three way diff */ + +struct diff3_block { + enum diff_type correspond; /* Type of diff */ + int ranges[3][2]; /* Ranges are inclusive */ + char **lines[3]; /* The actual lines (may contain nulls) */ + int *lengths[3]; /* Line lengths (including newlines, if any) */ + struct diff3_block *next; +}; + +/* + * Access the ranges on a diff block. + */ +#define D_LOWLINE(diff, filenum) \ + ((diff)->ranges[filenum][START]) +#define D_HIGHLINE(diff, filenum) \ + ((diff)->ranges[filenum][END]) +#define D_NUMLINES(diff, filenum) \ + (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1) + +/* + * Access the line numbers in a file in a diff by relative line + * numbers (i.e. line number within the diff itself). Note that these + * are lvalues and can be used for assignment. + */ +#define D_RELNUM(diff, filenum, linenum) \ + ((diff)->lines[filenum][linenum]) +#define D_RELLEN(diff, filenum, linenum) \ + ((diff)->lengths[filenum][linenum]) + +/* + * And get at them directly, when that should be necessary. + */ +#define D_LINEARRAY(diff, filenum) \ + ((diff)->lines[filenum]) +#define D_LENARRAY(diff, filenum) \ + ((diff)->lengths[filenum]) + +/* + * Next block. + */ +#define D_NEXT(diff) ((diff)->next) + +/* + * Access the type of a diff3 block. + */ +#define D3_TYPE(diff) ((diff)->correspond) + +/* + * Line mappings based on diffs. The first maps off the top of the + * diff, the second off of the bottom. + */ +#define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno) \ + ((lineno) \ + - D_HIGHLINE ((diff), (fromfile)) \ + + D_HIGHLINE ((diff), (tofile))) + +#define D_LOW_MAPLINE(diff, fromfile, tofile, lineno) \ + ((lineno) \ + - D_LOWLINE ((diff), (fromfile)) \ + + D_LOWLINE ((diff), (tofile))) + +/* + * General memory allocation function. + */ +#define ALLOCATE(number, type) \ + (type *) xmalloc ((number) * sizeof (type)) + +/* Options variables for flags set on command line. */ + +/* If nonzero, treat all files as text files, never as binary. */ +static int always_text; + +/* If nonzero, write out an ed script instead of the standard diff3 format. */ +static int edscript; + +/* If nonzero, in the case of overlapping diffs (type DIFF_ALL), + preserve the lines which would normally be deleted from + file 1 with a special flagging mechanism. */ +static int flagging; + +/* Number of lines to keep in identical prefix and suffix. */ +static int horizon_lines = 10; + +/* If nonzero, do not output information for overlapping diffs. */ +static int simple_only; + +/* If nonzero, do not output information for non-overlapping diffs. */ +static int overlap_only; + +/* If nonzero, show information for DIFF_2ND diffs. */ +static int show_2nd; + +/* If nonzero, include `:wq' at the end of the script + to write out the file being edited. */ +static int finalwrite; + +/* If nonzero, output a merged file. */ +static int merge; + +static char *argv0; + +/* + * Forward function declarations. + */ +static int myread (); +static void fatal (); +static void perror_with_exit (); +static struct diff_block *process_diff (); +static struct diff3_block *make_3way_diff (); +static void output_diff3 (); +static int output_diff3_edscript (); +static int output_diff3_merge (); +static void usage (); + +static struct diff3_block *using_to_diff3_block (); +static int copy_stringlist (); +static struct diff3_block *create_diff3_block (); +static int compare_line_list (); + +static char *read_diff (); +static enum diff_type process_diff_control (); +static char *scan_diff_line (); + +static struct diff3_block *reverse_diff3_blocklist (); + +VOID *xmalloc (); +static VOID *xrealloc (); + +static char diff_program[] = DIFF_PROGRAM; + +static struct option longopts[] = +{ + {"text", 0, NULL, 'a'}, + {"show-all", 0, NULL, 'A'}, + {"ed", 0, NULL, 'e'}, + {"show-overlap", 0, NULL, 'E'}, + {"label", 1, NULL, 'L'}, + {"merge", 0, NULL, 'm'}, + {"overlap-only", 0, NULL, 'x'}, + {"easy-only", 0, NULL, '3'}, + {"version", 0, NULL, 'v'}, + {0, 0, 0, 0} +}; + +/* + * Main program. Calls diff twice on two pairs of input files, + * combines the two diffs, and outputs them. + */ +int +main (argc, argv) + int argc; + char **argv; +{ + extern char *version_string; + int c, i; + int mapping[3]; + int rev_mapping[3]; + int incompat; + int conflicts_found; + struct diff_block *thread0, *thread1, *last_block; + struct diff3_block *diff3; + int tag_count = 0; + char *tag_strings[3]; + extern char *optarg; + char *commonname; + char **file; + struct stat statb; + + incompat = 0; + + argv0 = argv[0]; + + while ((c = getopt_long (argc, argv, "aeimvx3AEXL:", longopts, (int *) 0)) + != EOF) + { + switch (c) + { + case 'a': + always_text = 1; + break; + case 'A': + show_2nd = 1; + flagging = 1; + incompat++; + break; + case 'x': + overlap_only = 1; + incompat++; + break; + case '3': + simple_only = 1; + incompat++; + break; + case 'i': + finalwrite = 1; + break; + case 'm': + merge = 1; + break; + case 'X': + overlap_only = 1; + /* Falls through */ + case 'E': + flagging = 1; + /* Falls through */ + case 'e': + incompat++; + break; + case 'v': + fprintf (stderr, "GNU diff3 version %s\n", version_string); + break; + case 'L': + /* Handle up to three -L options. */ + if (tag_count < 3) + { + tag_strings[tag_count++] = optarg; + break; + } + /* Falls through */ + default: + usage (); + /* NOTREACHED */ + } + } + + edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */ + show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */ + flagging |= ~incompat & merge; + + if (incompat > 1 /* Ensure at most one of -AeExX3. */ + || finalwrite & merge /* -i -m would rewrite input file. */ + || (tag_count && ! flagging) /* -L requires one of -AEX. */ + || argc - optind != 3) + usage (); + + file = &argv[optind]; + + for (i = tag_count; i < 3; i++) + tag_strings[i] = file[i]; + + /* Always compare file1 to file2, even if file2 is "-". + This is needed for -mAeExX3. Using the file0 as + the common file would produce wrong results, because if the + file0-file1 diffs didn't line up with the file0-file2 diffs + (which is entirely possible since we don't use diff's -n option), + diff3 might report phantom changes from file1 to file2. */ + + if (strcmp (file[2], "-") == 0) + { + /* Sigh. We've got standard input as the last arg. We can't + call diff twice on stdin. Use the middle arg as the common + file instead. */ + if (strcmp (file[0], "-") == 0 || strcmp (file[1], "-") == 0) + fatal ("`-' specified for more than one input file"); + mapping[0] = 0; + mapping[1] = 2; + mapping[2] = 1; + } + else + { + /* Normal, what you'd expect */ + mapping[0] = 0; + mapping[1] = 1; + mapping[2] = 2; + } + + for (i = 0; i < 3; i++) + rev_mapping[mapping[i]] = i; + + for (i = 0; i < 3; i++) + if (strcmp (file[i], "-") != 0) + if (stat (file[i], &statb) < 0) + perror_with_exit (file[i]); + else if (S_ISDIR(statb.st_mode)) + { + fprintf (stderr, "%s: %s: Is a directory\n", argv0, file[i]); + exit (2); + } + + + commonname = file[rev_mapping[FILEC]]; + thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block); + if (thread1) + for (i = 0; i < 2; i++) + { + horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i)); + horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i)); + } + thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block); + diff3 = make_3way_diff (thread0, thread1); + if (edscript) + conflicts_found + = output_diff3_edscript (stdout, diff3, mapping, rev_mapping, + tag_strings[0], tag_strings[1], tag_strings[2]); + else if (merge) + { + if (! freopen (file[rev_mapping[FILE0]], "r", stdin)) + perror_with_exit (file[rev_mapping[FILE0]]); + conflicts_found + = output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping, + tag_strings[0], tag_strings[1], tag_strings[2]); + if (ferror (stdin)) + fatal ("read error"); + } + else + { + output_diff3 (stdout, diff3, mapping, rev_mapping); + conflicts_found = 0; + } + + if (ferror (stdout) || fclose (stdout) != 0) + fatal ("write error"); + exit (conflicts_found); + return conflicts_found; +} + +/* + * Explain, patiently and kindly, how to use this program. Then exit. + */ +static void +usage () +{ + fprintf (stderr, "\ +Usage: %s [options] my-file older-file your-file\n\ +Options:\n\ + [-exAEX3v] [-i|-m] [-L label1 [-L label2 [-L label3]]] [--text] [--ed]\n\ + [--merge] [--show-all] [--show-overlap] [--overlap-only] [--easy-only]\n\ + [--label=label1 [--label=label2 [--label=label3]]] [--version]\n\ + Only one of [exAEX3] is allowed\n", argv0); + exit (2); +} + +/* + * Routines that combine the two diffs together into one. The + * algorithm used follows: + * + * File2 is shared in common between the two diffs. + * Diff02 is the diff between 0 and 2. + * Diff12 is the diff between 1 and 2. + * + * 1) Find the range for the first block in File2. + * a) Take the lowest of the two ranges (in File2) in the two + * current blocks (one from each diff) as being the low + * water mark. Assign the upper end of this block as + * being the high water mark and move the current block up + * one. Mark the block just moved over as to be used. + * b) Check the next block in the diff that the high water + * mark is *not* from. + * + * *If* the high water mark is above + * the low end of the range in that block, + * + * mark that block as to be used and move the current + * block up. Set the high water mark to the max of + * the high end of this block and the current. Repeat b. + * + * 2) Find the corresponding ranges in File0 (from the blocks + * in diff02; line per line outside of diffs) and in File1. + * Create a diff3_block, reserving space as indicated by the ranges. + * + * 3) Copy all of the pointers for file2 in. At least for now, + * do bcmp's between corresponding strings in the two diffs. + * + * 4) Copy all of the pointers for file0 and 1 in. Get what you + * need from file2 (when there isn't a diff block, it's + * identical to file2 within the range between diff blocks). + * + * 5) If the diff blocks you used came from only one of the two + * strings of diffs, then that file (i.e. the one other than + * the common file in that diff) is the odd person out. If you used + * diff blocks from both sets, check to see if files 0 and 1 match: + * + * Same number of lines? If so, do a set of bcmp's (if a + * bcmp matches; copy the pointer over; it'll be easier later + * if you have to do any compares). If they match, 0 & 1 are + * the same. If not, all three different. + * + * Then you do it again, until you run out of blocks. + * + */ + +/* + * This routine makes a three way diff (chain of diff3_block's) from two + * two way diffs (chains of diff_block's). It is assumed that each of + * the two diffs passed are onto the same file (i.e. that each of the + * diffs were made "to" the same file). The three way diff pointer + * returned will have numbering FILE0--the other file in diff02, + * FILE1--the other file in diff12, and FILEC--the common file. + */ +static struct diff3_block * +make_3way_diff (thread0, thread1) + struct diff_block *thread0, *thread1; +{ +/* + * This routine works on the two diffs passed to it as threads. + * Thread number 0 is diff02, thread number 1 is diff12. The USING + * array is set to the base of the list of blocks to be used to + * construct each block of the three way diff; if no blocks from a + * particular thread are to be used, that element of the using array + * is set to 0. The elements LAST_USING array are set to the last + * elements on each of the using lists. + * + * The HIGH_WATER_MARK is set to the highest line number in the common file + * described in any of the diffs in either of the USING lists. The + * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK + * and BASE_WATER_THREAD describe the lowest line number in the common file + * described in any of the diffs in either of the USING lists. The + * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was + * taken. + * + * The HIGH_WATER_DIFF should always be equal to LAST_USING + * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for + * higher water, and should always be equal to + * CURRENT[HIGH_WATER_THREAD ^ 0x1]. The OTHER_THREAD is the thread + * in which the OTHER_DIFF is, and hence should always be equal to + * HIGH_WATER_THREAD ^ 0x1. + * + * The variable LAST_DIFF is kept set to the last diff block produced + * by this routine, for line correspondence purposes between that diff + * and the one currently being worked on. It is initialized to + * ZERO_DIFF before any blocks have been created. + */ + + struct diff_block + *using[2], + *last_using[2], + *current[2]; + + int + high_water_mark; + + int + high_water_thread, + base_water_thread, + other_thread; + + struct diff_block + *high_water_diff, + *other_diff; + + struct diff3_block + *result, + *tmpblock, + **result_end, + *last_diff3; + + static struct diff3_block zero_diff3 = { + ERROR, + { {0, 0}, {0, 0}, {0, 0} }, + { (char **) 0, (char **) 0, (char **) 0 }, + { (int *) 0, (int *) 0, (int *) 0 }, + (struct diff3_block *) 0 + }; + + /* Initialization */ + result = 0; + result_end = &result; + current[0] = thread0; current[1] = thread1; + last_diff3 = &zero_diff3; + + /* Sniff up the threads until we reach the end */ + + while (current[0] || current[1]) + { + using[0] = using[1] = last_using[0] = last_using[1] = + (struct diff_block *) 0; + + /* Setup low and high water threads, diffs, and marks. */ + if (!current[0]) + base_water_thread = 1; + else if (!current[1]) + base_water_thread = 0; + else + base_water_thread = + (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC)); + + high_water_thread = base_water_thread; + + high_water_diff = current[high_water_thread]; + +#if 0 + /* low and high waters start off same diff */ + base_water_mark = D_LOWLINE (high_water_diff, FC); +#endif + + high_water_mark = D_HIGHLINE (high_water_diff, FC); + + /* Make the diff you just got info from into the using class */ + using[high_water_thread] + = last_using[high_water_thread] + = high_water_diff; + current[high_water_thread] = high_water_diff->next; + last_using[high_water_thread]->next + = (struct diff_block *) 0; + + /* And mark the other diff */ + other_thread = high_water_thread ^ 0x1; + other_diff = current[other_thread]; + + /* Shuffle up the ladder, checking the other diff to see if it + needs to be incorporated. */ + while (other_diff + && D_LOWLINE (other_diff, FC) <= high_water_mark + 1) + { + + /* Incorporate this diff into the using list. Note that + this doesn't take it off the current list */ + if (using[other_thread]) + last_using[other_thread]->next = other_diff; + else + using[other_thread] = other_diff; + last_using[other_thread] = other_diff; + + /* Take it off the current list. Note that this following + code assumes that other_diff enters it equal to + current[high_water_thread ^ 0x1] */ + current[other_thread] + = current[other_thread]->next; + other_diff->next + = (struct diff_block *) 0; + + /* Set the high_water stuff + If this comparison is equal, then this is the last pass + through this loop; since diff blocks within a given + thread cannot overlap, the high_water_mark will be + *below* the range_start of either of the next diffs. */ + + if (high_water_mark < D_HIGHLINE (other_diff, FC)) + { + high_water_thread ^= 1; + high_water_diff = other_diff; + high_water_mark = D_HIGHLINE (other_diff, FC); + } + + /* Set the other diff */ + other_thread = high_water_thread ^ 0x1; + other_diff = current[other_thread]; + } + + /* The using lists contain a list of all of the blocks to be + included in this diff3_block. Create it. */ + + tmpblock = using_to_diff3_block (using, last_using, + base_water_thread, high_water_thread, + last_diff3); + + if (!tmpblock) + fatal ("internal error: screwup in format of diff blocks"); + + /* Put it on the list. */ + *result_end = tmpblock; + result_end = &tmpblock->next; + + /* Set up corresponding lines correctly. */ + last_diff3 = tmpblock; + } + return result; +} + +/* + * using_to_diff3_block: + * This routine takes two lists of blocks (from two separate diff + * threads) and puts them together into one diff3 block. + * It then returns a pointer to this diff3 block or 0 for failure. + * + * All arguments besides using are for the convenience of the routine; + * they could be derived from the using array. + * LAST_USING is a pair of pointers to the last blocks in the using + * structure. + * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest + * and highest line numbers for File0. + * last_diff3 contains the last diff produced in the calling routine. + * This is used for lines mappings which would still be identical to + * the state that diff ended in. + * + * A distinction should be made in this routine between the two diffs + * that are part of a normal two diff block, and the three diffs that + * are part of a diff3_block. + */ +static struct diff3_block * +using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3) + struct diff_block + *using[2], + *last_using[2]; + int low_thread, high_thread; + struct diff3_block *last_diff3; +{ + int low[2], high[2]; + struct diff3_block *result; + struct diff_block *ptr; + int d, i; + + /* Find the range in the common file. */ + int lowc = D_LOWLINE (using[low_thread], FC); + int highc = D_HIGHLINE (last_using[high_thread], FC); + + /* Find the ranges in the other files. + If using[d] is null, that means that the file to which that diff + refers is equivalent to the common file over this range. */ + + for (d = 0; d < 2; d++) + if (using[d]) + { + low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc); + high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc); + } + else + { + low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc); + high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc); + } + + /* Create a block with the appropriate sizes */ + result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc); + + /* Copy information for the common file. + Return with a zero if any of the compares failed. */ + + for (d = 0; d < 2; d++) + for (ptr = using[d]; ptr; ptr = D_NEXT (ptr)) + { + int result_offset = D_LOWLINE (ptr, FC) - lowc; + + if (!copy_stringlist (D_LINEARRAY (ptr, FC), + D_LENARRAY (ptr, FC), + D_LINEARRAY (result, FILEC) + result_offset, + D_LENARRAY (result, FILEC) + result_offset, + D_NUMLINES (ptr, FC))) + return 0; + } + + /* Copy information for file d. First deal with anything that might be + before the first diff. */ + + for (d = 0; d < 2; d++) + { + struct diff_block *u = using[d]; + int lo = low[d], hi = high[d]; + + for (i = 0; + i + lo < (u ? D_LOWLINE (u, FO) : hi + 1); + i++) + { + D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i); + D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i); + } + + for (ptr = u; ptr; ptr = D_NEXT (ptr)) + { + int result_offset = D_LOWLINE (ptr, FO) - lo; + int linec; + + if (!copy_stringlist (D_LINEARRAY (ptr, FO), + D_LENARRAY (ptr, FO), + D_LINEARRAY (result, FILE0 + d) + result_offset, + D_LENARRAY (result, FILE0 + d) + result_offset, + D_NUMLINES (ptr, FO))) + return 0; + + /* Catch the lines between here and the next diff */ + linec = D_HIGHLINE (ptr, FC) + 1 - lowc; + for (i = D_HIGHLINE (ptr, FO) + 1 - lo; + i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo; + i++) + { + D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec); + D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec); + linec++; + } + } + } + + /* Set correspond */ + if (!using[0]) + D3_TYPE (result) = DIFF_2ND; + else if (!using[1]) + D3_TYPE (result) = DIFF_1ST; + else + { + int nl0 = D_NUMLINES (result, FILE0); + int nl1 = D_NUMLINES (result, FILE1); + + if (nl0 != nl1 + || !compare_line_list (D_LINEARRAY (result, FILE0), + D_LENARRAY (result, FILE0), + D_LINEARRAY (result, FILE1), + D_LENARRAY (result, FILE1), + nl0)) + D3_TYPE (result) = DIFF_ALL; + else + D3_TYPE (result) = DIFF_3RD; + } + + return result; +} + +/* + * This routine copies pointers from a list of strings to a different list + * of strings. If a spot in the second list is already filled, it + * makes sure that it is filled with the same string; if not it + * returns 0, the copy incomplete. + * Upon successful completion of the copy, it returns 1. + */ +static int +copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum) + char *fromptrs[], *toptrs[]; + int *fromlengths, *tolengths; + int copynum; +{ + register char + **f = fromptrs, + **t = toptrs; + register int + *fl = fromlengths, + *tl = tolengths; + + while (copynum--) + { + if (*t) + { if (*fl != *tl || bcmp (*f, *t, *fl)) return 0; } + else + { *t = *f ; *tl = *fl; } + + t++; f++; tl++; fl++; + } + return 1; +} + +/* + * Create a diff3_block, with ranges as specified in the arguments. + * Allocate the arrays for the various pointers (and zero them) based + * on the arguments passed. Return the block as a result. + */ +static struct diff3_block * +create_diff3_block (low0, high0, low1, high1, low2, high2) + register int low0, high0, low1, high1, low2, high2; +{ + struct diff3_block *result = ALLOCATE (1, struct diff3_block); + int numlines; + + D3_TYPE (result) = ERROR; + D_NEXT (result) = 0; + + /* Assign ranges */ + D_LOWLINE (result, FILE0) = low0; + D_HIGHLINE (result, FILE0) = high0; + D_LOWLINE (result, FILE1) = low1; + D_HIGHLINE (result, FILE1) = high1; + D_LOWLINE (result, FILE2) = low2; + D_HIGHLINE (result, FILE2) = high2; + + /* Allocate and zero space */ + numlines = D_NUMLINES (result, FILE0); + if (numlines) + { + D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *); + D_LENARRAY (result, FILE0) = ALLOCATE (numlines, int); + bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *))); + bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (int))); + } + else + { + D_LINEARRAY (result, FILE0) = (char **) 0; + D_LENARRAY (result, FILE0) = (int *) 0; + } + + numlines = D_NUMLINES (result, FILE1); + if (numlines) + { + D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *); + D_LENARRAY (result, FILE1) = ALLOCATE (numlines, int); + bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *))); + bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (int))); + } + else + { + D_LINEARRAY (result, FILE1) = (char **) 0; + D_LENARRAY (result, FILE1) = (int *) 0; + } + + numlines = D_NUMLINES (result, FILE2); + if (numlines) + { + D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *); + D_LENARRAY (result, FILE2) = ALLOCATE (numlines, int); + bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *))); + bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (int))); + } + else + { + D_LINEARRAY (result, FILE2) = (char **) 0; + D_LENARRAY (result, FILE2) = (int *) 0; + } + + /* Return */ + return result; +} + +/* + * Compare two lists of lines of text. + * Return 1 if they are equivalent, 0 if not. + */ +static int +compare_line_list (list1, lengths1, list2, lengths2, nl) + char *list1[], *list2[]; + int *lengths1, *lengths2; + int nl; +{ + char + **l1 = list1, + **l2 = list2; + int + *lgths1 = lengths1, + *lgths2 = lengths2; + + while (nl--) + if (!*l1 || !*l2 || *lgths1 != *lgths2++ + || bcmp (*l1++, *l2++, *lgths1++)) + return 0; + return 1; +} + +/* + * Routines to input and parse two way diffs. + */ + +extern char **environ; + +#define DIFF_CHUNK_SIZE 10000 + +static struct diff_block * +process_diff (filea, fileb, last_block) + char *filea, *fileb; + struct diff_block **last_block; +{ + char *diff_contents; + char *diff_limit; + char *scan_diff; + enum diff_type dt; + int i; + struct diff_block *block_list, **block_list_end, *bptr; + + diff_limit = read_diff (filea, fileb, &diff_contents); + scan_diff = diff_contents; + block_list_end = &block_list; + + while (scan_diff < diff_limit) + { + bptr = ALLOCATE (1, struct diff_block); + bptr->lines[0] = bptr->lines[1] = (char **) 0; + bptr->lengths[0] = bptr->lengths[1] = (int *) 0; + + dt = process_diff_control (&scan_diff, bptr); + if (dt == ERROR || *scan_diff != '\n') + { + fprintf (stderr, "%s: diff error: ", argv0); + do + { + putc (*scan_diff, stderr); + } + while (*scan_diff++ != '\n'); + exit (2); + } + scan_diff++; + + /* Force appropriate ranges to be null, if necessary */ + switch (dt) + { + case ADD: + bptr->ranges[0][0]++; + break; + case DELETE: + bptr->ranges[1][0]++; + break; + case CHANGE: + break; + default: + fatal ("internal error: invalid diff type in process_diff"); + break; + } + + /* Allocate space for the pointers for the lines from filea, and + parcel them out among these pointers */ + if (dt != ADD) + { + int numlines = D_NUMLINES (bptr, 0); + bptr->lines[0] = ALLOCATE (numlines, char *); + bptr->lengths[0] = ALLOCATE (numlines, int); + for (i = 0; i < numlines; i++) + scan_diff = scan_diff_line (scan_diff, + &(bptr->lines[0][i]), + &(bptr->lengths[0][i]), + diff_limit, + '<'); + } + + /* Get past the separator for changes */ + if (dt == CHANGE) + { + if (strncmp (scan_diff, "---\n", 4)) + fatal ("invalid diff format; invalid change separator"); + scan_diff += 4; + } + + /* Allocate space for the pointers for the lines from fileb, and + parcel them out among these pointers */ + if (dt != DELETE) + { + int numlines = D_NUMLINES (bptr, 1); + bptr->lines[1] = ALLOCATE (numlines, char *); + bptr->lengths[1] = ALLOCATE (numlines, int); + for (i = 0; i < numlines; i++) + scan_diff = scan_diff_line (scan_diff, + &(bptr->lines[1][i]), + &(bptr->lengths[1][i]), + diff_limit, + '>'); + } + + /* Place this block on the blocklist. */ + *block_list_end = bptr; + block_list_end = &bptr->next; + } + + *block_list_end = 0; + *last_block = bptr; + return block_list; +} + +/* + * This routine will parse a normal format diff control string. It + * returns the type of the diff (ERROR if the format is bad). All of + * the other important information is filled into to the structure + * pointed to by db, and the string pointer (whose location is passed + * to this routine) is updated to point beyond the end of the string + * parsed. Note that only the ranges in the diff_block will be set by + * this routine. + * + * If some specific pair of numbers has been reduced to a single + * number, then both corresponding numbers in the diff block are set + * to that number. In general these numbers are interpetted as ranges + * inclusive, unless being used by the ADD or DELETE commands. It is + * assumed that these will be special cased in a superior routine. + */ + +static enum diff_type +process_diff_control (string, db) + char **string; + struct diff_block *db; +{ + char *s = *string; + int holdnum; + enum diff_type type; + +/* These macros are defined here because they can use variables + defined in this function. Don't try this at home kids, we're + trained professionals! + + Also note that SKIPWHITE only recognizes tabs and spaces, and + that READNUM can only read positive, integral numbers */ + +#define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; } +#define READNUM(s, num) \ + { if (!isdigit (*s)) return ERROR; holdnum = 0; \ + do { holdnum = (*s++ - '0' + holdnum * 10); } \ + while (isdigit (*s)); (num) = holdnum; } + + /* Read first set of digits */ + SKIPWHITE (s); + READNUM (s, db->ranges[0][START]); + + /* Was that the only digit? */ + SKIPWHITE (s); + if (*s == ',') + { + /* Get the next digit */ + s++; + READNUM (s, db->ranges[0][END]); + } + else + db->ranges[0][END] = db->ranges[0][START]; + + /* Get the letter */ + SKIPWHITE (s); + switch (*s) + { + case 'a': + type = ADD; + break; + case 'c': + type = CHANGE; + break; + case 'd': + type = DELETE; + break; + default: + return ERROR; /* Bad format */ + } + s++; /* Past letter */ + + /* Read second set of digits */ + SKIPWHITE (s); + READNUM (s, db->ranges[1][START]); + + /* Was that the only digit? */ + SKIPWHITE (s); + if (*s == ',') + { + /* Get the next digit */ + s++; + READNUM (s, db->ranges[1][END]); + SKIPWHITE (s); /* To move to end */ + } + else + db->ranges[1][END] = db->ranges[1][START]; + + *string = s; + return type; +} + +static char * +read_diff (filea, fileb, output_placement) + char *filea, *fileb; + char **output_placement; +{ + char *argv[7]; + char horizon_arg[256]; + char **ap; + int fds[2]; + char *diff_result; + int current_chunk_size; + int bytes; + int total; + int pid, w; + int wstatus; + + ap = argv; + *ap++ = diff_program; + if (always_text) + *ap++ = "-a"; + sprintf (horizon_arg, "--horizon-lines=%d", horizon_lines); + *ap++ = horizon_arg; + *ap++ = "--"; + *ap++ = filea; + *ap++ = fileb; + *ap = (char *) 0; + + if (pipe (fds) < 0) + perror_with_exit ("pipe failed"); + + pid = vfork (); + if (pid == 0) + { + /* Child */ + close (fds[0]); + if (fds[1] != fileno (stdout)) + { + dup2 (fds[1], fileno (stdout)); + close (fds[1]); + } + execve (diff_program, argv, environ); + /* Avoid stdio, because the parent process's buffers are inherited. */ + write (fileno (stderr), diff_program, strlen (diff_program)); + write (fileno (stderr), ": not found\n", 12); + _exit (2); + } + + if (pid == -1) + perror_with_exit ("fork failed"); + + close (fds[1]); /* Prevent erroneous lack of EOF */ + current_chunk_size = DIFF_CHUNK_SIZE; + diff_result = (char *) xmalloc (current_chunk_size); + total = 0; + do { + bytes = myread (fds[0], + diff_result + total, + current_chunk_size - total); + total += bytes; + if (total == current_chunk_size) + diff_result = (char *) xrealloc (diff_result, (current_chunk_size *= 2)); + } while (bytes); + + if (total != 0 && diff_result[total-1] != '\n') + fatal ("invalid diff format; incomplete last line"); + + *output_placement = diff_result; + + do + if ((w = wait (&wstatus)) == -1) + perror_with_exit ("wait failed"); + while (w != pid); + + if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2)) + fatal ("subsidiary diff failed"); + + return diff_result + total; +} + + +/* + * Scan a regular diff line (consisting of > or <, followed by a + * space, followed by text (including nulls) up to a newline. + * + * This next routine began life as a macro and many parameters in it + * are used as call-by-reference values. + */ +static char * +scan_diff_line (scan_ptr, set_start, set_length, limit, firstchar) + char *scan_ptr, **set_start; + int *set_length; + char *limit; + char firstchar; +{ + char *line_ptr; + + if (!(scan_ptr[0] == (firstchar) + && scan_ptr[1] == ' ')) + fatal ("invalid diff format; incorrect leading line chars"); + + *set_start = line_ptr = scan_ptr + 2; + while (*line_ptr++ != '\n') + ; + + /* Include newline if the original line ended in a newline, + or if an edit script is being generated. + Copy any missing newline message to stderr if an edit script is being + generated, because edit scripts cannot handle missing newlines. + Return the beginning of the next line. */ + *set_length = line_ptr - *set_start; + if (line_ptr < limit && *line_ptr == '\\') + { + if (edscript) + fprintf (stderr, "%s:", argv0); + else + --*set_length; + line_ptr++; + do + { + if (edscript) + putc (*line_ptr, stderr); + } + while (*line_ptr++ != '\n'); + } + + return line_ptr; +} + +/* + * This routine outputs a three way diff passed as a list of + * diff3_block's. + * The argument MAPPING is indexed by external file number (in the + * argument list) and contains the internal file number (from the + * diff passed). This is important because the user expects his + * outputs in terms of the argument list number, and the diff passed + * may have been done slightly differently (if the last argument + * was "-", for example). + * REV_MAPPING is the inverse of MAPPING. + */ +static void +output_diff3 (outputfile, diff, mapping, rev_mapping) + FILE *outputfile; + struct diff3_block *diff; + int mapping[3], rev_mapping[3]; +{ + int i; + int oddoneout; + char *cp; + struct diff3_block *ptr; + int line; + int length; + int dontprint; + static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */ + + for (ptr = diff; ptr; ptr = D_NEXT (ptr)) + { + char x[2]; + + switch (ptr->correspond) + { + case DIFF_ALL: + x[0] = '\0'; + dontprint = 3; /* Print them all */ + oddoneout = 3; /* Nobody's odder than anyone else */ + break; + case DIFF_1ST: + case DIFF_2ND: + case DIFF_3RD: + oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST]; + + x[0] = oddoneout + '1'; + x[1] = '\0'; + dontprint = oddoneout==0; + break; + default: + fatal ("internal error: invalid diff type passed to output"); + } + fprintf (outputfile, "====%s\n", x); + + /* Go 0, 2, 1 if the first and third outputs are equivalent. */ + for (i = 0; i < 3; + i = (oddoneout == 1 ? skew_increment[i] : i + 1)) + { + int realfile = mapping[i]; + int + lowt = D_LOWLINE (ptr, realfile), + hight = D_HIGHLINE (ptr, realfile); + + fprintf (outputfile, "%d:", i + 1); + switch (lowt - hight) + { + case 1: + fprintf (outputfile, "%da\n", lowt - 1); + break; + case 0: + fprintf (outputfile, "%dc\n", lowt); + break; + default: + fprintf (outputfile, "%d,%dc\n", lowt, hight); + break; + } + + if (i == dontprint) continue; + + for (line = 0; line < hight - lowt + 1; line++) + { + fprintf (outputfile, " "); + cp = D_RELNUM (ptr, realfile, line); + length = D_RELLEN (ptr, realfile, line); + fwrite (cp, sizeof (char), length, outputfile); + } + if (line != 0 && cp[length - 1] != '\n') + fprintf (outputfile, "\n\\ No newline at end of file\n"); + } + } +} + + +/* + * Output to OUTPUTFILE the lines of B taken from FILENUM. + * Double any initial '.'s; yield nonzero if any initial '.'s were doubled. + */ +static int +dotlines (outputfile, b, filenum) + FILE *outputfile; + struct diff3_block *b; + int filenum; +{ + int i; + int leading_dot = 0; + + for (i = 0; + i < D_NUMLINES (b, filenum); + i++) + { + char *line = D_RELNUM (b, filenum, i); + if (line[0] == '.') + { + leading_dot = 1; + fprintf (outputfile, "."); + } + fwrite (line, sizeof (char), + D_RELLEN (b, filenum, i), outputfile); + } + + return leading_dot; +} + +/* + * Output to OUTPUTFILE a '.' line. If LEADING_DOT is nonzero, + * also output a command that removes initial '.'s + * starting with line START and continuing for NUM lines. + */ +static void +undotlines (outputfile, leading_dot, start, num) + FILE *outputfile; + int leading_dot, start, num; +{ + fprintf (outputfile, ".\n"); + if (leading_dot) + if (num == 1) + fprintf (outputfile, "%ds/^\\.//\n", start); + else + fprintf (outputfile, "%d,%ds/^\\.//\n", start, start + num - 1); +} + +/* + * This routine outputs a diff3 set of blocks as an ed script. This + * script applies the changes between file's 2 & 3 to file 1. It + * takes the precise format of the ed script to be output from global + * variables set during options processing. Note that it does + * destructive things to the set of diff3 blocks it is passed; it + * reverses their order (this gets around the problems involved with + * changing line numbers in an ed script). + * + * Note that this routine has the same problem of mapping as the last + * one did; the variable MAPPING maps from file number according to + * the argument list to file number according to the diff passed. All + * files listed below are in terms of the argument list. + * REV_MAPPING is the inverse of MAPPING. + * + * The arguments FILE0, FILE1 and FILE2 are the strings to print + * as the names of the three files. These may be the actual names, + * or may be the arguments specified with -L. + * + * Returns 1 if conflicts were found. + */ + +static int +output_diff3_edscript (outputfile, diff, mapping, rev_mapping, + file0, file1, file2) + FILE *outputfile; + struct diff3_block *diff; + int mapping[3], rev_mapping[3]; + char *file0, *file1, *file2; +{ + int leading_dot; + int conflicts_found = 0, conflict; + struct diff3_block *b; + + for (b = reverse_diff3_blocklist (diff); b; b = b->next) + { + /* Must do mapping correctly. */ + enum diff_type type + = ((b->correspond == DIFF_ALL) ? + DIFF_ALL : + ((enum diff_type) + (((int) DIFF_1ST) + + rev_mapping[(int) b->correspond - (int) DIFF_1ST]))); + + /* If we aren't supposed to do this output block, skip it. */ + switch (type) + { + default: continue; + case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break; + case DIFF_3RD: if (overlap_only) continue; conflict = 0; break; + case DIFF_ALL: if (simple_only) continue; conflict = flagging; break; + } + + if (conflict) + { + conflicts_found = 1; + + + /* Mark end of conflict. */ + + fprintf (outputfile, "%da\n", D_HIGHLINE (b, mapping[FILE0])); + leading_dot = 0; + if (type == DIFF_ALL) + { + if (show_2nd) + { + /* Append lines from FILE1. */ + fprintf (outputfile, "||||||| %s\n", file1); + leading_dot = dotlines (outputfile, b, mapping[FILE1]); + } + /* Append lines from FILE2. */ + fprintf (outputfile, "=======\n"); + leading_dot |= dotlines (outputfile, b, mapping[FILE2]); + } + fprintf (outputfile, ">>>>>>> %s\n", file2); + undotlines (outputfile, leading_dot, + D_HIGHLINE (b, mapping[FILE0]) + 2, + (D_NUMLINES (b, mapping[FILE1]) + + D_NUMLINES (b, mapping[FILE2]) + 1)); + + + /* Mark start of conflict. */ + + fprintf (outputfile, "%da\n<<<<<<< %s\n", + D_LOWLINE (b, mapping[FILE0]) - 1, + type == DIFF_ALL ? file0 : file1); + leading_dot = 0; + if (type == DIFF_2ND) + { + /* Prepend lines from FILE1. */ + leading_dot = dotlines (outputfile, b, mapping[FILE1]); + fprintf (outputfile, "=======\n"); + } + undotlines (outputfile, leading_dot, + D_LOWLINE (b, mapping[FILE0]) + 1, + D_NUMLINES (b, mapping[FILE1])); + } + else if (D_NUMLINES (b, mapping[FILE2]) == 0) + /* Write out a delete */ + { + if (D_NUMLINES (b, mapping[FILE0]) == 1) + fprintf (outputfile, "%dd\n", + D_LOWLINE (b, mapping[FILE0])); + else + fprintf (outputfile, "%d,%dd\n", + D_LOWLINE (b, mapping[FILE0]), + D_HIGHLINE (b, mapping[FILE0])); + } + else + /* Write out an add or change */ + { + switch (D_NUMLINES (b, mapping[FILE0])) + { + case 0: + fprintf (outputfile, "%da\n", + D_HIGHLINE (b, mapping[FILE0])); + break; + case 1: + fprintf (outputfile, "%dc\n", + D_HIGHLINE (b, mapping[FILE0])); + break; + default: + fprintf (outputfile, "%d,%dc\n", + D_LOWLINE (b, mapping[FILE0]), + D_HIGHLINE (b, mapping[FILE0])); + break; + } + + undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]), + D_LOWLINE (b, mapping[FILE0]), + D_NUMLINES (b, mapping[FILE2])); + } + } + if (finalwrite) fprintf (outputfile, "w\nq\n"); + return conflicts_found; +} + +/* + * Read from INFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF + * as a merged file. This acts like 'ed file0 <[output_diff3_edscript]', + * except that it works even for binary data or incomplete lines. + * + * As before, MAPPING maps from arg list file number to diff file number, + * REV_MAPPING is its inverse, + * and FILE0, FILE1, and FILE2 are the names of the files. + * + * Returns 1 if conflicts were found. + */ + +static int +output_diff3_merge (infile, outputfile, diff, mapping, rev_mapping, + file0, file1, file2) + FILE *infile, *outputfile; + struct diff3_block *diff; + int mapping[3], rev_mapping[3]; + char *file0, *file1, *file2; +{ + int c, i; + int conflicts_found = 0, conflict; + struct diff3_block *b; + int linesread = 0; + + for (b = diff; b; b = b->next) + { + /* Must do mapping correctly. */ + enum diff_type type + = ((b->correspond == DIFF_ALL) ? + DIFF_ALL : + ((enum diff_type) + (((int) DIFF_1ST) + + rev_mapping[(int) b->correspond - (int) DIFF_1ST]))); + char *format_2nd = "<<<<<<< %s\n"; + + /* If we aren't supposed to do this output block, skip it. */ + switch (type) + { + default: continue; + case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break; + case DIFF_3RD: if (overlap_only) continue; conflict = 0; break; + case DIFF_ALL: if (simple_only) continue; conflict = flagging; + format_2nd = "||||||| %s\n"; + break; + } + + /* Copy I lines from file 0. */ + i = D_LOWLINE (b, FILE0) - linesread - 1; + linesread += i; + while (0 <= --i) + do + { + c = getc (infile); + if (c == EOF) + if (ferror (infile)) + perror_with_exit ("input file"); + else if (feof (infile)) + fatal ("input file shrank"); + putc (c, outputfile); + } + while (c != '\n'); + + if (conflict) + { + conflicts_found = 1; + + if (type == DIFF_ALL) + { + /* Put in lines from FILE0 with bracket. */ + fprintf (outputfile, "<<<<<<< %s\n", file0); + for (i = 0; + i < D_NUMLINES (b, mapping[FILE0]); + i++) + fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char), + D_RELLEN (b, mapping[FILE0], i), outputfile); + } + + if (show_2nd) + { + /* Put in lines from FILE1 with bracket. */ + fprintf (outputfile, format_2nd, file1); + for (i = 0; + i < D_NUMLINES (b, mapping[FILE1]); + i++) + fwrite (D_RELNUM (b, mapping[FILE1], i), sizeof (char), + D_RELLEN (b, mapping[FILE1], i), outputfile); + } + + fprintf (outputfile, "=======\n"); + } + + /* Put in lines from FILE2. */ + for (i = 0; + i < D_NUMLINES (b, mapping[FILE2]); + i++) + fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char), + D_RELLEN (b, mapping[FILE2], i), outputfile); + + if (conflict) + fprintf (outputfile, ">>>>>>> %s\n", file2); + + /* Skip I lines in file 0. */ + i = D_NUMLINES (b, FILE0); + linesread += i; + while (0 <= --i) + while ((c = getc (infile)) != '\n') + if (c == EOF) + if (ferror (infile)) + perror_with_exit ("input file"); + else if (feof (infile)) + { + if (i || b->next) + fatal ("input file shrank"); + return conflicts_found; + } + } + /* Copy rest of common file. */ + while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile))) + putc (c, outputfile); + return conflicts_found; +} + +/* + * Reverse the order of the list of diff3 blocks. + */ +static struct diff3_block * +reverse_diff3_blocklist (diff) + struct diff3_block *diff; +{ + register struct diff3_block *tmp, *next, *prev; + + for (tmp = diff, prev = (struct diff3_block *) 0; + tmp; tmp = next) + { + next = tmp->next; + tmp->next = prev; + prev = tmp; + } + + return prev; +} + +static int +myread (fd, ptr, size) + int fd, size; + char *ptr; +{ + int result = read (fd, ptr, size); + if (result < 0) + perror_with_exit ("read failed"); + return result; +} + +VOID * +xmalloc (size) + unsigned size; +{ + VOID *result = (VOID *) malloc (size ? size : 1); + if (!result) + fatal ("virtual memory exhausted"); + return result; +} + +static VOID * +xrealloc (ptr, size) + VOID *ptr; + unsigned size; +{ + VOID *result = (VOID *) realloc (ptr, size ? size : 1); + if (!result) + fatal ("virtual memory exhausted"); + return result; +} + +static void +fatal (string) + char *string; +{ + fprintf (stderr, "%s: %s\n", argv0, string); + exit (2); +} + +static void +perror_with_exit (string) + char *string; +{ + int e = errno; + fprintf (stderr, "%s: ", argv0); + errno = e; + perror (string); + exit (2); +} diff --git a/gnu/usr.bin/diff/sdiff.c b/gnu/usr.bin/diff/sdiff.c new file mode 100644 index 0000000..7f1019e --- /dev/null +++ b/gnu/usr.bin/diff/sdiff.c @@ -0,0 +1,1067 @@ +/* SDIFF -- interactive merge front end to diff + Copyright (C) 1992 Free Software Foundation, Inc. + +This file is part of GNU DIFF. + +GNU DIFF is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU DIFF is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU DIFF; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* GNU SDIFF was written by Thomas Lord. */ + +#include <stdio.h> +#include <ctype.h> +#include "system.h" +#include <signal.h> +#include "getopt.h" + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +/* Size of chunks read from files which must be parsed into lines. */ +#define SDIFF_BUFSIZE 65536 + +/* Default name of the diff program */ +#ifndef DIFF_PROGRAM +#define DIFF_PROGRAM "/usr/bin/diff" +#endif + +/* Users' editor of nonchoice */ +#ifndef DEFAULT_EDITOR +#define DEFAULT_EDITOR "ed" +#endif + +extern char *version_string; +static char const *prog; +static char const *diffbin = DIFF_PROGRAM; +static char const *edbin = DEFAULT_EDITOR; + +static char *tmpname; +static int volatile tmpmade; +static pid_t volatile diffpid; + +struct line_filter; +static void diffarg (); /* (char *); */ +static void execdiff (); /* (int, char const *, char const *, char const *); */ +static int edit (); /* (struct line_filter *left, int lenl, struct + line_filter *right, int lenr, FILE *outfile); */ +static int interact (); /* (struct line_filter *diff, + struct line_filter *left, + struct line_filter *right, FILE *outfile); */ +static void trapsigs (); /* (void); */ +/* this lossage until the gnu libc conquers the universe */ +#define TMPNAMSIZE 1024 +#define PVT_tmpdir "/tmp" +static char *private_tempnam (); /* (const char *, const char *, int, int *); */ +static int diraccess (); + +/* Options: */ + +/* name of output file if -o spec'd */ +static char *out_file; + +/* do not print common lines if true, set by -s option */ +static int suppress_common_flag; + +static struct option longopts[] = +{ + {"ignore-blank-lines", 0, NULL, 'B'}, + {"speed-large-files", 0, NULL, 'H'}, + {"ignore-matching-lines", 1, NULL, 'I'}, + {"ignore-all-space", 0, NULL, 'W'}, /* swap W and w for historical reasons */ + {"text", 0, NULL, 'a'}, + {"ignore-space-change", 0, NULL, 'b'}, + {"minimal", 0, NULL, 'd'}, + {"ignore-case", 0, NULL, 'i'}, + {"left-column", 0, NULL, 'l'}, + {"output", 1, NULL, 'o'}, + {"suppress-common-lines", 0, NULL, 's'}, + {"expand-tabs", 0, NULL, 't'}, + {"width", 1, NULL, 'w'}, + {"version", 0, NULL, 'v'}, + {NULL, 0, NULL, 0} +}; + +/* prints usage message and quits */ +static void +usage () +{ + fprintf (stderr, "Usage: %s [options] from-file to-file\n", prog); + fprintf (stderr, "Options:\n\ + [-abBdHilstv] [-I regexp] [-o outfile] [-w columns]\n\ + [--text] [--minimal] [--speed-large-files] [--expand-tabs]\n\ + [--ignore-case] [--ignore-matching-lines=regexp]\n\ + [--ignore-space-change] [--ignore-blank-lines] [--ignore-all-space]\n\ + [--suppress-common-lines] [--left-column] [--output=outfile]\n\ + [--version] [--width=columns]\n"); + exit (2); +} + +static void +cleanup () +{ + if (0 < diffpid) + kill (diffpid, SIGPIPE); + if (tmpmade) + unlink (tmpname); +} + +static void +exiterr () +{ + cleanup (); + exit (2); +} + +static void +fatal (msg) + char *msg; +{ + fprintf (stderr, "%s: %s\n", prog, msg); + exiterr (); +} + +static void +perror_fatal (msg) + char *msg; +{ + int e = errno; + fprintf (stderr, "%s: ", prog); + errno = e; + perror (msg); + exiterr (); +} + + +/* malloc freely or DIE! */ +char * +xmalloc (size) + size_t size; +{ + char *r = malloc (size); + if (!r) + fatal ("virtual memory exhausted"); + return r; +} + +static FILE * +ck_fopen (fname, type) + char *fname, *type; +{ + FILE *r = fopen (fname, type); + if (!r) + perror_fatal (fname); + return r; +} + + +static FILE * +ck_fdopen (fd, type) + int fd; + char *type; +{ + FILE *r = fdopen (fd, type); + if (!r) + perror_fatal ("fdopen"); + return r; +} + +static void +ck_fclose (f) + FILE *f; +{ + if (fclose (f)) + perror_fatal ("input/output error"); +} + +static size_t +ck_fread (buf, size, f) + char *buf; + size_t size; + FILE *f; +{ + size_t r = fread (buf, sizeof (char), size, f); + if (r == 0 && ferror (f)) + perror_fatal ("input error"); + return r; +} + +static void +ck_fwrite (buf, size, f) + char *buf; + size_t size; + FILE *f; +{ + if (fwrite (buf, sizeof (char), size, f) != size) + perror_fatal ("output error"); +} + +static void +ck_fflush (f) + FILE *f; +{ + if (fflush (f) != 0) + perror_fatal ("output error"); +} + +#if !HAVE_MEMCHR +char * +memchr (s, c, n) + char *s; + int c; + size_t n; +{ + unsigned char *p = (unsigned char *) s, *lim = p + n; + for (; p < lim; p++) + if (*p == c) + return (char *) p; + return 0; +} +#endif + +#ifndef HAVE_WAITPID +/* Emulate waitpid well enough for sdiff, which has at most two children. */ +static pid_t +waitpid (pid, stat_loc, options) + pid_t pid; + int *stat_loc; + int options; +{ + static int ostatus; + static pid_t opid; + int npid, status; + + if (pid == opid) + { + opid = 0; + status = ostatus; + } + else + while ((npid = wait (&status)) != pid) + { + if (npid < 0) + return npid; + opid = npid; + ostatus = status; + } + *stat_loc = status; + return pid; +} +#endif + +static char const * +expand_name (name, isdir, other_name) + char *name; + int isdir; + char const *other_name; +{ + if (strcmp (name, "-") == 0) + fatal ("cannot interactively merge standard input"); + if (!isdir) + return name; + else + { + /* Yield NAME/BASE, where BASE is OTHER_NAME's basename. */ + const char + *p = rindex (other_name, '/'), + *base = p ? p+1 : other_name; + size_t namelen = strlen (name), baselen = strlen (base); + char *r = xmalloc (namelen + baselen + 2); + bcopy (name, r, namelen); + r[namelen] = '/'; + bcopy (base, r + namelen + 1, baselen + 1); + return r; + } +} + + + +struct line_filter { + FILE *infile; + char *bufpos; + char *buffer; + char *buflim; +}; + +static void +lf_init (lf, infile) + struct line_filter *lf; + FILE *infile; +{ + lf->infile = infile; + lf->bufpos = lf->buffer = lf->buflim = xmalloc (SDIFF_BUFSIZE + 1); + lf->buflim[0] = '\n'; +} + +/* Fill an exhausted line_filter buffer from its INFILE */ +static size_t +lf_refill (lf) + struct line_filter *lf; +{ + size_t s = ck_fread (lf->buffer, SDIFF_BUFSIZE, lf->infile); + lf->bufpos = lf->buffer; + lf->buflim = lf->buffer + s; + lf->buflim[0] = '\n'; + return s; +} + +/* Advance LINES on LF's infile, copying lines to OUTFILE */ +static void +lf_copy (lf, lines, outfile) + struct line_filter *lf; + int lines; + FILE *outfile; +{ + char *start = lf->bufpos; + + while (lines) + { + lf->bufpos = memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos); + if (! lf->bufpos) + { + ck_fwrite (start, lf->buflim - start, outfile); + if (! lf_refill (lf)) + return; + start = lf->bufpos; + } + else + { + --lines; + ++lf->bufpos; + } + } + + ck_fwrite (start, lf->bufpos - start, outfile); +} + +/* Advance LINES on LF's infile without doing output */ +static void +lf_skip (lf, lines) + struct line_filter *lf; + int lines; +{ + while (lines) + { + lf->bufpos = memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos); + if (! lf->bufpos) + { + if (! lf_refill (lf)) + break; + } + else + { + --lines; + ++lf->bufpos; + } + } +} + +/* Snarf a line into a buffer. Return EOF if EOF, 0 if error, 1 if OK. */ +static int +lf_snarf (lf, buffer, bufsize) + struct line_filter *lf; + char *buffer; + size_t bufsize; +{ + char *start = lf->bufpos; + + for (;;) + { + char *next = memchr (start, '\n', lf->buflim + 1 - start); + size_t s = next - start; + if (bufsize <= s) + return 0; + bcopy (start, buffer, s); + if (next < lf->buflim) + { + buffer[s] = 0; + lf->bufpos = next + 1; + return 1; + } + if (! lf_refill (lf)) + return s ? 0 : EOF; + buffer += s; + bufsize -= s; + start = next; + } +} + + + +int +main (argc, argv) + int argc; + char *argv[]; +{ + int opt; + int version_requested = 0; + char *editor = getenv ("EDITOR"); + char *differ = getenv ("DIFF"); + + prog = argv[0]; + if (editor) + edbin = editor; + if (differ) + diffbin = differ; + + diffarg ("diff"); + + /* parse command line args */ + while ((opt=getopt_long (argc, argv, "abBdHiI:lo:stvw:W", longopts, (int *)0)) != EOF) + { + switch (opt) + { + case 'a': + diffarg ("-a"); + break; + + case 'b': + diffarg ("-b"); + break; + + case 'B': + diffarg ("-B"); + break; + + case 'd': + diffarg ("-d"); + break; + + case 'H': + diffarg ("-H"); + break; + + case 'i': + diffarg ("-i"); + break; + + case 'I': + diffarg ("-I"); + diffarg (optarg); + break; + + case 'l': + diffarg ("--left-column"); + break; + + case 'o': + out_file = optarg; + break; + + case 's': + suppress_common_flag = 1; + break; + + case 't': + diffarg ("-t"); + break; + + case 'v': + version_requested = 1; + fprintf (stderr, "GNU sdiff version %s\n", version_string); + ck_fflush (stderr); + break; + + case 'w': + diffarg ("-W"); + diffarg (optarg); + break; + + case 'W': + diffarg ("-w"); + break; + + default: + usage (); + } + } + + /* check: did user just want version message? if so exit. */ + if (version_requested && argc - optind == 0) + exit (0); + + if (argc - optind != 2) + usage (); + + if (! out_file) + /* easy case: diff does everything for us */ + execdiff (suppress_common_flag, "-y", argv[optind], argv[optind + 1]); + else + { + FILE *left, *right, *out, *diffout; + int diff_fds[2]; + int interact_ok; + pid_t pid; + struct line_filter lfilt; + struct line_filter rfilt; + struct line_filter diff_filt; + int leftdir = diraccess (argv[optind]); + int rightdir = diraccess (argv[optind + 1]); + + if (leftdir && rightdir) + fatal ("both files to be compared are directories"); + + left = ck_fopen (expand_name (argv[optind], leftdir, argv[optind + 1]), "r"); + ; + right = ck_fopen (expand_name (argv[optind + 1], rightdir, argv[optind]), "r"); + out = ck_fopen (out_file, "w"); + + if (pipe (diff_fds)) + perror_fatal ("pipe"); + + trapsigs (); + + diffpid = pid = vfork (); + + if (pid == 0) + { + signal (SIGINT, SIG_IGN); /* in case user interrupts editor */ + signal (SIGPIPE, SIG_DFL); + + close (diff_fds[0]); + if (diff_fds[1] != fileno (stdout)) + { + dup2 (diff_fds[1], fileno (stdout)); + close (diff_fds[1]); + } + + execdiff (0, "--sdiff-merge-assist", argv[optind], argv[optind + 1]); + } + + if (pid < 0) + perror_fatal ("fork failed"); + + close (diff_fds[1]); + diffout = ck_fdopen (diff_fds[0], "r"); + + lf_init (&diff_filt, diffout); + lf_init (&lfilt, left); + lf_init (&rfilt, right); + + interact_ok = interact (&diff_filt, &lfilt, &rfilt, out); + + ck_fclose (diffout); + ck_fclose (left); + ck_fclose (right); + ck_fclose (out); + + { + int wstatus; + + if (waitpid (pid, &wstatus, 0) < 0) + perror_fatal ("wait failed"); + diffpid = 0; + + if (tmpmade) + { + unlink (tmpname); + tmpmade = 0; + } + + if (! interact_ok) + exit (2); + + if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2)) + fatal ("Subsidiary diff failed"); + + exit (WEXITSTATUS (wstatus)); + } + } + return 0; /* Fool -Wall . . . */ +} + +static char **diffargv; + +static void +diffarg (a) + char *a; +{ + static unsigned diffargs, diffargsmax; + + if (diffargs == diffargsmax) + { + if (! diffargsmax) + { + diffargv = (char **) xmalloc (sizeof (char)); + diffargsmax = 8; + } + diffargsmax *= 2; + diffargv = (char **) realloc (diffargv, diffargsmax * sizeof (char *)); + if (! diffargv) + fatal ("out of memory"); + } + diffargv[diffargs++] = a; +} + +static void +execdiff (differences_only, option, file1, file2) + int differences_only; + char *option, *file1, *file2; +{ + if (differences_only) + diffarg ("--suppress-common-lines"); + diffarg (option); + diffarg ("--"); + diffarg (file1); + diffarg (file2); + diffarg (0); + + execvp (diffbin, diffargv); + write (fileno (stderr), diffbin, strlen (diffbin)); + write (fileno (stderr), ": not found\n", 12); + _exit (2); +} + + + + +/* Signal handling */ + +static int volatile ignore_signals; + +static void +catchsig (s) + int s; +{ + signal (s, catchsig); + if (! ignore_signals) + { + cleanup (); + _exit (2); + } +} + +static void +trapsigs () +{ + static int const sigs[] = { +# ifdef SIGHUP + SIGHUP, +# endif +# ifdef SIGQUIT + SIGQUIT, +# endif +# ifdef SIGTERM + SIGTERM, +# endif +# ifdef SIGXCPU + SIGXCPU, +# endif +# ifdef SIGXFSZ + SIGXFSZ, +# endif + SIGINT, + SIGPIPE + }; + int const *p; + + for (p = sigs; p < sigs + sizeof (sigs) / sizeof (*sigs); p++) + if (signal (*p, SIG_IGN) != SIG_IGN && signal (*p, catchsig) != SIG_IGN) + fatal ("signal error"); +} + + + +static void +give_help () +{ + fprintf (stderr,"l:\tuse the left version\n"); + fprintf (stderr,"r:\tuse the right version\n"); + fprintf (stderr,"e l:\tedit then use the left version\n"); + fprintf (stderr,"e r:\tedit then use the right version\n"); + fprintf (stderr,"e b:\tedit then use the left and right versions concatenated\n"); + fprintf (stderr,"e:\tedit a new version\n"); + fprintf (stderr,"s:\tsilently include common lines\n"); + fprintf (stderr,"v:\tverbosely include common lines\n"); + fprintf (stderr,"q:\tquit\n"); +} + +static int +skip_white () +{ + int c; + while (isspace (c = getchar ()) && c != '\n') + ; + if (ferror (stdin)) + perror_fatal ("input error"); + return c; +} + +static void +flush_line () +{ + int c; + while ((c = getchar ()) != '\n' && c != EOF) + ; + if (ferror (stdin)) + perror_fatal ("input error"); +} + + +/* interpret an edit command */ +static int +edit (left, lenl, right, lenr, outfile) + struct line_filter *left; + int lenl; + struct line_filter *right; + int lenr; + FILE *outfile; +{ + for (;;) + { + int cmd0, cmd1; + int gotcmd = 0; + + while (!gotcmd) + { + if (putchar ('%') != '%') + perror_fatal ("output error"); + ck_fflush (stdout); + + cmd0 = skip_white (); + switch (cmd0) + { + case 'l': case 'r': case 's': case 'v': case 'q': + if (skip_white () != '\n') + { + give_help (); + flush_line (); + continue; + } + gotcmd = 1; + break; + + case 'e': + cmd1 = skip_white (); + switch (cmd1) + { + case 'l': case 'r': case 'b': + if (skip_white () != '\n') + { + give_help (); + flush_line (); + continue; + } + gotcmd = 1; + break; + case '\n': + gotcmd = 1; + break; + default: + give_help (); + flush_line (); + continue; + } + break; + case EOF: + if (feof (stdin)) + { + gotcmd = 1; + cmd0 = 'q'; + break; + } + /* falls through */ + default: + give_help (); + flush_line (); + continue; + } + } + + switch (cmd0) + { + case 'l': + lf_copy (left, lenl, outfile); + lf_skip (right, lenr); + return 1; + case 'r': + lf_copy (right, lenr, outfile); + lf_skip (left, lenl); + return 1; + case 's': + suppress_common_flag = 1; + break; + case 'v': + suppress_common_flag = 0; + break; + case 'q': + return 0; + case 'e': + if (! tmpname && ! (tmpname = private_tempnam (0, "sdiff", 1, 0))) + perror_fatal ("temporary file name"); + + tmpmade = 1; + + { + FILE *tmp = ck_fopen (tmpname, "w+"); + + if (cmd1 == 'l' || cmd1 == 'b') + lf_copy (left, lenl, tmp); + else + lf_skip (left, lenl); + + if (cmd1 == 'r' || cmd1 == 'b') + lf_copy (right, lenr, tmp); + else + lf_skip (right, lenr); + + ck_fflush (tmp); + + { + pid_t pid; + int wstatus; + + ignore_signals = 1; + + pid = vfork (); + if (pid == 0) + { + char const *argv[3]; + int i = 0; + + argv[i++] = edbin; + argv[i++] = tmpname; + argv[i++] = 0; + + execvp (edbin, (char **) argv); + write (fileno (stderr), edbin, strlen (edbin)); + write (fileno (stderr), ": not found\n", 12); + _exit (1); + } + + if (pid < 0) + perror_fatal ("fork failed"); + + while (waitpid (pid, &wstatus, 0) < 0) + if (errno != EINTR) + perror_fatal ("wait failed"); + + ignore_signals = 0; + + if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 1)) + fatal ("Subsidiary editor failed"); + } + + if (fseek (tmp, 0L, SEEK_SET) != 0) + perror_fatal ("fseek"); + { + /* SDIFF_BUFSIZE is too big for a local var + in some compilers, so we allocate it dynamically. */ + char *buf = (char *) xmalloc (SDIFF_BUFSIZE); + size_t size; + + while ((size = ck_fread (buf, SDIFF_BUFSIZE, tmp)) != 0) + ck_fwrite (buf, size, outfile); + ck_fclose (tmp); + + free (buf); + } + return 1; + } + default: + give_help (); + break; + } + } +} + + + +/* Alternately reveal bursts of diff output and handle user editing comands. */ +static int +interact (diff, left, right, outfile) + struct line_filter *diff; + struct line_filter *left; + struct line_filter *right; + FILE *outfile; +{ + for (;;) + { + char diff_help[256]; + int snarfed = lf_snarf (diff, diff_help, sizeof (diff_help)); + + if (snarfed <= 0) + return snarfed; + + switch (diff_help[0]) + { + case ' ': + puts (diff_help + 1); + break; + case 'i': + { + int lenl = atoi (diff_help + 1), lenr, lenmax; + char *p = index (diff_help, ','); + + if (!p) + fatal (diff_help); + lenr = atoi (p + 1); + lenmax = max (lenl, lenr); + + if (suppress_common_flag) + lf_skip (diff, lenmax); + else + lf_copy (diff, lenmax, stdout); + + lf_copy (left, lenl, outfile); + lf_skip (right, lenr); + break; + } + case 'c': + { + int lenl = atoi (diff_help + 1), lenr; + char *p = index (diff_help, ','); + + if (!p) + fatal (diff_help); + lenr = atoi (p + 1); + lf_copy (diff, max (lenl, lenr), stdout); + if (! edit (left, lenl, right, lenr, outfile)) + return 0; + break; + } + default: + fatal (diff_help); + break; + } + } +} + + + +/* temporary lossage: this is torn from gnu libc */ +/* Return nonzero if DIR is an existent directory. */ +static int +diraccess (dir) + const char *dir; +{ + struct stat buf; + return stat (dir, &buf) == 0 && S_ISDIR (buf.st_mode); +} + +/* Return nonzero if FILE exists. */ +static int +exists (file) + const char *file; +{ + struct stat buf; + return stat (file, &buf) == 0; +} + +/* These are the characters used in temporary filenames. */ +static const char letters[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +/* Generate a temporary filename. + If DIR_SEARCH is nonzero, DIR and PFX are used as + described for tempnam. If not, a temporary filename + in P_tmpdir with no special prefix is generated. If LENPTR + is not NULL, *LENPTR is set the to length (including the + terminating '\0') of the resultant filename, which is returned. + This goes through a cyclic pattern of all possible filenames + consisting of five decimal digits of the current pid and three + of the characters in `letters'. Data for tempnam and tmpnam + is kept separate, but when tempnam is using P_tmpdir and no + prefix (i.e, it is identical to tmpnam), the same data is used. + Each potential filename is tested for an already-existing file of + the same name, and no name of an existing file will be returned. + When the cycle reaches its end (12345ZZZ), NULL is returned. */ + + +static char * +private_tempnam (dir, pfx, dir_search, lenptr) + const char *dir; + const char *pfx; + int dir_search; + size_t *lenptr; +{ + static const char tmpdir[] = PVT_tmpdir; + static struct + { + char buf[3]; + char *s; + size_t i; + } infos[2], *info; + static char buf[TMPNAMSIZE]; + static pid_t oldpid = 0; + pid_t pid = getpid (); + register size_t len, plen; + + if (dir_search) + { + register const char *d = getenv ("TMPDIR"); + if (d != NULL && !diraccess (d)) + d = NULL; + if (d == NULL && dir != NULL && diraccess (dir)) + d = dir; + if (d == NULL && diraccess (tmpdir)) + d = tmpdir; + if (d == NULL && diraccess ("/tmp")) + d = "/tmp"; + if (d == NULL) + { + errno = ENOENT; + return NULL; + } + dir = d; + } + else + dir = tmpdir; + + if (pfx != NULL && *pfx != '\0') + { + plen = strlen (pfx); + if (plen > 5) + plen = 5; + } + else + plen = 0; + + if (dir != tmpdir && !strcmp (dir, tmpdir)) + dir = tmpdir; + info = &infos[(plen == 0 && dir == tmpdir) ? 1 : 0]; + + if (pid != oldpid) + { + oldpid = pid; + info->buf[0] = info->buf[1] = info->buf[2] = '0'; + info->s = &info->buf[0]; + info->i = 0; + } + + len = strlen (dir) + 1 + plen + 8; + for (;;) + { + *info->s = letters[info->i]; + sprintf (buf, "%s/%.*s%.5d%.3s", dir, (int) plen, pfx, + pid % 100000, info->buf); + if (!exists (buf)) + break; + ++info->i; + if (info->i > sizeof (letters) - 1) + { + info->i = 0; + if (info->s == &info->buf[2]) + { + errno = EEXIST; + return NULL; + } + ++info->s; + } + } + + if (lenptr != NULL) + *lenptr = len; + return buf; +} |