pax_global_header00006660000000000000000000000064137070704630014521gustar00rootroot0000000000000052 comment=de825ff91d336bcdcf9ac5bc367248f467abe67d digup-digup-0.6.57/000077500000000000000000000000001370707046300140365ustar00rootroot00000000000000digup-digup-0.6.57/.gitignore000066400000000000000000000002021370707046300160200ustar00rootroot00000000000000# generated with autotools by autogen.sh /Makefile.in /aclocal.m4 /acscripts /autom4te.cache /configure /src/Makefile.in /INSTALL digup-digup-0.6.57/.travis.yml000066400000000000000000000002011370707046300161400ustar00rootroot00000000000000--- language: cpp script: - ./autogen.sh - mkdir build; cd build - ../configure --enable-optimize - make - make check digup-digup-0.6.57/AUTHORS000066400000000000000000000000621370707046300151040ustar00rootroot00000000000000Timo Bingmann digup-digup-0.6.57/COPYING000066400000000000000000001045131370707046300150750ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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 Lesser General Public License instead of this License. But first, please read . digup-digup-0.6.57/ChangeLog000066400000000000000000000031741370707046300156150ustar00rootroot000000000000002011-01-30 19:05 Timo Bingmann * src/digup.c: Adding shortcut option -w, --windows for --modify-window=1 as needed to check files on FAT filesystems. * src/digup.c: New feature: --restrict=substring to temporarily ignore all files not matching the substring. Required a new fileinfo state FS_SKIPPED and appropriate commands. 2011-01-13 17:11 Timo Bingmann * src/digup.c: Fixing problems with 64-bit file sizes on win32 under (mingw32): using _stat64 on mingw now. * src/digup.c: Simple variable rename node -> digestiter for clarity. 2011-01-13 17:04 Timo Bingmann * src/digup.c: Adding check in digest_file to verify that the complete file was read. 2011-01-13 17:01 Timo Bingmann * src/digup.c: Using intptr_t in rbtree tests to fix warnings about pointer conversion on 64-bit systems. 2010-11-29 18:05 Timo Bingmann * src/digup.c: Adding new flags --modify-window inspired by rsync: allow modification time deltas larger than zero e.g. for backuping on FAT filesystems. * src/digup.c: Adding new option --exclude-marker=file. If file is found in a directory during the recursive scan, the directory itself and all subdirectories are skipped. 2010-10-03 11:28 Timo Bingmann * src/digup.c: Applying contributed patch which fixes segfault on amd64 due to va_start(), va_end() use pattern. 2010-08-20 10:49 Timo Bingmann * src/digup.c: Fixed string allocation bug causing a segfault when using -t followed by -f parameters. 2010-03-20 14:27 Timo Bingmann * src/digup.c: Changing size variable from ssize_t to long long to enable support for large files. 2009-11-10 14:57 Timo Bingmann * Initial release of 0.6.23 digup-digup-0.6.57/Makefile.am000066400000000000000000000010731370707046300160730ustar00rootroot00000000000000# automake file for digup SUBDIRS = src if GCOV clean-local: find -name "*.da" -o -name "*.gcov" -o -name "*.gcda" -o -name "*.gcno" | xargs rm || true run-gcov: clean-gcov mkdir -p coverage/ lcov --directory . --zerocounters -$(MAKE) check lcov --directory . --capture --output-file coverage/all.info lcov -e coverage/all.info "/tdata/*" -o coverage/testsuite.info genhtml -o coverage --num-spaces 8 coverage/testsuite.info --title "digup Testsuite" --prefix `pwd` --legend clean-gcov: find -name "*.gcda" | xargs rm || true endif EXTRA_DIST = digup.spec digup-digup-0.6.57/NEWS000066400000000000000000000000251370707046300145320ustar00rootroot00000000000000No news is good news.digup-digup-0.6.57/README000066400000000000000000000035271370707046300147250ustar00rootroot00000000000000 --- digup - A Digest Updating Tool --- Description digup is a tool to update md5sum or shasum digest files. It will read existing digest files, check the current directory for new, updated, modified, renamed or deleted files and query the user with a summary of changes. After reviewing the updates, they can be written back to the digest file. One of the envisioned applications of digup is to update and verify incremental archives like chronological data storages or music collections. By using digup possibly undesired changes or lost files can easily be detected while quickly adding new files. Another purpose could be to automatically verify the integrity of hard disk copies of archives, as backups to hard disks are becoming increasingly popular. Using a full file digest scan even slowly creeping bad blocks on old hard disks can be detected. By using a crontab entry, this check can be performed unattended and routinely. In normal operation only touched files with newer modification times are fully read and their digest compared. Optionally a full scan can be performed to test all file contents against their expected digests. Symbolic links are supported by either following the link and reading the target's digest or by saving only the link target path and verifying it against the old one. The digest files written by digup are compatible with those generated and read by md5sum and similar programs from the coreutils package. Additional information like file size and modification time or symlink targets are stored on comment lines. Four digest algorithms are supported: MD5, SHA1, SHA256 and SHA512. The digest file itself is also checksummed using CRC32 against unintentional changes. A fast red-black binary tree is used for the internal file list, allowing fast operation on a large number of files. Website https://panthema.net/2009/digup/ digup-digup-0.6.57/autogen.sh000077500000000000000000000001211370707046300160310ustar00rootroot00000000000000#!/bin/sh mkdir -p acscripts aclocal \ && automake --add-missing \ && autoconf digup-digup-0.6.57/configure.ac000066400000000000000000000057551370707046300163400ustar00rootroot00000000000000# -*- mode: autoconf -*- AC_PREREQ(2.60) AC_INIT(digup, 0.6.57) AC_CONFIG_SRCDIR(src/digup.c) AC_CONFIG_AUX_DIR(acscripts) AM_INIT_AUTOMAKE AM_MAINTAINER_MODE # Check for mingw system and set compilation flag. AC_CANONICAL_HOST AC_MSG_CHECKING(building on win32) case "$host_os" in *cygwin* | *mingw32*) ON_WIN32=1 AC_DEFINE(ON_WIN32, 1, "") AC_DEFINE(__MSVCRT_VERSION__, 0x0601, "") # needed for _stat64 AC_MSG_RESULT(yes) ;; *) ON_WIN32=0 AC_DEFINE(ON_WIN32, 0, "") AC_MSG_RESULT(no) ;; esac # enable full optimization by configure switch AC_ARG_ENABLE(optimize, AS_HELP_STRING([--enable-optimize], [Build with full optimization @<:@default=no@:>@]), [ case "${enableval}" in yes) CFLAGS="$CFLAGS -O3 -DNDEBUG -fomit-frame-pointer"; ;; no) ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-optimize) ;; esac ]) # enable rbtree invariant testing by configure switch AC_ARG_ENABLE(rbtree-verify, AS_HELP_STRING([--enable-rbtree-verify], [Build digup with full red-black tree testing @<:@default=no@:>@]), [ case "${enableval}" in yes) CFLAGS="$CFLAGS -DRBTREE_VERIFY"; ;; no) ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-rbtree-verify) ;; esac ]) # possibly disable building of test programs by configure switch AC_ARG_ENABLE(tests, AS_HELP_STRING([--disable-tests], [Disable building of test program suite @<:@default=no@:>@]), [ case "${enableval}" in yes) buildtests=true ;; no) buildtests=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --disable-tests]) ;; esac ], [ buildtests=true ]) AM_CONDITIONAL(BUILDTESTS, test x"$buildtests" = "xtrue") # check whether to enable gcov coverage flags and macros AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov], [enable test coverage with gcov @<:@default=no@:>@]), [case "${enableval}" in yes) gcov=true ;; no) gcov=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-gcov]) ;; esac], [ gcov=false ]) AM_CONDITIONAL(GCOV, test x"$gcov" = "xtrue") if test x"$gcov" = "xtrue"; then CFLAGS="$CFLAGS -fprofile-arcs -ftest-coverage" fi # set debug info flag if no optimization flags are set. if test "$CFLAGS" == ""; then CFLAGS="-g" fi # enable GNU and large file extensions. AC_DEFINE(_GNU_SOURCE) AC_SYS_LARGEFILE # checks for programs. AC_PROG_CC # check for missing library functions. AC_CHECK_FUNCS([strndup asprintf getline lstat readlink]) # check for include files AC_CHECK_HEADER(endian.h, [AC_DEFINE(HAVE_ENDIAN_H, 1, "")], [AC_DEFINE(HAVE_ENDIAN_H, 0, "")]) AC_CHECK_HEADER(sys/param.h, [AC_DEFINE(HAVE_SYS_PARAM_H, 1, "")], [AC_DEFINE(HAVE_SYS_PARAM_H, 0, "")]) # Output transformed files. AC_CONFIG_FILES([Makefile src/Makefile digup.spec]) AC_OUTPUT digup-digup-0.6.57/digup.spec.in000066400000000000000000000017531370707046300164350ustar00rootroot00000000000000# openSUSE and fedora RPM spec for digup by Timo Bingmann Summary: Tool to read, verify and update MD5 or SHA digest files Name: digup Version: @VERSION@ Release: 1%{?dist} Group: Applications/System License: GPL Packager: Timo Bingmann URL: https://panthema.net/2009/digup/ Source: https://panthema.net/2009/digup/digup-%{version}.tar.bz2 BuildRequires: gcc BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root %description digup is a tool to update md5sum or shasum digest files. It will read existing digest files, check the current directory for new, updated, modified, renamed or deleted files and query the user with a summary of changes. After reviewing the updates, they can be written back to the digest file. %prep %setup -q %build %configure --enable-optimize make %{?_smp_mflags} make %{?_smp_mflags} check %install make install-strip DESTDIR=%{buildroot} %clean /bin/rm -rf %{buildroot} %files %defattr(-,root,root) %{_bindir}/digup %{_mandir}/man1/digup.1.gz digup-digup-0.6.57/src/000077500000000000000000000000001370707046300146255ustar00rootroot00000000000000digup-digup-0.6.57/src/Makefile.am000066400000000000000000000015051370707046300166620ustar00rootroot00000000000000# automake file for digup AM_CFLAGS = -W -Wall -pedantic -Wno-long-long bin_PROGRAMS = digup digup_SOURCES = digup.c \ rbtree.c rbtree.h \ digest.c digest.h \ md5.c md5.h sha1.c sha1.h \ sha256.c sha256.h sha512.c sha512.h \ crc32.c crc32.h dist_man1_MANS = digup.1 if BUILDTESTS noinst_PROGRAMS = test_rbtree test_digest test_digup TESTS = test_rbtree test_digest test_digup test_rbtree_SOURCES = test_rbtree.c \ rbtree.c rbtree.h test_rbtree_CFLAGS = -DRBTREE_VERIFY test_digest_SOURCES = test_digest.c \ digest.c digest.h \ md5.c md5.h sha1.c sha1.h \ sha256.c sha256.h sha512.c sha512.h \ crc32.c crc32.h test_digup_SOURCES = test_digup.c \ rbtree.c rbtree.h \ digest.c digest.h \ md5.c md5.h sha1.c sha1.h \ sha256.c sha256.h sha512.c sha512.h \ crc32.c crc32.h test_digup_CFLAGS = -DRBTREE_VERIFY endif digup-digup-0.6.57/src/crc32.c000066400000000000000000000146701370707046300157150ustar00rootroot00000000000000/***************************************************************************** * Compute the CRC-32 of a data stream. * * * * Copyright (C) 2009 Timo Bingmann * * * * Uses the standard slice-by-byte algorithm with a pre-generated 8-bit * * lookup table described by Dilip V. Sarwate, according to * * https://create.stephan-brumme.com/crc32/ * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ #include "crc32.h" static const uint32_t crc32_table[256] = { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL }; uint32_t crc32(uint32_t crc, const unsigned char* buf, unsigned int len) { if (buf == 0) return 0UL; crc = crc ^ 0xffffffffUL; while (len >= 8) { crc = crc32_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); crc = crc32_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); crc = crc32_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); crc = crc32_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); crc = crc32_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); crc = crc32_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); crc = crc32_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); crc = crc32_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); len -= 8; } while (len) { crc = crc32_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); --len; } return crc ^ 0xffffffffUL; } /*****************************************************************************/ digup-digup-0.6.57/src/crc32.h000066400000000000000000000035411370707046300157150ustar00rootroot00000000000000/***************************************************************************** * Compute the CRC-32 of a data stream. * * * * Copyright (C) 2009 Timo Bingmann * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ #ifndef _CRC32_H #define _CRC32_H 1 #include enum { CRC32_DIGEST_SIZE = 4 }; /** * Calculate the updated CRC32 value after shifting in a buffer of len * size. Start with crc = 0. */ extern uint32_t crc32(uint32_t crc, const unsigned char* buf, unsigned int len); #endif /* _CRC32_H */ /*****************************************************************************/ digup-digup-0.6.57/src/digest.c000066400000000000000000000256761370707046300162700ustar00rootroot00000000000000/***************************************************************************** * Class-like structures to easily switch between message digests. * * * * Copyright (C) 2009 Timo Bingmann * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ #include "digest.h" #include #include #include /*** Helpers ***/ static struct digest_result* malloc_result(unsigned int size) { struct digest_result* resbuf = malloc(1 + size); resbuf->size = size; return resbuf; } /*** MD5 ***/ static size_t __md5_digest_size(void) { return MD5_DIGEST_SIZE; } static void __md5_init(struct digest_ctx *ctx) { md5_init_ctx(&ctx->ctx.md5); } static void __md5_process(struct digest_ctx *ctx, const void *buffer, size_t len) { md5_process_bytes(buffer, len, &ctx->ctx.md5); } static struct digest_result* __md5_finish(struct digest_ctx *ctx) { struct digest_result* resbuf = malloc_result(MD5_DIGEST_SIZE); md5_finish_ctx(&ctx->ctx.md5, (char*)resbuf + 1); return resbuf; } static struct digest_result* __md5_read(struct digest_ctx *ctx) { struct digest_result* resbuf = malloc_result(MD5_DIGEST_SIZE); md5_read_ctx(&ctx->ctx.md5, (char*)resbuf + 1); return resbuf; } static struct digest_result* __md5_process_buffer(const char *buffer, size_t len) { struct digest_result* resbuf = malloc_result(MD5_DIGEST_SIZE); md5_buffer(buffer, len, (char*)resbuf + 1); return resbuf; } void digest_init_md5(struct digest_ctx* ctx) { ctx->digest_size = __md5_digest_size; ctx->init = __md5_init; ctx->process = __md5_process; ctx->finish = __md5_finish; ctx->read = __md5_read; ctx->process_buffer = __md5_process_buffer; ctx->init(ctx); } /*** SHA1 ***/ static size_t __sha1_digest_size(void) { return SHA1_DIGEST_SIZE; } static void __sha1_init(struct digest_ctx *ctx) { sha1_init_ctx(&ctx->ctx.sha1); } static void __sha1_process(struct digest_ctx *ctx, const void *buffer, size_t len) { sha1_process_bytes(buffer, len, &ctx->ctx.sha1); } static struct digest_result* __sha1_finish(struct digest_ctx *ctx) { struct digest_result* resbuf = malloc_result(SHA1_DIGEST_SIZE); sha1_finish_ctx(&ctx->ctx.sha1, (char*)resbuf + 1); return resbuf; } static struct digest_result* __sha1_read(struct digest_ctx *ctx) { struct digest_result* resbuf = malloc_result(SHA1_DIGEST_SIZE); sha1_read_ctx(&ctx->ctx.sha1, (char*)resbuf + 1); return resbuf; } static struct digest_result* __sha1_process_buffer(const char *buffer, size_t len) { struct digest_result* resbuf = malloc_result(SHA1_DIGEST_SIZE); sha1_buffer(buffer, len, (char*)resbuf + 1); return resbuf; } void digest_init_sha1(struct digest_ctx* ctx) { ctx->digest_size = __sha1_digest_size; ctx->init = __sha1_init; ctx->process = __sha1_process; ctx->finish = __sha1_finish; ctx->read = __sha1_read; ctx->process_buffer = __sha1_process_buffer; ctx->init(ctx); } /*** SHA256 ***/ static size_t __sha256_digest_size(void) { return SHA256_DIGEST_SIZE; } static void __sha256_init(struct digest_ctx *ctx) { sha256_init_ctx(&ctx->ctx.sha256); } static void __sha256_process(struct digest_ctx *ctx, const void *buffer, size_t len) { sha256_process_bytes(buffer, len, &ctx->ctx.sha256); } static struct digest_result* __sha256_finish(struct digest_ctx *ctx) { struct digest_result* resbuf = malloc_result(SHA256_DIGEST_SIZE); sha256_finish_ctx(&ctx->ctx.sha256, (char*)resbuf + 1); return resbuf; } static struct digest_result* __sha256_read(struct digest_ctx *ctx) { struct digest_result* resbuf = malloc_result(SHA256_DIGEST_SIZE); sha256_read_ctx(&ctx->ctx.sha256, (char*)resbuf + 1); return resbuf; } static struct digest_result* __sha256_process_buffer(const char *buffer, size_t len) { struct digest_result* resbuf = malloc_result(SHA256_DIGEST_SIZE); sha256_buffer(buffer, len, (char*)resbuf + 1); return resbuf; } void digest_init_sha256(struct digest_ctx* ctx) { ctx->digest_size = __sha256_digest_size; ctx->init = __sha256_init; ctx->process = __sha256_process; ctx->finish = __sha256_finish; ctx->read = __sha256_read; ctx->process_buffer = __sha256_process_buffer; ctx->init(ctx); } /*** SHA512 ***/ static size_t __sha512_digest_size(void) { return SHA512_DIGEST_SIZE; } static void __sha512_init(struct digest_ctx *ctx) { sha512_init_ctx(&ctx->ctx.sha512); } static void __sha512_process(struct digest_ctx *ctx, const void *buffer, size_t len) { sha512_process_bytes(buffer, len, &ctx->ctx.sha512); } static struct digest_result* __sha512_finish(struct digest_ctx *ctx) { struct digest_result* resbuf = malloc_result(SHA512_DIGEST_SIZE); sha512_finish_ctx(&ctx->ctx.sha512, (char*)resbuf + 1); return resbuf; } static struct digest_result* __sha512_read(struct digest_ctx *ctx) { struct digest_result* resbuf = malloc_result(SHA512_DIGEST_SIZE); sha512_read_ctx(&ctx->ctx.sha512, (char*)resbuf + 1); return resbuf; } static struct digest_result* __sha512_process_buffer(const char *buffer, size_t len) { struct digest_result* resbuf = malloc_result(SHA512_DIGEST_SIZE); sha512_buffer(buffer, len, (char*)resbuf + 1); return resbuf; } void digest_init_sha512(struct digest_ctx* ctx) { ctx->digest_size = __sha512_digest_size; ctx->init = __sha512_init; ctx->process = __sha512_process; ctx->finish = __sha512_finish; ctx->read = __sha512_read; ctx->process_buffer = __sha512_process_buffer; ctx->init(ctx); } /*** CRC32 ***/ static size_t __crc32_digest_size(void) { return CRC32_DIGEST_SIZE; } static void __crc32_init(struct digest_ctx *ctx) { ctx->ctx.crc32 = 0; } static void __crc32_process(struct digest_ctx *ctx, const void *buffer, size_t len) { ctx->ctx.crc32 = crc32(ctx->ctx.crc32, buffer, len); } static struct digest_result* __crc32_finish(struct digest_ctx *ctx) { struct digest_result* resbuf = malloc_result(CRC32_DIGEST_SIZE); *(uint32_t*)((char*)resbuf+1) = ctx->ctx.crc32; return resbuf; } static struct digest_result* __crc32_read(struct digest_ctx *ctx) { struct digest_result* resbuf = malloc_result(CRC32_DIGEST_SIZE); *(uint32_t*)((char*)resbuf+1) = ctx->ctx.crc32; return resbuf; } static struct digest_result* __crc32_process_buffer(const char *buffer, size_t len) { struct digest_result* resbuf = malloc_result(CRC32_DIGEST_SIZE); uint32_t crc = crc32(0, (const unsigned char*)buffer, len); *(uint32_t*)((char*)resbuf+1) = crc; return resbuf; } void digest_init_crc32(struct digest_ctx* ctx) { ctx->digest_size = __crc32_digest_size; ctx->init = __crc32_init; ctx->process = __crc32_process; ctx->finish = __crc32_finish; ctx->read = __crc32_read; ctx->process_buffer = __crc32_process_buffer; ctx->init(ctx); } /*** Utilities ***/ struct digest_result* digest_dup(const struct digest_result* res) { struct digest_result* newres = malloc_result(res->size); memcpy((char*)newres+1, (char*)res+1, res->size); return newres; } char* digest_bin2hex(const struct digest_result* res, char* out) { unsigned int i; unsigned char *cbin = (unsigned char*)res+1; static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; for (i = 0; i < res->size; ++i) { out[2*i+0] = hex[ (cbin[i] >> 4) & 0x0F ]; out[2*i+1] = hex[ (cbin[i] >> 0) & 0x0F ]; } out[2*res->size] = 0; return out; } char* digest_bin2hex_dup(const struct digest_result* res) { char* out = malloc(2 * res->size + 1); return digest_bin2hex(res, out); } struct digest_result* digest_hex2bin(const char* str, int len) { static const char hexval[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; struct digest_result* resbuf; int i; if (len < 0) len = strlen(str); if (len % 2 != 0) return NULL; resbuf = malloc_result(len / 2); for (i = 0; i < len; i += 2) { if (hexval[(unsigned char)str[i]] < 0) { free(resbuf); return NULL; } if (hexval[(unsigned char)str[i+1]] < 0) { free(resbuf); return NULL; } ((unsigned char*)resbuf+1)[i/2] = hexval[(unsigned char)str[i]] * 16 + hexval[(unsigned char)str[i+1]]; } return resbuf; } int digest_equal(const struct digest_result* a, const struct digest_result* b) { if (a->size != b->size) return 0; return memcmp((unsigned char*)a+1, (unsigned char*)b+1, a->size) == 0; } int digest_cmp(const struct digest_result* a, const struct digest_result* b) { if (a->size != b->size) return a->size - b->size; return memcmp((unsigned char*)a+1, (unsigned char*)b+1, a->size); } /*****************************************************************************/ digup-digup-0.6.57/src/digest.h000066400000000000000000000067051370707046300162650ustar00rootroot00000000000000/***************************************************************************** * Class-like structures to easily switch between message digests. * * * * Copyright (C) 2009 Timo Bingmann * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ #ifndef _DIGEST_H #define _DIGEST_H 1 #include #include #include "md5.h" #include "sha1.h" #include "sha256.h" #include "sha512.h" #include "crc32.h" /** * variable sized structure to hold binary digest results of different * algorithms. */ typedef struct digest_result { unsigned char size; /* variable length of bytes follows: unsigned char data[]; */ } digest_result; /** * class-like structure with function pointers and integrated digest * algorithm context. */ typedef struct digest_ctx { union { struct md5_ctx md5; struct sha1_ctx sha1; struct sha256_ctx sha256; struct sha512_ctx sha512; uint32_t crc32; } ctx; size_t (*digest_size)(void); void (*init)(struct digest_ctx *ctx); void (*process)(struct digest_ctx *ctx, const void *buffer, size_t len); struct digest_result* (*finish)(struct digest_ctx *ctx); struct digest_result* (*read)(struct digest_ctx *ctx); struct digest_result* (*process_buffer)(const char *buffer, size_t len); } digest_ctx; /* initialize the structure with function pointers for specific digest * type */ extern void digest_init_md5(struct digest_ctx* ctx); extern void digest_init_sha1(struct digest_ctx* ctx); extern void digest_init_sha256(struct digest_ctx* ctx); extern void digest_init_sha512(struct digest_ctx* ctx); extern void digest_init_crc32(struct digest_ctx* ctx); /* miscellaneous utilities */ extern struct digest_result* digest_dup(const struct digest_result* res); extern char* digest_bin2hex(const struct digest_result*, char* out); extern char* digest_bin2hex_dup(const struct digest_result* res); extern struct digest_result* digest_hex2bin(const char* str, int len); extern int digest_equal(const struct digest_result* a, const struct digest_result* b); extern int digest_cmp(const struct digest_result* a, const struct digest_result* b); #endif /* _DIGEST_H */ /*****************************************************************************/ digup-digup-0.6.57/src/digup.1000066400000000000000000000133341370707046300160230ustar00rootroot00000000000000.TH DIGUP 1 2009-11-10 .SH "NAME" .LP digup \- \fBDig\fPest file \fBup\fPdating program. .SH "SYNOPSIS" .LP digup [\fIOPTIONS\fP] .SH "DESCRIPTION" .LP digup is a tool to update md5sum or shasum digest files. It will read existing digest files, check the current directory for new, updated, modified, renamed or deleted files and query the user with a summary of changes. After reviewing the updates, they can be written back to the digest file. One of the envisioned applications of digup is to update and verify incremental archives like chronological data storages or music collections. By using digup possibly undesired changes or lost files can easily be detected while quickly adding new files. Another purpose could be to automatically verify the integrity of hard disk copies of archives, as backups to hard disks are becoming increasingly popular. Using a full file digest scan even slowly creeping bad blocks on old hard disks can be detected. By using a crontab entry, this check can be performed unattended and routinely. In normal operation only touched files with newer modification times are fully read and their digest compared. Optionally a full scan can be performed to test all file contents against their expected digests. Symbolic links are supported by either following the link and reading the target's digest or by saving only the link target path and verifying it against the old one. The digest files written by digup are compatible with those generated and read by md5sum and similar programs from the coreutils package. Additional information like file size and modification time or symlink targets are stored on comment lines. Four digest algorithms are supported: MD5, SHA1, SHA256 and SHA512. The digest file itself is also checksummed using CRC32 against unintentional changes. A fast red-black binary tree is used for the internal file list, allowing fast operation on a large number of files. .SH "OPTIONS" .TP \fB\-b\fR, \fB\-\-batch\fR Enable non-interactive batch processing mode as needed when run unattended e.g. from cron. This option also decreases verbosity by one level (--quiet). The returned error code is set to 1 if any changed, renamed, moved, deleted files or read errors occur. .TP \fB\-c\fR, \fB\-\-check\fR Perform a full digest scan of all file contents, thus ignoring file modification times. Without this option files with equal size and modification time are skipped. .TP \fB\-d\fR, \fB\-\-directory\fR=\fI\fR Change into this directory before looking for digest files or performing a recursive scan. .TP \fB\-\-exclude\-marker\fR=\fI\fR Sets a marker file, often called ".nobackup" in other programs. If this marker file is found in a directory, the directory itself and all sub-directories are excluded from the digest scan. This option is persistent. It is saved in the digest file and will be applied to all future scans performed to check or update digests. .TP \fB\-f\fR, \fB\-\-file\fR=\fI\fR Check this file for existing digests and write updates to it. Depending on the selected digest --type the following file names are used by default: "md5sum.txt", "sha1sum.txt", "sha256sum.txt" or "sha512sum.txt". .TP \fB\-l\fR, \fB\-\-links\fR When this flag is enabled, symbolic links (if supported on the platform) are followed. Otherwise, by default, only the symbolic link's target path is saved and verified. .TP \fB\-m\fR, \fB\-\-modified\fR Print only modified, changed, copied, renamed or deleted files. Unchanged files lines are suppressed. If the whole digest file is clean, then no summary output is printed at all. This option is useful for crontabs in combination with --batch. .TP \fB\-\-modify\-window\fR=\fI\fI Consider modification time deltas of up to this value to be unchanged (the default is zero). This option is very useful for checking backups on FAT filesystems, as FAT stores modification times with a precision of only 2 seconds. .TP \fB\-q\fR, \fB\-\-quiet\fR Reduces the level of verbosity by one. .TP \fB\-r\fR, \fB\-\-restrict\fR=\fI\fR Restricts the digest check to filepaths containing the given substring pattern, other files are skipped. Does NOT imply -c / --check; specify it additionally to run a full digest check of specific files. .TP \fB\-t\fR, \fB\-\-type\fR=\fI\fR Select the digest type for newly created digest files. This is not needed for updating existing one, as the type can inferred from the digest length. digest-type must be md5, sha1, sha256 or sha512. The default digest type is sha1. .TP \fB\-u\fR, \fB\-\-update\fR Automatically update the digest file in batch mode. Requires --batch, which is not automatically activated by this option. .TP \fB\-v\fR, \fB\-\-verbose\fR Increase the level of verbosity by one. At level 0 only read errors are printed. At level 1 the status of each processed file is printed. And at level 2 (the default) additionally a progress indicator is printed while reading each file (one dot per megabyte). .TP \fB\-V\fR, \fB\-\-version\fR Print digup version and exit. .TP \fB\-w\fR, \fB\-\-windows\fR Ignores modification time deltas of just 1 second (equivalent to --modify-window=1). Useful for checking backups on FAT filesystems. .SH "EXAMPLES" .TP To update or create a SHA1 digest file in current directory just run plain digup .TP Alternatively update or create a SHA512 digest file in /mnt/disk1 digup -t sha512 -d /mnt/disk1/archive .TP A common call for a crontab line is digup -bmd /mnt/disk1/archive .TP To run a full scan every midnight add a line similar to the following to your crontab 0 * * * * digup -bcmd /mnt/disk1/archive .SH "AUTHORS" .LP Timo Bingmann (tb (at) panthema net) .SH "SEE ALSO" .LP md5sum(1), sha1sum(1), sha256sum(1), sha512sum(1) \" LocalWords: storages coreutils digup symlink filesystems crontab digup-digup-0.6.57/src/digup.c000066400000000000000000001742401370707046300161110ustar00rootroot00000000000000/***************************************************************************** * digup.c - Digest File Updating Program * * * * Copyright (C) 2010-2020 Timo Bingmann * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "digest.h" #include "rbtree.h" /************************** * Basic Type Definitions * **************************/ typedef enum { FALSE, TRUE } bool; enum DigestType { DT_NONE, DT_MD5, DT_SHA1, DT_SHA256, DT_SHA512 }; enum FileStatus { FS_UNSEEN, /* in digest file but not seen on fs yet. */ FS_SEEN, /* in digest file and seen on fs with equal mtime. */ FS_NEW, /* newly seen file on fs. */ FS_TOUCHED, /* identical in digest file and fs but with different mtime. */ FS_CHANGED, /* in digest file but modified on fs. */ FS_ERROR, /* error while reading file. */ FS_COPIED, /* copied within tree. */ FS_RENAMED, /* renamed within tree. */ FS_OLDPATH, /* original entry of a renamed file */ FS_SKIPPED /* skipped due to --restrict */ }; struct FileInfo { enum FileStatus status; time_t mtime; long long size; char* error; digest_result* digest; char* symlink; /* target actually */ char* oldpath; /* for renamed or copied files. */ }; /******************************** * Global Variables and Options * ********************************/ const char* g_progname = NULL; /* various parameters set by the command line parameters */ int gopt_verbose = 2; bool gopt_batch = FALSE; bool gopt_fullcheck = FALSE; bool gopt_followsymlinks = FALSE; bool gopt_onlymodified = FALSE; bool gopt_update = FALSE; char* gopt_digestfile = NULL; enum DigestType gopt_digesttype = DT_NONE; unsigned int gopt_modify_window = 0; const char* gopt_exclude_marker = NULL; const char* gopt_matchpattern = NULL; /* red-black tree mapping filename string -> struct FileInfo */ struct rb_tree* g_filelist = NULL; /* red-black tree mapping digest_result -> filename string */ struct rb_tree* g_filedigestmap = NULL; /* file status counters */ unsigned int g_filelist_seen = 0; unsigned int g_filelist_new = 0; unsigned int g_filelist_touched = 0; unsigned int g_filelist_changed = 0; unsigned int g_filelist_error = 0; unsigned int g_filelist_copied = 0; unsigned int g_filelist_renamed = 0; unsigned int g_filelist_oldpath = 0; unsigned int g_filelist_skipped = 0; /********************************** * Helper Functions and Utilities * **********************************/ /* functional for the g_filelist red-black tree */ void rbtree_string_free(void *a) { free((char*)a); } /* functional for the g_filelist red-black tree */ void rbtree_fileinfo_free(void *a) { struct FileInfo* fileinfo = a; if (fileinfo->error) free(fileinfo->error); if (fileinfo->digest) free(fileinfo->digest); if (fileinfo->symlink) free(fileinfo->symlink); if (fileinfo->oldpath) free(fileinfo->oldpath); free(fileinfo); } /* functional for the g_filelist red-black tree */ void rbtree_digest_result_free(void *a) { free((digest_result*)a); } /* functional for the g_filelist red-black tree */ void rbtree_null_free(void *a) { (void)a; } /* functional for the g_filelist red-black tree */ int rbtree_string_cmp(const void *a, const void *b) { return strcmp((const char*)a, (const char*)b); } /* functional for the g_filelist red-black tree */ int rbtree_digest_result_cmp(const void *a, const void *b) { return digest_cmp((const digest_result*)a, (const digest_result*)b); } /* functional for qsort() on a char* array */ static int strcmpptr(const void *p1, const void *p2) { return strcmp(*(char**)p1, *(char**)p2); } /* simple strndup() replacement if not in standard library. */ #if !HAVE_STRNDUP static char *strndup(const char *str, size_t len) { char* out = malloc(len + 1); strncpy(out, str, len); out[len] = 0; return out; } #endif /* simple asprintf() replacement if not in standard library. */ #if !HAVE_ASPRINTF static int asprintf(char **strp, const char *fmt, ...) { va_list ap; ssize_t len; char *out; va_start(ap, fmt); len = vsnprintf(NULL, 0, fmt, ap) + 1; va_end (ap); out = malloc(len); if (out == NULL) return -1; va_start(ap, fmt); len = vsnprintf(out, len, fmt, ap); va_end (ap); *strp = out; return len; } #endif /* wrapper to abort if out of memory */ static int my_asprintf(char **strp, const char *fmt, ...) { va_list ap; int r; va_start(ap, fmt); r = vasprintf(strp, fmt, ap); va_end(ap); if (r < 0) { fprintf(stderr, "asprintf(): out of memory\n"); exit(EXIT_FAILURE); } return r; } /* select correct struct stat and functions for 64-bit file sizes in mingw */ #if ON_WIN32 typedef struct __stat64 mystatst; #define mystat _stat64 #define mylstat _stat64 #else /* for sane systems */ typedef struct stat mystatst; #define mystat stat #if !HAVE_LSTAT #define mylstat stat #else #define mylstat lstat #endif #endif /* not so simple getline() replacement from xine-ui code. */ #if !HAVE_GETLINE #define GETLINE_BLOCK_SIZE 128 static ssize_t getdelims(char **lineptr, size_t *n, const char *delims, FILE *stream) { void *tmp; const char *d; int c; size_t i; if (!lineptr || !n || !delims || !stream) { errno = EINVAL; return -1; } if (!*lineptr) *n = 0; i = 0; while ((c = fgetc(stream)) != EOF) { if (i + 1 >= *n) { if ((tmp = realloc(*lineptr, *n + GETLINE_BLOCK_SIZE)) == NULL) { errno = ENOMEM; return -1; } *lineptr = tmp; *n += GETLINE_BLOCK_SIZE; } (*lineptr)[i++] = (unsigned char)c; d = delims; while (*d) { if ((unsigned char)c == *d++) break; } if (*d != '\0') break; } if (i != 0) (*lineptr)[i] = '\0'; return (i == 0) ? -1 : (ssize_t)i; } static ssize_t getline(char **lineptr, size_t *n, FILE *stream) { return getdelims(lineptr, n, "\n\r", stream); } #endif /** * Call readlink() as often as needed to return the complete symlink * target in a malloc()ed buffer. */ char* readlink_dup(const char *filename) { #if HAVE_READLINK ssize_t size = 128; char *buffer = NULL, *tmp; int nchars; while (1) { tmp = realloc(buffer, size); if (!tmp) { /* out of memory */ free(buffer); return NULL; } buffer = tmp; nchars = readlink(filename, buffer, size); if (nchars < 0) { free(buffer); return NULL; } if (nchars + 1 < size) { buffer[nchars] = 0; return buffer; } size *= 2; } #else (void)filename; errno = EINVAL; return NULL; #endif } /** * fprintf() variant which also updates a CRC32 value. */ int fprintfcrc(uint32_t *crc, FILE* fp, const char *fmt, ...) { va_list ap; ssize_t len; static char *out = NULL; static ssize_t outlen = 0; char *tmp; va_start(ap, fmt); len = vsnprintf(NULL, 0, fmt, ap) + 1; va_end (ap); if (outlen < len) { while (outlen < len) { outlen = 2 * outlen; if (outlen < 128) outlen = 128; } tmp = realloc(out, outlen); if (tmp == NULL) return -1; out = tmp; } va_start(ap, fmt); len = vsnprintf(out, len, fmt, ap); va_end (ap); *crc = crc32(*crc, (unsigned char*)out, len); len = fwrite(out, len, 1, fp); return len; } /** * Transform each \n to a new line and each \\ back to a slash. no * other escapes characters are allowed. */ bool unescape_filename(char *str) { size_t i, j = 0; for (i = 0; str[i]; ++i, ++j) { if (str[i] == '\\') { if (str[i+1] == 0) { /* illegal filename finishes with single backslash */ return 0; } ++i; switch (str[i]) { case 'n': str[j] = '\n'; break; case '\\': str[j] = '\\'; break; default: /* invalid escape sequence. */ return FALSE; } } else if (i != j) { str[j] = str[i]; } } str[j] = 0; return TRUE; } /** * Reverse transform each \n and \. into the escaped form and signal * to main function whether escaping is needed. The function will * replaced the malloc()ed parameter string in str. */ bool needescape_filename(char** str) { int needescape = 0; char *s, *t, *newstr; s = *str; while(*s != 0) { if (*s == '\\' || *s == '\n') ++needescape; ++s; } if (needescape == 0) return FALSE; newstr = malloc(s - *str + needescape + 1); t = newstr; s = *str; while(*s != 0) { if (*s == '\\') { *t++ = '\\'; *t++ = '\\'; } else if (*s == '\n') { *t++ = '\\'; *t++ = 'n'; } else { *t++ = *s; } ++s; } *t = 0; free(*str); *str = newstr; return (needescape != 0); } #if ON_WIN32 /** * Replace all backslashes with forward slashes. Used only on Windows. */ void replace_backslahes_with_slashes(char* s) { while(*s != 0) { if (*s == '\\') *s = '/'; ++s; } } #endif /*************************************** * Functions to calculate file digests * ***************************************/ /** * Called from digest_file() with a struct digest_ctx. If there is an * error while calculating the digest, the function returns FALSE and * outerror is filled with an error message string. */ bool digest_file2(const char* filepath, long long filesize, digest_ctx* digctx, digest_result** outdigest, char** outerror) { char buffer[1024*1024]; ssize_t rb; long long totalread = 0; #if ON_WIN32 int openflags = O_RDONLY | O_BINARY; #else int openflags = O_RDONLY; #endif #ifdef O_NOATIME int fd = open(filepath, openflags | O_NOATIME); if (fd < 0 && errno == EPERM) { /* try without O_NOATIME for files not owned by the user */ fd = open(filepath, openflags); } #else int fd = open(filepath, openflags); #endif if (fd < 0) { if (gopt_verbose >= 2) { fprintf(stdout, "ERROR. Could not open file: %s.\n", strerror(errno)); } else if (gopt_verbose >= 1) { fprintf(stdout, "%s ERROR. Could not open file: %s.\n", filepath, strerror(errno)); } else if (gopt_verbose >= 0) { fprintf(stderr, "%s: could not open file \"%s\": %s.\n", g_progname, filepath, strerror(errno)); } my_asprintf(outerror, "Could not open file: %s.", strerror(errno)); return FALSE; } while( (rb = read(fd, &buffer, sizeof(buffer))) > 0 ) { if (gopt_verbose >= 2) { fprintf(stdout, "."); fflush(stdout); } digctx->process(digctx, buffer, rb); totalread += rb; } if (rb != 0) { if (gopt_verbose >= 2) { fprintf(stdout, "ERROR. Could not read file: %s.\n", strerror(errno)); } else if (gopt_verbose >= 1) { fprintf(stdout, "%s ERROR. Could not read file: %s.\n", filepath, strerror(errno)); } else if (gopt_verbose >= 0) { fprintf(stderr, "%s: could not read file \"%s\": %s.\n", g_progname, filepath, strerror(errno)); } my_asprintf(outerror, "Could not read file: %s.", strerror(errno)); close(fd); return FALSE; } close(fd); if (totalread != filesize) { if (gopt_verbose >= 2) { fprintf(stdout, "ERROR. Could not read complete file.\n"); } else if (gopt_verbose >= 1) { fprintf(stdout, "%s ERROR. Could not read complete file.\n", filepath); } else if (gopt_verbose >= 0) { fprintf(stderr, "%s: Could not read complete file \"%s\".\n", g_progname, filepath); } my_asprintf(outerror, "Could not read complete file."); return FALSE; } assert(!*outdigest); *outdigest = digctx->finish(digctx); return TRUE; } /** * Read a filepath and calucate the digest over all data. Returns it * as a malloc()ed hex string in outdigest, or returns FALSE if there * was a read error. */ bool digest_file(const char* filepath, long long filesize, digest_result** outdigest, char** outerror) { digest_ctx digctx; switch (gopt_digesttype) { case DT_MD5: digest_init_md5(&digctx); break; case DT_SHA1: digest_init_sha1(&digctx); break; case DT_SHA256: digest_init_sha256(&digctx); break; case DT_SHA512: digest_init_sha512(&digctx); break; default: assert(0); my_asprintf(outerror, "Invalid digest algorithm."); return FALSE; } return digest_file2(filepath, filesize, &digctx, outdigest, outerror); } /************************************ * Functions to parse a digest file * ************************************/ /** * Parse one digest line and fill in tempinfo according or add a new * file to g_filelist. The return value is -1 for an unknown line, 0 * for a correct digest or symlink line, +1 for a comment line * providing additional file info and -2 for and eof flagged line. */ int parse_digestline(const char* line, const unsigned int linenum, struct FileInfo* tempinfo, uint32_t crc) { /*** parse line from digest file ***/ size_t p = 0; /* skip initial whitespace */ while (isspace(line[p])) ++p; if (line[p] == '#') { /* if first character is a hash then the line might be a comment or our custom mtime indicator. */ size_t p_word, p_arg; ++p; if (line[p] != ':') { /* usual comment */ return 0; } ++p; while (line[p]) { while (isspace(line[p])) ++p; p_word = p; while (isalpha(line[p]) || line[p] == '\\') ++p; if (!isspace(line[p]) && line[p] != 0) { fprintf(stderr, "%s: \"%s\" line %d: unparseable digest comment line.\n", g_progname, gopt_digestfile, linenum); return -1; } if (strncmp(line+p_word, "option", p - p_word) == 0) { /* read persistent option following */ while (isspace(line[p])) ++p; p_arg = p; while (line[p] != 0 && line[p] != '=') ++p; if (strncmp(line+p_arg, "--exclude-marker", p - p_arg) == 0 && line[p] == '=') { ++p; /* skip over '=' */ p_arg = p; while (line[p] != 0) ++p; if (gopt_exclude_marker) free((void*)gopt_exclude_marker); gopt_exclude_marker = strndup(line+p_arg, p - p_arg); if (gopt_verbose >= 2) { fprintf(stderr, "%s: \"%s\" line %d: persistent option --exclude-marker=%s\n", g_progname, gopt_digestfile, linenum, gopt_exclude_marker); } } else { fprintf(stderr, "%s: \"%s\" line %d: unknown persistent option line.\n", g_progname, gopt_digestfile, linenum); return -1; } } else if (strncmp(line+p_word, "mtime", p - p_word) == 0) { /* read number following mtime */ while (isspace(line[p])) ++p; p_arg = p; while (isdigit(line[p])) ++p; if (!isspace(line[p]) && line[p] != 0) { fprintf(stderr, "%s: \"%s\" line %d: unparseable digest comment line.\n", g_progname, gopt_digestfile, linenum); return -1; } tempinfo->mtime = strtoul(line + p_arg, NULL, 10); } else if (strncmp(line+p_word, "size", p - p_word) == 0) { /* read number following size */ while (isspace(line[p])) ++p; p_arg = p; while (isdigit(line[p])) ++p; if (!isspace(line[p]) && line[p] != 0) { fprintf(stderr, "%s: \"%s\" line %d: unparseable digest comment line.\n", g_progname, gopt_digestfile, linenum); return -1; } tempinfo->size = strtoull(line + p_arg, NULL, 10); } else if (strncmp(line+p_word, "target", p - p_word) == 0) { /* read the complete following line (after the current * white space) as the symlink target */ if (!isspace(line[p])) { fprintf(stderr, "%s: \"%s\" line %d: unparseable digest comment line.\n", g_progname, gopt_digestfile, linenum); return -1; } ++p; p_arg = p; while (line[p] != 0) ++p; tempinfo->symlink = strndup(line+p_arg, p - p_arg); } else if (strncmp(line+p_word, "target\\", p - p_word) == 0) { /* read the complete following line (after the current * white space) as the escaped symlink target */ if (!isspace(line[p])) { fprintf(stderr, "%s: \"%s\" line %d: unparseable digest comment line.\n", g_progname, gopt_digestfile, linenum); return -1; } ++p; p_arg = p; while (line[p] != 0) ++p; tempinfo->symlink = strndup(line+p_arg, p - p_arg); if (!unescape_filename(tempinfo->symlink)) { fprintf(stderr, "%s: \"%s\" line %d: improperly escaped symlink target.\n", g_progname, gopt_digestfile, linenum); free(tempinfo->symlink); return -1; } } else if (strncmp(line+p_word, "symlink", p - p_word) == 0) { /* read the complete following line (after the current * white space) as the symlink source file name. */ char* filename; struct FileInfo* fileinfo; if (!isspace(line[p])) { fprintf(stderr, "%s: \"%s\" line %d: unparseable digest comment line.\n", g_progname, gopt_digestfile, linenum); return -1; } ++p; p_arg = p; while (line[p] != 0) ++p; filename = strndup(line+p_arg, p - p_arg); fileinfo = malloc(sizeof(struct FileInfo)); memcpy(fileinfo, tempinfo, sizeof(struct FileInfo)); if (fileinfo->symlink) /* tempinfo's copy will be freed */ fileinfo->symlink = strdup(fileinfo->symlink); /* insert fileinfo into filelist */ if (rb_find(g_filelist, filename) != NULL) { fprintf(stderr, "%s: \"%s\" line %d: duplicate symlink file name.\n", g_progname, gopt_digestfile, linenum); free(fileinfo->symlink); free(fileinfo); return -1; } rb_insert(g_filelist, filename, fileinfo); /* return +1 here to clear tempinfo. */ return 1; } else if (strncmp(line+p_word, "symlink\\", p - p_word) == 0) { /* read the complete following line (after the current * white space) as the escaped symlink source file name. */ char* filename; struct FileInfo* fileinfo; if (!isspace(line[p])) { fprintf(stderr, "%s: \"%s\" line %d: unparseable digest comment line.\n", g_progname, gopt_digestfile, linenum); return -1; } ++p; p_arg = p; while (line[p] != 0) ++p; filename = strndup(line+p_arg, p - p_arg); if (!unescape_filename(filename)) { fprintf(stderr, "%s: \"%s\" line %d: improperly escaped symlink filename.\n", g_progname, gopt_digestfile, linenum); free(filename); return -1; } fileinfo = malloc(sizeof(struct FileInfo)); memcpy(fileinfo, tempinfo, sizeof(struct FileInfo)); if (fileinfo->symlink) /* tempinfo's copy will be freed */ fileinfo->symlink = strdup(fileinfo->symlink); /* insert fileinfo into filelist */ if (rb_find(g_filelist, filename) != NULL) { fprintf(stderr, "%s: \"%s\" line %d: duplicate symlink file name.\n", g_progname, gopt_digestfile, linenum); free(fileinfo->symlink); free(fileinfo); return -1; } rb_insert(g_filelist, filename, fileinfo); /* return +1 here to clear tempinfo. */ return 1; } else if (strncmp(line+p_word, "crc", p - p_word) == 0) { /* read hex crc32 value following the word */ char *crchex; while (isspace(line[p])) ++p; if (line[p] != '0' || line[++p] != 'x') { fprintf(stderr, "%s: \"%s\" line %d: unparseable crc line.\n", g_progname, gopt_digestfile, linenum); return 0; } ++p; p_arg = p; while (isxdigit(line[p])) ++p; if (p - p_arg != 8) { fprintf(stderr, "%s: \"%s\" line %d: unparseable sdfsdcrc line.\n", g_progname, gopt_digestfile, linenum); return 0; } my_asprintf(&crchex, "%08x", crc); if (strncmp(crchex, line+p_arg, p - p_arg) != 0) { free(crchex); fprintf(stderr, "%s: \"%s\" line %d: crc32 value saved in file does not match!\n", g_progname, gopt_digestfile, linenum); if (gopt_batch) { exit(-1); /* fail badly */ } else { char input[256], *r; fprintf(stderr, "This indicates an unintentional or intentional modification of the digest file.\n"); fprintf(stderr, "Continue despite change (y/n)? "); r = fgets(input, sizeof(input), stdin); if (r == NULL || input[0] != 'y') { exit(-1); } } } else { free(crchex); } } else if (strncmp(line+p_word, "eof", p - p_word) == 0) { return -2; } else { fprintf(stderr, "%s: \"%s\" line %d: unparseable digest comment line.\n", g_progname, gopt_digestfile, linenum); return -1; } } return 0; } else { /* a usual digest line. */ size_t p_hex1; struct FileInfo* fileinfo; enum DigestType this_digesttype = DT_NONE; char* filename = NULL; bool escaped_filename = FALSE; if (line[p] == '\\') { ++p; escaped_filename = TRUE; } p_hex1 = p; while (isxdigit(line[p])) ++p; if (!isspace(line[p])) { /* digest is not followed by a space -> error. */ return -1; } fileinfo = malloc(sizeof(struct FileInfo)); memcpy(fileinfo, tempinfo, sizeof(struct FileInfo)); if (fileinfo->symlink) /* tempinfo's copy will be freed */ fileinfo->symlink = strdup(fileinfo->symlink); if (p_hex1 + 2 * MD5_DIGEST_SIZE == p) { fileinfo->digest = digest_hex2bin( line+p_hex1, p - p_hex1 ); this_digesttype = DT_MD5; } else if (p_hex1 + 2 * SHA1_DIGEST_SIZE == p) { fileinfo->digest = digest_hex2bin( line+p_hex1, p - p_hex1 ); this_digesttype = DT_SHA1; } else if (p_hex1 + 2 * SHA256_DIGEST_SIZE == p) { fileinfo->digest = digest_hex2bin( line+p_hex1, p - p_hex1 ); this_digesttype = DT_SHA256; } else if (p_hex1 + 2 * SHA512_DIGEST_SIZE == p) { fileinfo->digest = digest_hex2bin( line+p_hex1, p - p_hex1 ); this_digesttype = DT_SHA512; } else { fprintf(stderr, "%s: \"%s\" line %d: no proper hex digest detected on line.\n", g_progname, gopt_digestfile, linenum); free(fileinfo); return -1; } if (!fileinfo->digest) { assert(fileinfo->digest); fprintf(stderr, "%s: \"%s\" line %d: no proper hex digest detected on line.\n", g_progname, gopt_digestfile, linenum); free(fileinfo); return -1; } if (gopt_digesttype != DT_NONE && this_digesttype != gopt_digesttype) { fprintf(stderr, "%s: \"%s\" line %d: different digest types in file.\n", g_progname, gopt_digestfile, linenum); free(fileinfo); exit(0); } ++p; /* after digest terminating white space follows a "type indicator": text or binary. We always use binary. */ if (line[p] != ' ' && line[p] != '*') { fprintf(stderr, "%s: \"%s\" line %d: improper type indicator.\n", g_progname, gopt_digestfile, linenum); return -1; } ++p; /* all non-null character after type indicator and \n are relevant. */ filename = strdup(line + p); if (escaped_filename) { if (!unescape_filename(filename)) { fprintf(stderr, "%s: \"%s\" line %d: improperly escaped file name.\n", g_progname, gopt_digestfile, linenum); return -1; } } #if ON_WIN32 /* on Windows: replace backslashes in filename with forward slashes */ replace_backslahes_with_slashes(filename); #endif /* insert fileinfo into filelist */ if (rb_find(g_filelist, filename) != NULL) { fprintf(stderr, "%s: \"%s\" line %d: duplicate file name.\n", g_progname, gopt_digestfile, linenum); return -1; } rb_insert(g_filelist, filename, fileinfo); gopt_digesttype = this_digesttype; /* return +1 here to clear tempinfo. */ return 1; } } bool select_digestfile(void) { /* Check for existing standard digest file names. However, if multiple exist, failed with an error message. */ if (access("md5sum.txt", F_OK) == 0) { gopt_digesttype = DT_MD5; gopt_digestfile = "md5sum.txt"; } if (access("sha1sum.txt", F_OK) == 0) { if (gopt_digestfile != NULL) { fprintf(stderr, "%s: multiple digest files found in current directory. Select one using --file.\n", g_progname); return FALSE; } gopt_digesttype = DT_SHA1; gopt_digestfile = "sha1sum.txt"; } if (access("sha128sum.txt", F_OK) == 0) { if (gopt_digestfile != NULL) { fprintf(stderr, "%s: multiple digest files found in current directory. Select one using --file.\n", g_progname); return FALSE; } gopt_digesttype = DT_SHA1; gopt_digestfile = "sha128sum.txt"; } if (access("sha256sum.txt", F_OK) == 0) { if (gopt_digestfile != NULL) { fprintf(stderr, "%s: multiple digest files found in current directory. Select one using --file.\n", g_progname); return FALSE; } gopt_digesttype = DT_SHA256; gopt_digestfile = "sha256sum.txt"; } if (access("sha512sum.txt", F_OK) == 0) { if (gopt_digestfile != NULL) { fprintf(stderr, "%s: multiple digest files found in current directory. Select one using --file.\n", g_progname); return FALSE; } gopt_digesttype = DT_SHA512; gopt_digestfile = "sha512sum.txt"; } return TRUE; } bool read_digestfile(void) { FILE* sumfile; struct FileInfo tempinfo; char *line = NULL; size_t linemax = 0; ssize_t linelen; unsigned int linenum = 0; int res = 0; uint32_t crc = 0, nextcrc; if (gopt_digestfile == NULL) { if (!select_digestfile()) return FALSE; if (gopt_digestfile == NULL) { fprintf(stderr, "%s: no digest file found. Creating \"sha1sum.txt\" from full scan.\n", g_progname); gopt_digesttype = DT_SHA1; gopt_digestfile = "sha1sum.txt"; return TRUE; } } sumfile = fopen(gopt_digestfile, "rb"); if (sumfile == NULL) { if (errno == ENOENT) { fprintf(stderr, "%s: could not open digest file \"%s\": performing full scan.\n", g_progname, gopt_digestfile); if (gopt_digesttype == DT_NONE) { fprintf(stderr, "%s: to create a new digest file specify the digest --type (see --help).\n", g_progname); return FALSE; } return TRUE; } else { fprintf(stderr, "%s: could not open digest file \"%s\": %s\n", g_progname, gopt_digestfile, strerror(errno)); return FALSE; } } memset(&tempinfo, 0, sizeof(struct FileInfo)); tempinfo.status = FS_UNSEEN; while ( (linelen = getline(&line, &linemax, sumfile)) >= 0 ) { ++linenum; if (res == -2) /* last line indicated eof */ { fprintf(stderr, "%s: \"%s\" line %d: superfluous line after eof.\n", g_progname, gopt_digestfile, linenum); } nextcrc = crc32(crc, (unsigned char*)line, linelen); /* remove trailing newline */ if (linelen > 0 && line[linelen-1] == '\n') line[linelen-1] = 0; res = parse_digestline(line, linenum, &tempinfo, crc); if (res != 0) { /* Illegal or valid digest line found. Clear fileinfo. */ if (tempinfo.symlink) free(tempinfo.symlink); memset(&tempinfo, 0, sizeof(struct FileInfo)); tempinfo.status = FS_UNSEEN; } crc = nextcrc; } if (line) free(line); if (rb_isempty(g_filelist)) { fprintf(stderr, "%s: %s: no digests found in file.\n", g_progname, gopt_digestfile); if (gopt_digesttype == DT_NONE) { fprintf(stderr, "%s: to create a new digest file specify the digest --type (see --help).\n", g_progname); return FALSE; } } else { /* Insert all file digests into the map for fast lookup. */ /* Simulanteously mark files as skipped that don't match --restrict */ struct rb_node* node; for (node = rb_begin(g_filelist); node != rb_end(g_filelist); node = rb_successor(g_filelist, node)) { struct FileInfo* fileinfo = node->value; if (gopt_matchpattern && strstr(node->key, gopt_matchpattern) == NULL) { fileinfo->status = FS_SKIPPED; ++g_filelist_skipped; } if (fileinfo->digest) { rb_insert(g_filedigestmap, digest_dup(fileinfo->digest), node->key); } } } fclose(sumfile); return TRUE; } /************************************************************* * Functions to recursively scan directories and process file * *************************************************************/ bool process_file(const char* filepath, const mystatst* st) { struct rb_node* fileiter; struct rb_node* digestiter; if (filepath[0] == '.' && filepath[1] == '/') filepath += 2; /* skip over the digestfile */ if (strcmp(filepath, gopt_digestfile) == 0) return TRUE; /* silently skip over ignored filepaths */ if (gopt_matchpattern && strstr(filepath, gopt_matchpattern) == NULL) return TRUE; if (gopt_verbose >= 2) { fprintf(stdout, "%s ", filepath); } /* lookup file info for mtime */ fileiter = rb_find(g_filelist, filepath); if (fileiter != NULL) { struct FileInfo* fileinfo = fileiter->value; digest_result* filedigest = NULL; if (fileinfo->status != FS_UNSEEN) { if (gopt_verbose >= 2) { fprintf(stdout, " same file processed twice??? This should never occur.\n"); } else { fprintf(stdout, "%s same file processed twice??? This should never occur.\n", filepath); } return TRUE; } if (gopt_fullcheck) { if (gopt_verbose >= 2) { fprintf(stdout, "check "); } } else if ((unsigned int)labs(st->st_mtime - fileinfo->mtime) > gopt_modify_window || st->st_size != fileinfo->size) { if (gopt_verbose >= 2) { fprintf(stdout, "touched "); } } else { if (gopt_verbose >= 2) { fprintf(stdout, "untouched.\n"); } else if (gopt_verbose == 1 && !gopt_onlymodified) { fprintf(stdout, "%s untouched.\n", filepath); } fileinfo->status = FS_SEEN; ++g_filelist_seen; return TRUE; } /* calculate file digest */ if (!digest_file(filepath, st->st_size, &filedigest, &fileinfo->error)) { fileinfo->status = FS_ERROR; fileinfo->mtime = st->st_mtime; fileinfo->size = st->st_size; ++g_filelist_error; return FALSE; } if (fileinfo->digest && digest_equal(filedigest, fileinfo->digest)) { if (gopt_verbose >= 2) { fprintf(stdout, " matched.\n"); } else if (gopt_verbose == 1 && !gopt_onlymodified) { fprintf(stdout, "%s matched.\n", filepath); } fileinfo->status = FS_TOUCHED; fileinfo->mtime = st->st_mtime; fileinfo->size = st->st_size; free(filedigest); ++g_filelist_touched; } else { if (gopt_verbose >= 2) { fprintf(stdout, " CHANGED.\n"); } else if (gopt_verbose == 1) { fprintf(stdout, "%s CHANGED.\n", filepath); } fileinfo->status = FS_CHANGED; fileinfo->mtime = st->st_mtime; fileinfo->size = st->st_size; if (fileinfo->digest) free(fileinfo->digest); fileinfo->digest = filedigest; ++g_filelist_changed; } return TRUE; } else { struct FileInfo* fileinfo = malloc(sizeof(struct FileInfo)); memset(fileinfo, 0, sizeof(struct FileInfo)); fileinfo->status = FS_NEW; fileinfo->mtime = st->st_mtime; fileinfo->size = st->st_size; if (!digest_file(filepath, st->st_size, &fileinfo->digest, &fileinfo->error)) { fileinfo->status = FS_ERROR; rb_insert(g_filelist, strdup(filepath), fileinfo); ++g_filelist_error; return FALSE; } /* look for existing file with equal digest */ digestiter = rb_find(g_filedigestmap, fileinfo->digest); if (digestiter != NULL) { bool copied = FALSE; struct rb_node* nodecopy = digestiter; /* test if the oldfile still exists. */ while (nodecopy != rb_end(g_filedigestmap) && digest_equal((digest_result*)nodecopy->key, fileinfo->digest)) { if (access((char*)nodecopy->value, F_OK) == 0) { copied = TRUE; digestiter = nodecopy; } else { /* lookup FileInfo of matching file and set oldpath flags */ struct rb_node* filenode = rb_find(g_filelist, nodecopy->value); if (filenode == NULL) { fprintf(stderr, "\n%s: internal error. Cannot find entry for matching file.\n", g_progname); } else if (((struct FileInfo*)filenode->value)->status == FS_UNSEEN) { ((struct FileInfo*)filenode->value)->status = FS_OLDPATH; ++g_filelist_oldpath; } else if (((struct FileInfo*)filenode->value)->status == FS_OLDPATH) { } else { fprintf(stderr, "\n%s: renamed original file still existed when scanning.\n", g_progname); } } nodecopy = rb_successor(g_filedigestmap, nodecopy); } if (copied) { fileinfo->status = FS_COPIED; ++g_filelist_copied; if (gopt_verbose >= 2) { fprintf(stdout, " copied.\n"); } else if (gopt_verbose == 1) { fprintf(stdout, "%s copied.\n", filepath); } } else { fileinfo->status = FS_RENAMED; ++g_filelist_renamed; if (gopt_verbose >= 2) { fprintf(stdout, " renamed.\n"); } else if (gopt_verbose == 1) { fprintf(stdout, "%s renamed.\n", filepath); } } if (gopt_verbose >= 1) { fprintf(stdout, "<-- %s", (char*)digestiter->value); } fileinfo->oldpath = strdup((char*)digestiter->value); } rb_insert(g_filelist, strdup(filepath), fileinfo); if (fileinfo->status == FS_NEW) { if (gopt_verbose >= 2) { fprintf(stdout, " new."); } else if (gopt_verbose == 1) { fprintf(stdout, "%s new.", filepath); } ++g_filelist_new; } if (gopt_verbose >= 1) { fprintf(stdout, "\n"); } return TRUE; } } bool process_symlink(const char* filepath, const mystatst* st) { struct rb_node* fileiter; if (filepath[0] == '.' && filepath[1] == '/') filepath += 2; /* skip over the digestfile */ if (strcmp(filepath, gopt_digestfile) == 0) return TRUE; /* silently skip over ignored filepaths */ if (gopt_matchpattern && strstr(filepath, gopt_matchpattern) == NULL) return TRUE; if (gopt_verbose >= 2) { fprintf(stdout, "%s ", filepath); } /* lookup file info */ fileiter = rb_find(g_filelist, filepath); if (fileiter != NULL) { struct FileInfo* fileinfo = fileiter->value; char* linktarget = NULL; if (fileinfo->status != FS_UNSEEN) { if (gopt_verbose >= 2) { fprintf(stdout, " same symlink processed twice??? This should never occur.\n"); } else { fprintf(stdout, "%s same symlink processed twice??? This should never occur.\n", filepath); } return TRUE; } /* mimic method used for regular files even though reading a * symlink is no expensive operation. */ if (gopt_fullcheck) { if (gopt_verbose >= 2) { fprintf(stdout, "check "); } } else if (st->st_mtime != fileinfo->mtime || st->st_size != fileinfo->size) { if (gopt_verbose >= 2) { fprintf(stdout, "touched "); } } else { if (gopt_verbose >= 2) { fprintf(stdout, "untouched.\n"); } else if (gopt_verbose == 1 && !gopt_onlymodified) { fprintf(stdout, "%s untouched.\n", filepath); } fileinfo->status = FS_SEEN; ++g_filelist_seen; return TRUE; } linktarget = readlink_dup(filepath); if (!linktarget) { if (gopt_verbose >= 2) { fprintf(stdout, " ERROR. Could not read symlink: %s.\n", strerror(errno)); } else if (gopt_verbose >= 1) { fprintf(stdout, "%s ERROR. Could not read symlink: %s.\n", filepath, strerror(errno)); } else if (gopt_verbose >= 0) { fprintf(stderr, "%s: could not read symlink \"%s\": %s.\n", g_progname, filepath, strerror(errno)); } my_asprintf(&fileinfo->error, "Could not read symlink: %s.", strerror(errno)); fileinfo->status = FS_ERROR; fileinfo->mtime = st->st_mtime; fileinfo->size = st->st_size; ++g_filelist_error; return FALSE; } if (fileinfo->symlink && strcmp(linktarget, fileinfo->symlink) == 0) { if (gopt_verbose >= 2) { fprintf(stdout, "matched.\n"); } else if (gopt_verbose == 1 && !gopt_onlymodified) { fprintf(stdout, "%s matched.\n", filepath); } fileinfo->status = FS_TOUCHED; fileinfo->mtime = st->st_mtime; fileinfo->size = st->st_size; free(linktarget); ++g_filelist_touched; } else { if (gopt_verbose >= 2) { fprintf(stdout, "CHANGED.\n"); } else if (gopt_verbose == 1) { fprintf(stdout, "%s CHANGED.\n", filepath); } fileinfo->status = FS_CHANGED; fileinfo->mtime = st->st_mtime; fileinfo->size = st->st_size; if (fileinfo->symlink) free(fileinfo->symlink); fileinfo->symlink = linktarget; ++g_filelist_changed; } return TRUE; } else { struct FileInfo* fileinfo = malloc(sizeof(struct FileInfo)); memset(fileinfo, 0, sizeof(struct FileInfo)); fileinfo->status = FS_NEW; fileinfo->mtime = st->st_mtime; fileinfo->size = st->st_size; fileinfo->symlink = readlink_dup(filepath); if (!fileinfo->symlink) { if (gopt_verbose >= 2) { fprintf(stdout, " ERROR. Could not read symlink: %s.\n", strerror(errno)); } else if (gopt_verbose >= 1) { fprintf(stdout, "%s ERROR. Could not read symlink: %s.\n", filepath, strerror(errno)); } else if (gopt_verbose >= 0) { fprintf(stderr, "%s: could not read symlink \"%s\": %s.\n", g_progname, filepath, strerror(errno)); } my_asprintf(&fileinfo->error, "Could not read symlink: %s.", strerror(errno)); fileinfo->status = FS_ERROR; rb_insert(g_filelist, strdup(filepath), fileinfo); ++g_filelist_error; return FALSE; } rb_insert(g_filelist, strdup(filepath), fileinfo); if (gopt_verbose >= 2) { fprintf(stdout, "new.\n"); } else if (gopt_verbose == 1) { fprintf(stdout, "%s new.\n", filepath); } ++g_filelist_new; return TRUE; } } /** * Dynamically growing array of (dev_t, ino_t) pairs to test for * symlink loops while scanning. */ struct DirLevel { dev_t dev; ino_t ino; }; struct DirLevel* dirstack = NULL; size_t dirstackmax = 0; size_t dirstacklen = 0; bool dirstack_push(const mystatst* st) { #if !ON_WIN32 /* win32 under mingw has no inode numbers. */ size_t i; /* first search in the current stack for the new level */ for (i = 0; i < dirstacklen; ++i) { if (dirstack[i].dev == st->st_dev && dirstack[i].ino == st->st_ino) { return FALSE; } } #endif /* add new entry */ if (dirstacklen >= dirstackmax) { struct DirLevel* tmp; dirstackmax = dirstackmax * 2; if (dirstackmax < 16) dirstackmax = 16; tmp = realloc(dirstack, sizeof(struct DirLevel) * dirstackmax); if (!tmp) { return FALSE; } dirstack = tmp; } dirstack[dirstacklen].dev = st->st_dev; dirstack[dirstacklen].ino = st->st_ino; ++dirstacklen; return TRUE; } void dirstack_pop(const mystatst* st) { assert( dirstacklen > 0 ); assert( dirstack[dirstacklen-1].dev == st->st_dev ); assert( dirstack[dirstacklen-1].ino == st->st_ino ); (void)st; if (dirstacklen > 0) --dirstacklen; } bool scan_directory(const char* path, const mystatst* st) { DIR* dirp; struct dirent* de; char **filenames = NULL; unsigned int filenamepos = 0; unsigned int filenamemax = 0; bool exclude_marker_found = FALSE; if (!dirstack_push(st)) { fprintf(stderr, "%s: filesystem loop detected at \"%s\".\n", g_progname, path); return TRUE; } dirp = opendir(path); if (dirp == NULL) { dirstack_pop(st); fprintf(stderr, "%s: could not open directory \"%s\": %s\n", g_progname, path, strerror(errno)); return FALSE; } while ((de = readdir(dirp))) { if (de->d_name[0] == '.' && de->d_name[1] == 0) continue; if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == 0) continue; if (filenamepos >= filenamemax) { filenamemax *= 2; if (filenamemax == 0) filenamemax = 8; filenames = realloc(filenames, sizeof(char*) * filenamemax); } filenames[filenamepos++] = strdup( de->d_name ); if (gopt_exclude_marker) { if (strcmp(de->d_name, gopt_exclude_marker) == 0) exclude_marker_found = TRUE; } } closedir(dirp); if (exclude_marker_found) { if (gopt_verbose >= 2) { fprintf(stderr, "%s: exclude marker found in \"%s\": skipping.\n", g_progname, path); } free(filenames); dirstack_pop(st); return TRUE; } qsort(filenames, filenamepos, sizeof(char*), strcmpptr); { mystatst st; unsigned int fi; for (fi = 0; fi < filenamepos; ++fi) { char* filepath; my_asprintf(&filepath, "%s/%s", path, filenames[fi]); free(filenames[fi]); #ifndef S_ISSOCK #define S_ISSOCK(x) 0 #endif #ifndef S_ISLNK #define S_ISLNK(x) 0 #endif if (mylstat(filepath, &st) != 0) { fprintf(stderr, "%s: could not stat file \"%s\": %s\n", g_progname, filepath, strerror(errno)); } else if (S_ISLNK(st.st_mode)) { if (!gopt_followsymlinks) { process_symlink(filepath, &st); } else { if (mystat(filepath, &st) != 0) { fprintf(stderr, "%s: could not stat symlink \"%s\": %s\n", g_progname, filepath, strerror(errno)); } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { fprintf(stderr, "%s: skipping special device symlink \"%s\"\n", g_progname, filepath); } else if (S_ISFIFO(st.st_mode)) { fprintf(stderr, "%s: skipping named pipe symlink \"%s\"\n", g_progname, filepath); } else if (S_ISSOCK(st.st_mode)) { fprintf(stderr, "%s: skipping unix socket symlink \"%s\"\n", g_progname, filepath); } else if (S_ISDIR(st.st_mode)) { scan_directory(filepath, &st); } else if (!S_ISREG(st.st_mode)) { fprintf(stderr, "%s: skipping special symlink \"%s\"\n", g_progname, filepath); } else { process_file(filepath, &st); } } } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { fprintf(stderr, "%s: skipping special device file \"%s\"\n", g_progname, filepath); } else if (S_ISFIFO(st.st_mode)) { fprintf(stderr, "%s: skipping named pipe \"%s\"\n", g_progname, filepath); } else if (S_ISSOCK(st.st_mode)) { fprintf(stderr, "%s: skipping unix socket \"%s\"\n", g_progname, filepath); } else if (S_ISDIR(st.st_mode)) { scan_directory(filepath, &st); } else if (!S_ISREG(st.st_mode)) { fprintf(stderr, "%s: skipping special file \"%s\"\n", g_progname, filepath); } else { process_file(filepath, &st); } free(filepath); } } free(filenames); dirstack_pop(st); return TRUE; } bool start_scan(const char* path) { mystatst st; if (mylstat(path, &st) != 0) { fprintf(stderr, "%s: could not stat path \"%s\": %s\n", g_progname, path, strerror(errno)); } else if (S_ISDIR(st.st_mode)) { return scan_directory(path, &st); } else if (!S_ISREG(st.st_mode)) { fprintf(stderr, "%s: skipping special path \"%s\"\n", g_progname, path); } else { return process_file(path, &st); } return FALSE; } /************************************************* * Functions for interactive scan result review * *************************************************/ struct CommandEntry { const char* name; bool (*func)(void); const char* help; }; static struct CommandEntry cmdlist[16]; bool filelist_clean(void) { return ( rb_size(g_filelist) == g_filelist_seen + g_filelist_touched ); } unsigned int filelist_deleted(void) { return rb_size(g_filelist) - (g_filelist_new + g_filelist_seen + g_filelist_touched + g_filelist_changed + g_filelist_error + g_filelist_renamed + g_filelist_copied + g_filelist_oldpath + g_filelist_skipped); } void print_summary(void) { fprintf(stdout, "File scan summary:\n"); if (g_filelist_new) fprintf(stdout, " New: %d\n", g_filelist_new); if (g_filelist_seen) fprintf(stdout, " Untouched: %d\n", g_filelist_seen); if (g_filelist_touched) fprintf(stdout, " Touched: %d\n", g_filelist_touched); if (g_filelist_changed) fprintf(stdout, " Changed: %d\n", g_filelist_changed); if (g_filelist_error) fprintf(stdout, " Errors: %d\n", g_filelist_error); if (g_filelist_renamed) fprintf(stdout, " Renamed: %d\n", g_filelist_renamed); if (g_filelist_copied) fprintf(stdout, " Copied: %d\n", g_filelist_copied); if (g_filelist_skipped) fprintf(stdout, " Skipped: %d\n", g_filelist_skipped); if (filelist_deleted()) fprintf(stdout, " Deleted: %d\n", filelist_deleted()); fprintf(stdout, " Total: %d\n", rb_size(g_filelist)); } bool cmd_help(void) { int i; fprintf(stdout, "Commands: (can be abbreviated)\n"); for (i = 0; cmdlist[i].name; ++i) { if (!cmdlist[i].help) continue; fprintf(stdout, " %-10s %s\n", cmdlist[i].name, cmdlist[i].help); } return TRUE; } bool cmd_new(void) { struct rb_node* node; unsigned int count = 0; for (node = rb_begin(g_filelist); node != rb_end(g_filelist); node = rb_successor(g_filelist, node)) { const struct FileInfo* fileinfo = node->value; if (fileinfo->status != FS_NEW) continue; fprintf(stdout, "%s new.\n", (char*)node->key); ++count; } if (count == 0) { fprintf(stdout, "%s: no new files encountered during scan.\n", g_progname); } return TRUE; } bool cmd_untouched(void) { struct rb_node* node; unsigned int count = 0; for (node = rb_begin(g_filelist); node != rb_end(g_filelist); node = rb_successor(g_filelist, node)) { const struct FileInfo* fileinfo = node->value; if (fileinfo->status != FS_SEEN) continue; fprintf(stdout, "%s untouched.\n", (char*)node->key); ++count; } if (count == 0) { fprintf(stdout, "%s: no untouched files encountered during scan.\n", g_progname); } return TRUE; } bool cmd_touched(void) { struct rb_node* node; unsigned int count = 0; for (node = rb_begin(g_filelist); node != rb_end(g_filelist); node = rb_successor(g_filelist, node)) { const struct FileInfo* fileinfo = node->value; if (fileinfo->status != FS_TOUCHED) continue; fprintf(stdout, "%s touched.\n", (char*)node->key); ++count; } if (count == 0) { fprintf(stdout, "%s: no touched but unchanged files encountered during scan.\n", g_progname); } return TRUE; } bool cmd_changed(void) { struct rb_node* node; unsigned int count = 0; for (node = rb_begin(g_filelist); node != rb_end(g_filelist); node = rb_successor(g_filelist, node)) { const struct FileInfo* fileinfo = node->value; if (fileinfo->status != FS_CHANGED) continue; fprintf(stdout, "%s CHANGED.\n", (char*)node->key); ++count; } if (count == 0) { fprintf(stdout, "%s: no changed files encountered during scan.\n", g_progname); } return TRUE; } bool cmd_deleted(void) { struct rb_node* node; unsigned int count = 0; for (node = rb_begin(g_filelist); node != rb_end(g_filelist); node = rb_successor(g_filelist, node)) { const struct FileInfo* fileinfo = node->value; if (fileinfo->status != FS_UNSEEN) continue; fprintf(stdout, "%s DELETED.\n", (char*)node->key); ++count; } if (count == 0) { fprintf(stdout, "%s: no deleted files detected during scan.\n", g_progname); } return TRUE; } bool cmd_error(void) { struct rb_node* node; unsigned int count = 0; for (node = rb_begin(g_filelist); node != rb_end(g_filelist); node = rb_successor(g_filelist, node)) { const struct FileInfo* fileinfo = node->value; if (fileinfo->status != FS_ERROR) continue; fprintf(stdout, "%s ERROR. %s\n", (char*)node->key, fileinfo->error); ++count; } if (count == 0) { fprintf(stdout, "%s: no errors encountered during scan.\n", g_progname); } return TRUE; } bool cmd_copied(void) { struct rb_node* node; unsigned int count = 0; for (node = rb_begin(g_filelist); node != rb_end(g_filelist); node = rb_successor(g_filelist, node)) { const struct FileInfo* fileinfo = node->value; if (fileinfo->status != FS_COPIED) continue; fprintf(stdout, "%s copied.\n<-- %s\n", (char*)node->key, fileinfo->oldpath); ++count; } if (count == 0) { fprintf(stdout, "%s: no copied files detected during scan.\n", g_progname); } return TRUE; } bool cmd_renamed(void) { struct rb_node* node; unsigned int count = 0; for (node = rb_begin(g_filelist); node != rb_end(g_filelist); node = rb_successor(g_filelist, node)) { const struct FileInfo* fileinfo = node->value; if (fileinfo->status != FS_RENAMED) continue; fprintf(stdout, "%s renamed.\n<-- %s\n", (char*)node->key, fileinfo->oldpath); ++count; } if (count == 0) { fprintf(stdout, "%s: no renamed files detected during scan.\n", g_progname); } return TRUE; } bool cmd_skipped(void) { struct rb_node* node; unsigned int count = 0; for (node = rb_begin(g_filelist); node != rb_end(g_filelist); node = rb_successor(g_filelist, node)) { const struct FileInfo* fileinfo = node->value; if (fileinfo->status != FS_SKIPPED) continue; fprintf(stdout, "%s SKIPPED.\n", (char*)node->key); ++count; } if (count == 0) { fprintf(stdout, "%s: no files skipped during scan.\n", g_progname); } return TRUE; } bool cmd_write(void) { FILE *sumfile = fopen(gopt_digestfile, "wb"); uint32_t crc = 0; char digeststr[128]; unsigned int digestcount = 0; struct rb_node* node; if (sumfile == NULL) { fprintf(stderr, "%s: could not open %s: %s\n", g_progname, gopt_digestfile, strerror(errno)); return TRUE; } /* add a small note current date at the beginning */ { time_t tnow = time(NULL); char datenow[64]; strftime(datenow, sizeof(datenow), "%Y-%m-%d %H:%M:%S %Z", localtime(&tnow)); fprintfcrc(&crc, sumfile, "# %s last update: %s\n", g_progname, datenow); } /* add persisent options to digest file */ if (gopt_exclude_marker) { fprintfcrc(&crc, sumfile, "#: option --exclude-marker=%s\n", gopt_exclude_marker); } /* list files with properties and digests */ for (node = rb_begin(g_filelist); node != rb_end(g_filelist); node = rb_successor(g_filelist, node)) { struct FileInfo* fileinfo = node->value; char* filename; if (fileinfo->status == FS_UNSEEN) continue; if (fileinfo->status == FS_ERROR) continue; if (fileinfo->status == FS_OLDPATH) continue; filename = strdup((char*)node->key); if (fileinfo->symlink) { #if ON_WIN32 /* mingw uses msvcrt which uses %I64d or %I64u for long long formatting. */ if (needescape_filename(&fileinfo->symlink)) /* may replace the symlink string */ fprintfcrc(&crc, sumfile, "#: mtime %ld size %I64d target\\ %s\n", fileinfo->mtime, fileinfo->size, fileinfo->symlink); else fprintfcrc(&crc, sumfile, "#: mtime %ld size %I64d target %s\n", fileinfo->mtime, fileinfo->size, fileinfo->symlink); #else if (needescape_filename(&fileinfo->symlink)) /* may replace the symlink string */ fprintfcrc(&crc, sumfile, "#: mtime %ld size %lld target\\ %s\n", fileinfo->mtime, fileinfo->size, fileinfo->symlink); else fprintfcrc(&crc, sumfile, "#: mtime %ld size %lld target %s\n", fileinfo->mtime, fileinfo->size, fileinfo->symlink); #endif if (needescape_filename(&filename)) /* may replace the filename string */ fprintfcrc(&crc, sumfile, "#: symlink\\ %s\n", filename); else fprintfcrc(&crc, sumfile, "#: symlink %s\n", filename); } else { #if ON_WIN32 /* mingw uses msvcrt which uses %I64d or %I64u for long long formatting. */ fprintfcrc(&crc, sumfile, "#: mtime %ld size %I64d\n", fileinfo->mtime, fileinfo->size); #else fprintfcrc(&crc, sumfile, "#: mtime %ld size %lld\n", fileinfo->mtime, fileinfo->size); #endif if (needescape_filename(&filename)) /* may replace the filename string */ fprintfcrc(&crc, sumfile, "\\"); fprintfcrc(&crc, sumfile, "%s %s\n", digest_bin2hex(fileinfo->digest, digeststr), filename); } ++digestcount; free(filename); } fprintf(sumfile, "#: crc 0x%08x eof\n", crc); fclose(sumfile); fprintf(stderr, "%s: wrote %d digests to %s\n", g_progname, digestcount, gopt_digestfile); return FALSE; } bool cmd_quit(void) { return FALSE; } static struct CommandEntry cmdlist[16] = { { "help", &cmd_help, "See this help text." }, { "new", &cmd_new, "Print newly seen files not in digest file." }, { "untouched", &cmd_untouched, "Print all untouched files." }, { "touched", &cmd_touched, "Print all files with changed modification time." }, { "changed", &cmd_changed, "Print files with changed contents." }, { "modified", &cmd_changed, NULL }, { "copied", &cmd_copied, "Print files copied from a different path." }, { "renamed", &cmd_renamed, "Print files renamed from a different path." }, { "deleted", &cmd_deleted, "Print deleted files." }, { "error", &cmd_error, "Print files with read errors." }, { "skipped", &cmd_skipped, "Print files skipped during scan." }, { "save", &cmd_write, "Write updates to digest file and exit program." }, { "write", &cmd_write, NULL }, { "exit", &cmd_quit, "Exit program without saving updates." }, { "quit", &cmd_quit, NULL }, { NULL, NULL, NULL }, }; /********** * main() * **********/ void print_usage(void) { /* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ printf("Usage: %s [OPTIONS...]\n" "\n" "Tool to read, verify and update MD5 or SHA digest files.\n" "\n", g_progname); printf("Looks for a digest file (defaults to \"md5sum.txt\", \"sha1sum.txt\",\n" "\"sha256sum.txt\" or \"sha512sum.txt\") in the current directory. If one exists\n" "it is parsed and loaded. Then all files in the directory are recursively\n" "checked. Their status (new, unmodified, touched and matching, changed) is\n" "determined from modification time and the stored file digest. After the scan\n" "a manual review of the status can be done and a new digest file written.\n" "\n"); printf("Options:\n"); printf(" -b, --batch enable non-interactive batch processing mode.\n"); printf(" -c, --check perform full digest check ignoring modification times.\n"); printf(" -d, --directory=PATH change into this directory before any operations.\n"); printf(" --exclude-marker=FILE skip all directories contain this marker file.\n"); printf(" -f, --file=FILE check FILE for existing digests and writing updates.\n"); printf(" -l, --links follow symlinks instead of saving their destination.\n"); printf(" -m, --modified suppressing printing of unchanged files.\n"); printf(" --modify-window=NUM allow higher delta window for modification times.\n"); printf(" -q, --quiet reduce status printing while scanning.\n"); printf(" -r, --restrict=PAT run full digest check restricted to files matching PAT.\n"); printf(" -t, --type=TYPE select digest type for newly created digest files.\n"); printf(" TYPE = md5, sha1, sha256 or sha512.\n"); printf(" -u, --update automatically update digest file in batch mode.\n"); printf(" -v, --verbose increase status printing during scanning.\n"); printf(" -V, --version print digup version and exit.\n"); printf(" -w, --windows allow a --modify-window of 1 (for FAT filesystems).\n"); printf("\n"); printf("See \"man 1 digup\" for further explanations. This is digup " VERSION "\n"); printf("\n"); } int main(int argc, char* argv[]) { int retcode = 0; g_progname = argv[0]; while (1) { static struct option long_options[] = { { "batch", no_argument, 0, 'b' }, { "check", no_argument, 0, 'c' }, { "directory", required_argument, 0, 'd' }, { "file", required_argument, 0, 'f' }, { "help", no_argument, 0, 'h' }, { "links", no_argument, 0, 'l' }, { "modified", no_argument, 0, 'm' }, { "quiet", no_argument, 0, 'q' }, { "restrict", required_argument, 0, 'r' }, { "type", required_argument, 0, 't' }, { "update", no_argument, 0, 'u' }, { "verbose", no_argument, 0, 'v' }, { "version", no_argument, 0, 'V' }, { "windows", no_argument, 0, 'w' }, { "modify-window", required_argument, 0, 1 }, { "exclude-marker", required_argument, 0, 2 }, { NULL, 0, 0, 0 } }; /* getgopt_long stores the option index here. */ int option_index = 0; int c = getopt_long(argc, argv, "bcd:f:hlmqr:t:uvVw", long_options, &option_index); if (c == -1) break; switch (c) { case 1: { char *endp; gopt_modify_window = strtoul(optarg, &endp, 10); if (!endp || *endp) { fprintf(stderr, "%s: invalid valid for modify window: use an unsigned integer\n", g_progname); return -1; } break; } case 2: gopt_exclude_marker = strdup(optarg); break; case 'b': gopt_batch = TRUE; --gopt_verbose; break; case 'c': gopt_fullcheck = TRUE; break; case 'd': if (chdir(optarg) != 0) { fprintf(stderr, "%s: could not chdir to \"%s\": %s\n", g_progname, optarg, strerror(errno)); return -1; } break; case 'f': gopt_digestfile = optarg; break; case 'h': print_usage(); return -1; case 'l': gopt_followsymlinks = TRUE; break; case 'm': gopt_onlymodified = TRUE; break; case 'q': --gopt_verbose; break; case 'r': gopt_matchpattern = optarg; fprintf(stdout, "Checking only paths matching: \"%s\".\n", gopt_matchpattern); break; case 't': if (strcasecmp(optarg, "md5") == 0) { gopt_digesttype = DT_MD5; if (gopt_digestfile == NULL) gopt_digestfile = "md5sum.txt"; } else if (strcasecmp(optarg, "sha1") == 0) { gopt_digesttype = DT_SHA1; if (gopt_digestfile == NULL) gopt_digestfile = "sha1sum.txt"; } else if (strcasecmp(optarg, "sha128") == 0) { gopt_digesttype = DT_SHA1; if (gopt_digestfile == NULL) gopt_digestfile = "sha128sum.txt"; } else if (strcasecmp(optarg, "sha256") == 0) { gopt_digesttype = DT_SHA256; if (gopt_digestfile == NULL) gopt_digestfile = "sha256sum.txt"; } else if (strcasecmp(optarg, "sha512") == 0) { gopt_digesttype = DT_SHA512; if (gopt_digestfile == NULL) gopt_digestfile = "sha512sum.txt"; } else { fprintf(stderr, "%s: unknown digest type: \"%s\". See --help.\n", g_progname, optarg); return -1; } break; case 'u': gopt_update = TRUE; break; case 'v': ++gopt_verbose; break; case 'V': printf("digup " VERSION "\n"); return 0; case 'w': gopt_modify_window = 1; break; case '?': /* getgopt_long already printed an error message. */ fprintf(stderr, "Try \"%s --help\" for more information on program usage.\n", g_progname); return -1; default: assert(0); } } /* print any remaining unknown command line arguments. */ if (optind < argc) { while (optind < argc) { fprintf(stderr, "%s: superfluous argument \"%s\"\n", g_progname, argv[optind++]); } return -1; } /* reduce level for only-modified printing */ if (gopt_onlymodified && gopt_verbose >= 2) gopt_verbose = 1; if (gopt_update && !gopt_batch) { fprintf(stderr, "%s: automaticcaly updating the digest file requires --batch mode.\n", g_progname); return -1; } /* initialize red-black trees */ g_filelist = rb_create(rbtree_string_cmp, rbtree_string_free, rbtree_fileinfo_free, NULL, NULL); g_filedigestmap = rb_create(rbtree_digest_result_cmp, rbtree_digest_result_free, rbtree_null_free, NULL, NULL); /* read digest file if it exists */ if (!read_digestfile()) return -1; /* recursively scan current directory */ start_scan("."); if (filelist_deleted() != 0 || !gopt_onlymodified) { /* always print deleted files, otherwise they may be silently ignored. */ cmd_deleted(); } /* batch processing */ if (gopt_batch) { if (!filelist_clean() || !gopt_onlymodified) print_summary(); if (gopt_update) { cmd_write(); } if (filelist_clean()) retcode = 0; else retcode = 1; /* changes, renames, moves, deletes or read errors detected. */ } /* interactive processing */ else { char input[256]; fprintf(stdout, "Scan finished. "); /* print scan summary */ while ( print_summary(), fprintf(stdout, "Command (see help)? "), fgets(input, sizeof(input), stdin) ) { /* Run through command table and determine entry by prefix matching */ int cmd = -1; unsigned int i; if (strlen(input) > 0 && input[strlen(input)-1] == '\n') input[strlen(input)-1] = 0; for (i = 0; cmdlist[i].name; ++i) { if (strncmp(input, cmdlist[i].name, strlen(input)) == 0) { if (cmd == -1) cmd = i; else cmd = -2; } } if (cmd >= 0) { if (!cmdlist[cmd].func()) break; } else if (cmd == -2) { fprintf(stdout, "%s: Ambiguous command. See \"help\".\n", g_progname); } else { fprintf(stdout, "%s: Unknown command. See \"help\".\n", g_progname); } } } rb_destroy(g_filelist); rb_destroy(g_filedigestmap); if (dirstack) free(dirstack); if (gopt_exclude_marker) free((void*)gopt_exclude_marker); return retcode; } /*****************************************************************************/ digup-digup-0.6.57/src/md5.c000066400000000000000000000304061370707046300154610ustar00rootroot00000000000000/***************************************************************************** * Functions to compute MD5 message digest. * * * * Copyright (C) 1995-1997,1999-2001,2004-2006,2008 * * by Free Software Foundation, Inc. * * * * This file was taken from coreutils-7.4 and adapted for digup. * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * Written by Ulrich Drepper , 1995. * *****************************************************************************/ #include "md5.h" #include #include #include #include #if HAVE_ENDIAN_H #include #define WORDS_ARE_BIGENDIAN (__BYTE_ORDER == __BIG_ENDIAN) #elif HAVE_SYS_PARAM_H #include #define WORDS_ARE_BIGENDIAN (BYTE_ORDER == BIG_ENDIAN) #else #error "Cannot determine system endianness." #endif #if WORDS_ARE_BIGENDIAN # define SWAP(n) \ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) #else # define SWAP(n) (n) #endif #define BLOCKSIZE 4096 #if BLOCKSIZE % 64 != 0 # error "invalid BLOCKSIZE" #endif /* This array contains the bytes used to pad the buffer to the next 64-byte boundary. (RFC 1321, 3.1: Step 1) */ static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; /* Initialize structure containing state of computation. (RFC 1321, 3.3: Step 3) */ void md5_init_ctx (struct md5_ctx *ctx) { ctx->A = 0x67452301; ctx->B = 0xefcdab89; ctx->C = 0x98badcfe; ctx->D = 0x10325476; ctx->total[0] = ctx->total[1] = 0; ctx->buflen = 0; } /* Copy the 4 byte value from v into the memory location pointed to by *cp, If your architecture allows unaligned access this is equivalent to * (uint32_t *) cp = v */ static inline void set_uint32 (char *cp, uint32_t v) { memcpy (cp, &v, sizeof v); } /* Put result from CTX in first 16 bytes following RESBUF. The result must be in little endian byte order. */ void * md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) { char *r = resbuf; set_uint32 (r + 0 * sizeof ctx->A, SWAP (ctx->A)); set_uint32 (r + 1 * sizeof ctx->B, SWAP (ctx->B)); set_uint32 (r + 2 * sizeof ctx->C, SWAP (ctx->C)); set_uint32 (r + 3 * sizeof ctx->D, SWAP (ctx->D)); return resbuf; } /* Process the remaining bytes in the internal buffer and the usual prolog according to the standard and write the result to RESBUF. */ void * md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) { /* Take yet unprocessed bytes into account. */ uint32_t bytes = ctx->buflen; size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; /* Now count remaining bytes. */ ctx->total[0] += bytes; if (ctx->total[0] < bytes) ++ctx->total[1]; /* Put the 64-bit file length in *bits* at the end of the buffer. */ ctx->buffer[size - 2] = SWAP (ctx->total[0] << 3); ctx->buffer[size - 1] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); /* Process last bytes. */ md5_process_block (ctx->buffer, size * 4, ctx); return md5_read_ctx (ctx, resbuf); } /* Compute MD5 message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ void * md5_buffer (const char *buffer, size_t len, void *resblock) { struct md5_ctx ctx; /* Initialize the computation context. */ md5_init_ctx (&ctx); /* Process whole buffer but last len % 64 bytes. */ md5_process_bytes (buffer, len, &ctx); /* Put result in desired memory area. */ return md5_finish_ctx (&ctx, resblock); } void md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) { /* When we already have some bits in our internal buffer concatenate both inputs first. */ if (ctx->buflen != 0) { size_t left_over = ctx->buflen; size_t add = 128 - left_over > len ? len : 128 - left_over; memcpy (&((char *) ctx->buffer)[left_over], buffer, add); ctx->buflen += add; if (ctx->buflen > 64) { md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx); ctx->buflen &= 63; /* The regions in the following copy operation cannot overlap. */ memcpy (ctx->buffer, &((char *) ctx->buffer)[(left_over + add) & ~63], ctx->buflen); } buffer = (const char *) buffer + add; len -= add; } /* Process available complete blocks. */ if (len >= 64) { #if !_STRING_ARCH_unaligned # define alignof(type) offsetof (struct { char c; type x; }, x) # define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) if (UNALIGNED_P (buffer)) while (len > 64) { md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); buffer = (const char *) buffer + 64; len -= 64; } else #endif { md5_process_block (buffer, len & ~63, ctx); buffer = (const char *) buffer + (len & ~63); len &= 63; } } /* Move remaining bytes in internal buffer. */ if (len > 0) { size_t left_over = ctx->buflen; memcpy (&((char *) ctx->buffer)[left_over], buffer, len); left_over += len; if (left_over >= 64) { md5_process_block (ctx->buffer, 64, ctx); left_over -= 64; memcpy (ctx->buffer, &ctx->buffer[16], left_over); } ctx->buflen = left_over; } } /* These are the four functions used in the four steps of the MD5 algorithm and defined in the RFC 1321. The first function is a little bit optimized (as found in Colin Plumbs public domain implementation). */ /* #define FF(b, c, d) ((b & c) | (~b & d)) */ #define FF(b, c, d) (d ^ (b & (c ^ d))) #define FG(b, c, d) FF (d, b, c) #define FH(b, c, d) (b ^ c ^ d) #define FI(b, c, d) (c ^ (b | ~d)) /* Process LEN bytes of BUFFER, accumulating context into CTX. It is assumed that LEN % 64 == 0. */ void md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) { uint32_t correct_words[16]; const uint32_t *words = buffer; size_t nwords = len / sizeof (uint32_t); const uint32_t *endp = words + nwords; uint32_t A = ctx->A; uint32_t B = ctx->B; uint32_t C = ctx->C; uint32_t D = ctx->D; /* First increment the byte count. RFC 1321 specifies the possible length of the file up to 2^64 bits. Here we only compute the number of bytes. Do a double word increment. */ ctx->total[0] += len; if (ctx->total[0] < len) ++ctx->total[1]; /* Process all bytes in the buffer with 64 bytes in each round of the loop. */ while (words < endp) { uint32_t *cwp = correct_words; uint32_t A_save = A; uint32_t B_save = B; uint32_t C_save = C; uint32_t D_save = D; /* First round: using the given function, the context and a constant the next context is computed. Because the algorithms processing unit is a 32-bit word and it is determined to work on words in little endian byte order we perhaps have to change the byte order before the computation. To reduce the work for the next steps we store the swapped words in the array CORRECT_WORDS. */ #define OP(a, b, c, d, s, T) \ do \ { \ a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ ++words; \ CYCLIC (a, s); \ a += b; \ } \ while (0) /* It is unfortunate that C does not provide an operator for cyclic rotation. Hope the C compiler is smart enough. */ #define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) /* Before we start, one word to the strange constants. They are defined in RFC 1321 as T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 Here is an equivalent invocation using Perl: perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}' */ /* Round 1. */ OP (A, B, C, D, 7, 0xd76aa478); OP (D, A, B, C, 12, 0xe8c7b756); OP (C, D, A, B, 17, 0x242070db); OP (B, C, D, A, 22, 0xc1bdceee); OP (A, B, C, D, 7, 0xf57c0faf); OP (D, A, B, C, 12, 0x4787c62a); OP (C, D, A, B, 17, 0xa8304613); OP (B, C, D, A, 22, 0xfd469501); OP (A, B, C, D, 7, 0x698098d8); OP (D, A, B, C, 12, 0x8b44f7af); OP (C, D, A, B, 17, 0xffff5bb1); OP (B, C, D, A, 22, 0x895cd7be); OP (A, B, C, D, 7, 0x6b901122); OP (D, A, B, C, 12, 0xfd987193); OP (C, D, A, B, 17, 0xa679438e); OP (B, C, D, A, 22, 0x49b40821); /* For the second to fourth round we have the possibly swapped words in CORRECT_WORDS. Redefine the macro to take an additional first argument specifying the function to use. */ #undef OP #define OP(f, a, b, c, d, k, s, T) \ do \ { \ a += f (b, c, d) + correct_words[k] + T; \ CYCLIC (a, s); \ a += b; \ } \ while (0) /* Round 2. */ OP (FG, A, B, C, D, 1, 5, 0xf61e2562); OP (FG, D, A, B, C, 6, 9, 0xc040b340); OP (FG, C, D, A, B, 11, 14, 0x265e5a51); OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); OP (FG, A, B, C, D, 5, 5, 0xd62f105d); OP (FG, D, A, B, C, 10, 9, 0x02441453); OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); OP (FG, D, A, B, C, 14, 9, 0xc33707d6); OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); OP (FG, B, C, D, A, 8, 20, 0x455a14ed); OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); OP (FG, C, D, A, B, 7, 14, 0x676f02d9); OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); /* Round 3. */ OP (FH, A, B, C, D, 5, 4, 0xfffa3942); OP (FH, D, A, B, C, 8, 11, 0x8771f681); OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); OP (FH, B, C, D, A, 14, 23, 0xfde5380c); OP (FH, A, B, C, D, 1, 4, 0xa4beea44); OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); OP (FH, B, C, D, A, 6, 23, 0x04881d05); OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); /* Round 4. */ OP (FI, A, B, C, D, 0, 6, 0xf4292244); OP (FI, D, A, B, C, 7, 10, 0x432aff97); OP (FI, C, D, A, B, 14, 15, 0xab9423a7); OP (FI, B, C, D, A, 5, 21, 0xfc93a039); OP (FI, A, B, C, D, 12, 6, 0x655b59c3); OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); OP (FI, C, D, A, B, 10, 15, 0xffeff47d); OP (FI, B, C, D, A, 1, 21, 0x85845dd1); OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); OP (FI, C, D, A, B, 6, 15, 0xa3014314); OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); OP (FI, A, B, C, D, 4, 6, 0xf7537e82); OP (FI, D, A, B, C, 11, 10, 0xbd3af235); OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); OP (FI, B, C, D, A, 9, 21, 0xeb86d391); /* Add the starting values of the context. */ A += A_save; B += B_save; C += C_save; D += D_save; } /* Put checksum in context given as argument. */ ctx->A = A; ctx->B = B; ctx->C = C; ctx->D = D; } /*****************************************************************************/ digup-digup-0.6.57/src/md5.h000066400000000000000000000073321370707046300154700ustar00rootroot00000000000000/***************************************************************************** * Declaration of functions and data types used for MD5 sum computing. * * * * Copyright (C) 1995-1997,1999-2001,2004-2006,2008 * * by Free Software Foundation, Inc. * * * * This file was taken from coreutils-7.4 and adapted for digup. * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ #ifndef _MD5_H #define _MD5_H 1 #include #include enum { MD5_DIGEST_SIZE = 16 }; /* Structure to save state of computation between the single steps. */ struct md5_ctx { uint32_t A, B, C, D; uint32_t total[2]; uint32_t buflen; uint32_t buffer[32]; }; /* Initialize structure containing state of computation. (RFC 1321, 3.3: Step 3) */ extern void md5_init_ctx (struct md5_ctx *ctx); /* Starting with the result of former calls of this function (or the initialization function update the context for the next LEN bytes starting at BUFFER. It is necessary that LEN is a multiple of 64!!! */ extern void md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx); /* Starting with the result of former calls of this function (or the initialization function update the context for the next LEN bytes starting at BUFFER. It is NOT required that LEN is a multiple of 64. */ extern void md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx); /* Process the remaining bytes in the buffer and put result from CTX in first 16 bytes following RESBUF. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ extern void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf); /* Put result from CTX in first 16 bytes following RESBUF. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ extern void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf); /* Compute MD5 message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ extern void *md5_buffer (const char *buffer, size_t len, void *resblock); #endif /* _MD5_H */ /*****************************************************************************/ digup-digup-0.6.57/src/rbtree.c000066400000000000000000000372711370707046300162660ustar00rootroot00000000000000/***************************************************************************** * Red-Black Balanced Binary Tree Implementation in Plain C * * * * Copyright (C) 2001,2005 Emin Martinian * * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted provided that neither the name of Emin * * Martinian nor the names of any contributors are be used to endorse * * or promote products derived from this software without specific * * prior written permission. * * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * * Modifications 2009 by Timo Bingmann for duplicate key trees, opaque * * pointers, invariant testing and general code cleanup. * * * *****************************************************************************/ #include "rbtree.h" #include #include #include /** * Tree object struct holding top-level information and function * pointers. * * - compare_keys(a,b) should return >0 if *a > *b, <0 if *a < *b, and * 0 otherwise. * - destroy_xyz(a) takes a pointer to either key or value object and * must free it accordingly. * - print_xyz(a) is used by rb_print() to dump the tree. */ struct rb_tree { int (*compare_keys)(const void *a, const void *b); void (*destroy_key)(void *a); void (*destroy_value)(void *a); void (*print_key)(const void *a); void (*print_value)(const void *a); struct rb_node *root, *nil; unsigned int size; }; /** * Create a new red-black tree object. Function pointers to all * necessary callbacks must be provided. Returns a new tree object. */ struct rb_tree *rb_create(int (*compare_keys_func)(const void*, const void*), void (*destroy_key_func)(void*), void (*destroy_value_func)(void*), void (*print_key_func)(const void*), void (*print_value_func)(const void*)) { struct rb_tree *tree; struct rb_node *temp; tree = (struct rb_tree*)malloc(sizeof(struct rb_tree)); if (tree == NULL) return NULL; tree->compare_keys = compare_keys_func; tree->destroy_key = destroy_key_func; tree->destroy_value = destroy_value_func; tree->print_key = print_key_func; tree->print_value = print_value_func; tree->size = 0; /* initialize nil and root nodes */ temp = tree->nil = (struct rb_node*)malloc(sizeof(struct rb_node)); temp->parent = temp->left = temp->right = temp; temp->red = 0; temp->key = 0; temp = tree->root = (struct rb_node*)malloc(sizeof(struct rb_node)); temp->parent = temp->left = temp->right = tree->nil; temp->red = 0; temp->key = 0; return tree; } /** * Returns true if the tree is empty. */ int rb_isempty(struct rb_tree *tree) { return (tree->root->left == tree->nil); } /** * Returns the number of elements in the tree. */ unsigned int rb_size(struct rb_tree *tree) { return tree->size; } /** * Returns first node or nil in the tree. */ struct rb_node *rb_begin(struct rb_tree *tree) { struct rb_node *x = tree->root->left; while (x->left != tree->nil) x = x->left; return x; } /** * Returns first node or nil in the tree. */ struct rb_node *rb_end(struct rb_tree *tree) { return tree->nil; } /** * Internal function. Applies the left rotation as described in * Introduction to Algorithms by Cormen, Leiserson and Rivest. */ static void rb_rotate_left(struct rb_tree *tree, struct rb_node *x) { struct rb_node *y, *nil = tree->nil; y = x->right; x->right = y->left; if (y->left != nil) y->left->parent = x; y->parent = x->parent; if (x == x->parent->left) { x->parent->left = y; } else { x->parent->right = y; } y->left = x; x->parent = y; assert(!tree->nil->red); /* nil not red in LeftRotate */ } /** * Internal function. Applies the right rotation as described in * Introduction to Algorithms by Cormen, Leiserson and Rivest. */ static void rb_rotate_right(struct rb_tree *tree, struct rb_node *y) { struct rb_node *x, *nil = tree->nil; x = y->left; y->left = x->right; if (nil != x->right) x->right->parent = y; x->parent = y->parent; if (y == y->parent->left) { y->parent->left = x; } else { y->parent->right = x; } x->right=y; y->parent=x; assert(!tree->nil->red); /* nil not red in RightRotate */ } /** * Internal function used by rb_insert(). Inserts z into the binary * tree as usual. Described in Introduction to Algorithms by Cormen, * Leiserson and Rivest. */ static void rb_insert_helper(struct rb_tree *tree, struct rb_node *z) { struct rb_node *x, *y, *nil = tree->nil; z->left = z->right = nil; y = tree->root; x = tree->root->left; while (x != nil) { y = x; if (tree->compare_keys(x->key, z->key) > 0) { /* x.key > z.key */ x = x->left; } else { /* x,key <= z.key */ x = x->right; } } z->parent = y; if ( (y == tree->root) || (tree->compare_keys(y->key, z->key) > 0) ) { /* y.key > z.key */ y->left = z; } else { y->right = z; } assert(!tree->nil->red); /* nil not red in TreeInsertHelp */ } /** * Insert function to place a new key, value pair into the tree, * taking ownership of key and value object.. First inserts a new node * and then applies iterative rotations to rebalance the tree. */ struct rb_node *rb_insert(struct rb_tree *tree, void *key, void *value) { struct rb_node *x, *y, *newnode; x = (struct rb_node*)malloc(sizeof(struct rb_node)); x->key = key; x->value = value; rb_insert_helper(tree, x); newnode = x; x->red = 1; while (x->parent->red) /* use sentinel instead of checking for root */ { if (x->parent == x->parent->parent->left) { y = x->parent->parent->right; if (y->red) { x->parent->red = 0; y->red = 0; x->parent->parent->red = 1; x = x->parent->parent; } else { if (x == x->parent->right) { x = x->parent; rb_rotate_left(tree, x); } x->parent->red = 0; x->parent->parent->red = 1; rb_rotate_right(tree, x->parent->parent); } } else /* case for x->parent == x->parent->parent->right */ { y = x->parent->parent->left; if (y->red) { x->parent->red = 0; y->red = 0; x->parent->parent->red = 1; x = x->parent->parent; } else { if (x == x->parent->left) { x = x->parent; rb_rotate_right(tree, x); } x->parent->red = 0; x->parent->parent->red = 1; rb_rotate_left(tree, x->parent->parent); } } } tree->root->left->red = 0; ++tree->size; #ifdef RBTREE_VERIFY assert(rb_verify(tree)); #endif return newnode; } /** * Return the successor node of x in the tree or tree->nil if there is * none. */ struct rb_node *rb_successor(struct rb_tree *tree, struct rb_node *x) { struct rb_node *y, *nil = tree->nil; struct rb_node *root = tree->root; if (nil != (y = x->right)) /* assignment to y is intentional */ { while (y->left != nil) { /* returns the minimum of the right subtree of x */ y = y->left; } return y; } else { y = x->parent; while (x == y->right) { /* sentinel used instead of checking for nil */ x = y; y = y->parent; } if (y == root) return nil; return y; } } /** * Return the predecessor node of x in the tree or tree->nil if there * is none. */ struct rb_node *rb_predecessor(struct rb_tree *tree, struct rb_node *x) { struct rb_node *y, *nil = tree->nil; struct rb_node *root = tree->root; if (nil != (y = x->left)) /* assignment to y is intentional */ { while (y->right != nil) { /* returns the maximum of the left subtree of x */ y = y->right; } return y; } else { y = x->parent; while (x == y->left) { if (y == root) return nil; x = y; y = y->parent; } return y; } } /** * Internal function to recursively destroy all nodes in the tree. */ static void rb_destroy_helper(struct rb_tree *tree, struct rb_node *x) { if (x != tree->nil) { rb_destroy_helper(tree, x->left); rb_destroy_helper(tree, x->right); tree->destroy_key(x->key); tree->destroy_value(x->value); free(x); } } /** * Destroy the tree and destroy all associated key and value objects * via the appropriate callbacks. */ void rb_destroy(struct rb_tree *tree) { rb_destroy_helper(tree, tree->root->left); free(tree->root); free(tree->nil); free(tree); } /** * Internal function to recursively print the whole tree in order. */ static void rb_print_inorder(struct rb_tree *tree, struct rb_node *x) { struct rb_node *nil = tree->nil; struct rb_node *root = tree->root; if (x != tree->nil) { rb_print_inorder(tree, x->left); printf("value="); tree->print_value(x->value); printf(" key="); tree->print_key(x->key); printf(" l->key="); if (x->left == nil) printf("NULL"); else tree->print_key(x->left->key); printf(" r->key="); if (x->right == nil) printf("NULL"); else tree->print_key(x->right->key); printf(" p->key="); if (x->parent == root) printf("NULL"); else tree->print_key(x->parent->key); printf(" red=%i\n", x->red); rb_print_inorder(tree, x->right); } } /** * Print the whole tree using the print_xyz() callbacks. */ void rb_print(struct rb_tree *tree) { assert(tree->print_key != NULL); assert(tree->print_value != NULL); rb_print_inorder(tree, tree->root->left); } /** * Find the first node matching the key in the tree. If multiple equal * keys are contained in the tree, the first one in-order is returned. * Returns NULL if the key was not found. */ struct rb_node *rb_find(struct rb_tree *tree, const void *key) { struct rb_node *x = tree->root->left; struct rb_node *nil = tree->nil; int cmpval; if (x == nil) return NULL; cmpval = tree->compare_keys(x->key, key); while (cmpval != 0) { if (cmpval > 0) { /* x->key > q */ x = x->left; } else { x = x->right; } if (x == nil) return NULL; cmpval = tree->compare_keys(x->key, key); } while (x->left != nil && tree->compare_keys(key, x->left->key) == 0) { x = x->left; } return x; } /** * Internal function to rebalance the tree after a node is deleted. */ static void rb_delete_fixup(struct rb_tree *tree, struct rb_node *x) { struct rb_node *root = tree->root->left; struct rb_node *w; while ( (!x->red) && (root != x) ) { if (x == x->parent->left) { w = x->parent->right; if (w->red) { w->red = 0; x->parent->red = 1; rb_rotate_left(tree, x->parent); w = x->parent->right; } if ( (!w->right->red) && (!w->left->red) ) { w->red = 1; x = x->parent; } else { if (!w->right->red) { w->left->red = 0; w->red = 1; rb_rotate_right(tree, w); w = x->parent->right; } w->red = x->parent->red; x->parent->red = 0; w->right->red = 0; rb_rotate_left(tree, x->parent); x = root; /* this is to exit while loop */ } } else /* the code below is has left and right switched from above */ { w = x->parent->left; if (w->red) { w->red = 0; x->parent->red = 1; rb_rotate_right(tree, x->parent); w = x->parent->left; } if ( (!w->right->red) && (!w->left->red) ) { w->red = 1; x = x->parent; } else { if (!w->left->red) { w->right->red = 0; w->red = 1; rb_rotate_left(tree, w); w = x->parent->left; } w->red = x->parent->red; x->parent->red = 0; w->left->red = 0; rb_rotate_right(tree, x->parent); x = root; /* this is to exit while loop */ } } } x->red = 0; assert(!tree->nil->red); /* nil not black in RBDeleteFixUp */ } /** * Delete a node from the tree and rebalance it. */ void rb_delete(struct rb_tree *tree, struct rb_node *z) { struct rb_node *x, *y, *nil = tree->nil; struct rb_node *root = tree->root; y = ((z->left == nil) || (z->right == nil)) ? z : rb_successor(tree, z); x = (y->left == nil) ? y->right : y->left; if (root == (x->parent = y->parent)) { /* assignment of y->p to x->p is intentional */ root->left = x; } else { if (y == y->parent->left) { y->parent->left = x; } else { y->parent->right = x; } } if (y != z) /* y should not be nil in this case */ { assert( (y!=tree->nil) ); /* y is nil in RBDelete */ /* y is the node to splice out and x is its child */ if (!(y->red)) rb_delete_fixup(tree, x); tree->destroy_key(z->key); tree->destroy_value(z->value); y->left = z->left; y->right = z->right; y->parent = z->parent; y->red = z->red; z->left->parent = z->right->parent = y; if (z == z->parent->left) { z->parent->left = y; } else { z->parent->right = y; } free(z); } else { tree->destroy_key(y->key); tree->destroy_value(y->value); if (!(y->red)) rb_delete_fixup(tree, x); free(y); } --tree->size; #ifdef RBTREE_VERIFY assert(rb_verify(tree)); #endif } /** * Verify red-black tree invariants: the root is black, both children * of a red node are black and every path from root to leaf has the * same number of black nodes. */ static int rb_verify_helper(struct rb_tree *tree, struct rb_node *z, int blacks, int *blackmatch, unsigned int *count) { if (z->red) { /* both children of a red node must be black */ if (z->left->red) return 0; if (z->right->red) return 0; } if (!z->red) ++blacks; if (++(*count) > tree->size) return 0; if (z->left != tree->nil) { if (!rb_verify_helper(tree, z->left, blacks, blackmatch, count)) return 0; } else { if (*blackmatch < 0) *blackmatch = blacks; else if (*blackmatch != blacks) return 0; } if (z->right != tree->nil) { if (!rb_verify_helper(tree, z->right, blacks, blackmatch, count)) return 0; } else { if (*blackmatch < 0) *blackmatch = blacks; else if (*blackmatch != blacks) return 0; } return 1; } /** * Verify red-black tree invariants: the root is black, both children * of a red node are black and every path from root to leaf has the * same number of black nodes. */ int rb_verify(struct rb_tree *tree) { int blackmatch = -1; unsigned int count = 0; /* nil must be black. */ if (tree->nil->red) return 0; /* the root must always be black */ if (tree->root->left->red) return 0; if (tree->root->left != tree->nil) { if (!rb_verify_helper(tree, tree->root->left, 0, &blackmatch, &count)) return 0; } if (count != tree->size) return 0; return 1; } /*****************************************************************************/ digup-digup-0.6.57/src/rbtree.h000066400000000000000000000116511370707046300162650ustar00rootroot00000000000000/***************************************************************************** * Red-Black Balanced Binary Tree Implementation in Plain C * * * * Copyright (C) 2001,2005 Emin Martinian * * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted provided that neither the name of Emin * * Martinian nor the names of any contributors are be used to endorse * * or promote products derived from this software without specific * * prior written permission. * * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * * Modifications 2009 by Timo Bingmann for duplicate key trees, opaque * * pointers, invariant testing and general code cleanup. * * * *****************************************************************************/ #ifndef _RBTREE_H #define _RBTREE_H 1 /** * Node structure of the red-black binary tree. */ struct rb_node { void *key, *value; int red; /* if red==0 then the node is black */ struct rb_node *left, *right, *parent; }; /** opaque structure declaration */ struct rb_tree; /** * Create a new red-black tree object. Function pointers to all * necessary callbacks must be provided. Returns a new tree object. * * - compare_keys(a,b) should return >0 if *a > *b, <0 if *a < *b, and * 0 otherwise. * - destroy_xyz(a) takes a pointer to either key or value object and * must free it accordingly. * - print_xyz(a) is used by rb_print() to dump the tree. */ struct rb_tree *rb_create(int (*compare_keys_func)(const void*, const void*), void (*destroy_key_func)(void*), void (*destroy_value_func)(void*), void (*print_key_func)(const void*), void (*print_value_func)(const void*)); /** * Returns true if the tree is empty. */ int rb_isempty(struct rb_tree *tree); /** * Returns the number of elements in the tree. */ unsigned int rb_size(struct rb_tree *tree); /** * Returns first node or nil in the tree. Similar to STL's begin(). */ struct rb_node *rb_begin(struct rb_tree *tree); /** * Returns the nil node in the tree. Similar to STL's end(). */ struct rb_node *rb_end(struct rb_tree *tree); /** * Insert function to place a new key, value pair into the tree, * taking ownership of key and value object.. First inserts a new node * and then applies iterative rotations to rebalance the tree. */ struct rb_node *rb_insert(struct rb_tree *tree, void *key, void *value); /** * Return the successor node of x in the tree or tree->nil if there is * none. */ struct rb_node *rb_successor(struct rb_tree *tree, struct rb_node *x); /** * Return the predecessor node of x in the tree or tree->nil if there * is none. */ struct rb_node *rb_predecessor(struct rb_tree *tree, struct rb_node *x); /** * Destroy the tree and destroy all associated key and value objects * via the appropriate callbacks. */ void rb_destroy(struct rb_tree *tree); /** * Print the whole tree using the print_xyz() callbacks. */ void rb_print(struct rb_tree *tree); /** * Find the first node matching the key in the tree. If multiple equal * keys are contained in the tree, the first one in-order is returned. * Returns NULL if the key was not found. */ struct rb_node *rb_find(struct rb_tree *tree, const void *key); /** * Delete a node from the tree and rebalance it. */ void rb_delete(struct rb_tree *tree, struct rb_node *z); /** * Verify red-black tree invariants: the root is black, both children * of a red node are black and every path from root to leaf has the * same number of black nodes. */ int rb_verify(struct rb_tree *tree); #endif /* _RBTREE_H */ /*****************************************************************************/ digup-digup-0.6.57/src/sha1.c000066400000000000000000000270651370707046300156370ustar00rootroot00000000000000/***************************************************************************** * Functions to compute SHA1 message digest. * * * * Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006, 2008 * * by Free Software Foundation, Inc. * * * * This file was taken from coreutils-7.4 and adapted for digup. * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * Written by Scott G. Miller * * Credits: Robert Klep -- Expansion function fix * *****************************************************************************/ #include "sha1.h" #include #include #if HAVE_ENDIAN_H #include #define WORDS_ARE_BIGENDIAN (__BYTE_ORDER == __BIG_ENDIAN) #elif HAVE_SYS_PARAM_H #include #define WORDS_ARE_BIGENDIAN (BYTE_ORDER == BIG_ENDIAN) #else #error "Cannot determine system endianness." #endif #if WORDS_ARE_BIGENDIAN # define SWAP(n) (n) #else # define SWAP(n) \ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) #endif #define BLOCKSIZE 4096 #if BLOCKSIZE % 64 != 0 # error "invalid BLOCKSIZE" #endif /* This array contains the bytes used to pad the buffer to the next 64-byte boundary. (RFC 1321, 3.1: Step 1) */ static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; /* Take a pointer to a 160 bit block of data (five 32 bit ints) and initialize it to the start constants of the SHA1 algorithm. This must be called before using hash in the call to sha1_hash. */ void sha1_init_ctx (struct sha1_ctx *ctx) { ctx->A = 0x67452301; ctx->B = 0xefcdab89; ctx->C = 0x98badcfe; ctx->D = 0x10325476; ctx->E = 0xc3d2e1f0; ctx->total[0] = ctx->total[1] = 0; ctx->buflen = 0; } /* Copy the 4 byte value from v into the memory location pointed to by *cp, If your architecture allows unaligned access this is equivalent to * (uint32_t *) cp = v */ static inline void set_uint32 (char *cp, uint32_t v) { memcpy (cp, &v, sizeof v); } /* Put result from CTX in first 20 bytes following RESBUF. The result must be in little endian byte order. */ void * sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf) { char *r = resbuf; set_uint32 (r + 0 * sizeof ctx->A, SWAP (ctx->A)); set_uint32 (r + 1 * sizeof ctx->B, SWAP (ctx->B)); set_uint32 (r + 2 * sizeof ctx->C, SWAP (ctx->C)); set_uint32 (r + 3 * sizeof ctx->D, SWAP (ctx->D)); set_uint32 (r + 4 * sizeof ctx->E, SWAP (ctx->E)); return resbuf; } /* Process the remaining bytes in the internal buffer and the usual prolog according to the standard and write the result to RESBUF. */ void * sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) { /* Take yet unprocessed bytes into account. */ uint32_t bytes = ctx->buflen; size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; /* Now count remaining bytes. */ ctx->total[0] += bytes; if (ctx->total[0] < bytes) ++ctx->total[1]; /* Put the 64-bit file length in *bits* at the end of the buffer. */ ctx->buffer[size - 2] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); ctx->buffer[size - 1] = SWAP (ctx->total[0] << 3); memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); /* Process last bytes. */ sha1_process_block (ctx->buffer, size * 4, ctx); return sha1_read_ctx (ctx, resbuf); } /* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ void * sha1_buffer (const char *buffer, size_t len, void *resblock) { struct sha1_ctx ctx; /* Initialize the computation context. */ sha1_init_ctx (&ctx); /* Process whole buffer but last len % 64 bytes. */ sha1_process_bytes (buffer, len, &ctx); /* Put result in desired memory area. */ return sha1_finish_ctx (&ctx, resblock); } void sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx) { /* When we already have some bits in our internal buffer concatenate both inputs first. */ if (ctx->buflen != 0) { size_t left_over = ctx->buflen; size_t add = 128 - left_over > len ? len : 128 - left_over; memcpy (&((char *) ctx->buffer)[left_over], buffer, add); ctx->buflen += add; if (ctx->buflen > 64) { sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx); ctx->buflen &= 63; /* The regions in the following copy operation cannot overlap. */ memcpy (ctx->buffer, &((char *) ctx->buffer)[(left_over + add) & ~63], ctx->buflen); } buffer = (const char *) buffer + add; len -= add; } /* Process available complete blocks. */ if (len >= 64) { #if !_STRING_ARCH_unaligned # define alignof(type) offsetof (struct { char c; type x; }, x) # define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) if (UNALIGNED_P (buffer)) while (len > 64) { sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); buffer = (const char *) buffer + 64; len -= 64; } else #endif { sha1_process_block (buffer, len & ~63, ctx); buffer = (const char *) buffer + (len & ~63); len &= 63; } } /* Move remaining bytes in internal buffer. */ if (len > 0) { size_t left_over = ctx->buflen; memcpy (&((char *) ctx->buffer)[left_over], buffer, len); left_over += len; if (left_over >= 64) { sha1_process_block (ctx->buffer, 64, ctx); left_over -= 64; memcpy (ctx->buffer, &ctx->buffer[16], left_over); } ctx->buflen = left_over; } } /* --- Code below is the primary difference between md5.c and sha1.c --- */ /* SHA1 round constants */ #define K1 0x5a827999 #define K2 0x6ed9eba1 #define K3 0x8f1bbcdc #define K4 0xca62c1d6 /* Round functions. Note that F2 is the same as F4. */ #define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) ) #define F2(B,C,D) (B ^ C ^ D) #define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) ) #define F4(B,C,D) (B ^ C ^ D) /* Process LEN bytes of BUFFER, accumulating context into CTX. It is assumed that LEN % 64 == 0. Most of this code comes from GnuPG's cipher/sha1.c. */ void sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx) { const uint32_t *words = buffer; size_t nwords = len / sizeof (uint32_t); const uint32_t *endp = words + nwords; uint32_t x[16]; uint32_t a = ctx->A; uint32_t b = ctx->B; uint32_t c = ctx->C; uint32_t d = ctx->D; uint32_t e = ctx->E; /* First increment the byte count. RFC 1321 specifies the possible length of the file up to 2^64 bits. Here we only compute the number of bytes. Do a double word increment. */ ctx->total[0] += len; if (ctx->total[0] < len) ++ctx->total[1]; #define rol(x, n) (((x) << (n)) | ((uint32_t) (x) >> (32 - (n)))) #define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \ ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \ , (x[I&0x0f] = rol(tm, 1)) ) #define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \ + F( B, C, D ) \ + K \ + M; \ B = rol( B, 30 ); \ } while(0) while (words < endp) { uint32_t tm; int t; for (t = 0; t < 16; t++) { x[t] = SWAP (*words); words++; } R( a, b, c, d, e, F1, K1, x[ 0] ); R( e, a, b, c, d, F1, K1, x[ 1] ); R( d, e, a, b, c, F1, K1, x[ 2] ); R( c, d, e, a, b, F1, K1, x[ 3] ); R( b, c, d, e, a, F1, K1, x[ 4] ); R( a, b, c, d, e, F1, K1, x[ 5] ); R( e, a, b, c, d, F1, K1, x[ 6] ); R( d, e, a, b, c, F1, K1, x[ 7] ); R( c, d, e, a, b, F1, K1, x[ 8] ); R( b, c, d, e, a, F1, K1, x[ 9] ); R( a, b, c, d, e, F1, K1, x[10] ); R( e, a, b, c, d, F1, K1, x[11] ); R( d, e, a, b, c, F1, K1, x[12] ); R( c, d, e, a, b, F1, K1, x[13] ); R( b, c, d, e, a, F1, K1, x[14] ); R( a, b, c, d, e, F1, K1, x[15] ); R( e, a, b, c, d, F1, K1, M(16) ); R( d, e, a, b, c, F1, K1, M(17) ); R( c, d, e, a, b, F1, K1, M(18) ); R( b, c, d, e, a, F1, K1, M(19) ); R( a, b, c, d, e, F2, K2, M(20) ); R( e, a, b, c, d, F2, K2, M(21) ); R( d, e, a, b, c, F2, K2, M(22) ); R( c, d, e, a, b, F2, K2, M(23) ); R( b, c, d, e, a, F2, K2, M(24) ); R( a, b, c, d, e, F2, K2, M(25) ); R( e, a, b, c, d, F2, K2, M(26) ); R( d, e, a, b, c, F2, K2, M(27) ); R( c, d, e, a, b, F2, K2, M(28) ); R( b, c, d, e, a, F2, K2, M(29) ); R( a, b, c, d, e, F2, K2, M(30) ); R( e, a, b, c, d, F2, K2, M(31) ); R( d, e, a, b, c, F2, K2, M(32) ); R( c, d, e, a, b, F2, K2, M(33) ); R( b, c, d, e, a, F2, K2, M(34) ); R( a, b, c, d, e, F2, K2, M(35) ); R( e, a, b, c, d, F2, K2, M(36) ); R( d, e, a, b, c, F2, K2, M(37) ); R( c, d, e, a, b, F2, K2, M(38) ); R( b, c, d, e, a, F2, K2, M(39) ); R( a, b, c, d, e, F3, K3, M(40) ); R( e, a, b, c, d, F3, K3, M(41) ); R( d, e, a, b, c, F3, K3, M(42) ); R( c, d, e, a, b, F3, K3, M(43) ); R( b, c, d, e, a, F3, K3, M(44) ); R( a, b, c, d, e, F3, K3, M(45) ); R( e, a, b, c, d, F3, K3, M(46) ); R( d, e, a, b, c, F3, K3, M(47) ); R( c, d, e, a, b, F3, K3, M(48) ); R( b, c, d, e, a, F3, K3, M(49) ); R( a, b, c, d, e, F3, K3, M(50) ); R( e, a, b, c, d, F3, K3, M(51) ); R( d, e, a, b, c, F3, K3, M(52) ); R( c, d, e, a, b, F3, K3, M(53) ); R( b, c, d, e, a, F3, K3, M(54) ); R( a, b, c, d, e, F3, K3, M(55) ); R( e, a, b, c, d, F3, K3, M(56) ); R( d, e, a, b, c, F3, K3, M(57) ); R( c, d, e, a, b, F3, K3, M(58) ); R( b, c, d, e, a, F3, K3, M(59) ); R( a, b, c, d, e, F4, K4, M(60) ); R( e, a, b, c, d, F4, K4, M(61) ); R( d, e, a, b, c, F4, K4, M(62) ); R( c, d, e, a, b, F4, K4, M(63) ); R( b, c, d, e, a, F4, K4, M(64) ); R( a, b, c, d, e, F4, K4, M(65) ); R( e, a, b, c, d, F4, K4, M(66) ); R( d, e, a, b, c, F4, K4, M(67) ); R( c, d, e, a, b, F4, K4, M(68) ); R( b, c, d, e, a, F4, K4, M(69) ); R( a, b, c, d, e, F4, K4, M(70) ); R( e, a, b, c, d, F4, K4, M(71) ); R( d, e, a, b, c, F4, K4, M(72) ); R( c, d, e, a, b, F4, K4, M(73) ); R( b, c, d, e, a, F4, K4, M(74) ); R( a, b, c, d, e, F4, K4, M(75) ); R( e, a, b, c, d, F4, K4, M(76) ); R( d, e, a, b, c, F4, K4, M(77) ); R( c, d, e, a, b, F4, K4, M(78) ); R( b, c, d, e, a, F4, K4, M(79) ); a = ctx->A += a; b = ctx->B += b; c = ctx->C += c; d = ctx->D += d; e = ctx->E += e; } } /*****************************************************************************/ digup-digup-0.6.57/src/sha1.h000066400000000000000000000073071370707046300156410ustar00rootroot00000000000000/***************************************************************************** * Declaration of functions and data types used for SHA1 sum computing. * * * * Copyright (C) 2000, 2001, 2003, 2005, 2006, 2008 * * by Free Software Foundation, Inc. * * * * This file was taken from coreutils-7.4 and adapted for digup. * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ #ifndef _SHA1_H #define _SHA1_H 1 #include #include enum { SHA1_DIGEST_SIZE = 20 }; /* Structure to save state of computation between the single steps. */ struct sha1_ctx { uint32_t A, B, C, D, E; uint32_t total[2]; uint32_t buflen; uint32_t buffer[32]; }; /* Initialize structure containing state of computation. */ extern void sha1_init_ctx (struct sha1_ctx *ctx); /* Starting with the result of former calls of this function (or the initialization function update the context for the next LEN bytes starting at BUFFER. It is necessary that LEN is a multiple of 64!!! */ extern void sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx); /* Starting with the result of former calls of this function (or the initialization function update the context for the next LEN bytes starting at BUFFER. It is NOT required that LEN is a multiple of 64. */ extern void sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx); /* Process the remaining bytes in the buffer and put result from CTX in first 20 bytes following RESBUF. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf); /* Put result from CTX in first 20 bytes following RESBUF. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf); /* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ extern void *sha1_buffer (const char *buffer, size_t len, void *resblock); #endif /* _SHA1_H */ /*****************************************************************************/ digup-digup-0.6.57/src/sha256.c000066400000000000000000000345121370707046300160060ustar00rootroot00000000000000/***************************************************************************** * Functions to compute SHA256 and SHA224 message digests according to * * the NIST specification FIPS-180-2. * * * * Copyright (C) 2005, 2006, 2008 * * by Free Software Foundation, Inc. * * * * This file was taken from coreutils-7.4 and adapted for digup. * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * Written by David Madore, considerably copypasting from * * Scott G. Miller's sha1.c * *****************************************************************************/ #include "sha256.h" #include #include #if HAVE_ENDIAN_H #include #define WORDS_ARE_BIGENDIAN (__BYTE_ORDER == __BIG_ENDIAN) #elif HAVE_SYS_PARAM_H #include #define WORDS_ARE_BIGENDIAN (BYTE_ORDER == BIG_ENDIAN) #else #error "Cannot determine system endianness." #endif #if WORDS_ARE_BIGENDIAN # define SWAP(n) (n) #else # define SWAP(n) \ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) #endif #define BLOCKSIZE 4096 #if BLOCKSIZE % 64 != 0 # error "invalid BLOCKSIZE" #endif /* This array contains the bytes used to pad the buffer to the next 64-byte boundary. */ static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; /* Takes a pointer to a 256 bit block of data (eight 32 bit ints) and initializes it to the start constants of the SHA256 algorithm. This must be called before using hash in the call to sha256_hash */ void sha256_init_ctx (struct sha256_ctx *ctx) { ctx->state[0] = 0x6a09e667UL; ctx->state[1] = 0xbb67ae85UL; ctx->state[2] = 0x3c6ef372UL; ctx->state[3] = 0xa54ff53aUL; ctx->state[4] = 0x510e527fUL; ctx->state[5] = 0x9b05688cUL; ctx->state[6] = 0x1f83d9abUL; ctx->state[7] = 0x5be0cd19UL; ctx->total[0] = ctx->total[1] = 0; ctx->buflen = 0; } void sha224_init_ctx (struct sha256_ctx *ctx) { ctx->state[0] = 0xc1059ed8UL; ctx->state[1] = 0x367cd507UL; ctx->state[2] = 0x3070dd17UL; ctx->state[3] = 0xf70e5939UL; ctx->state[4] = 0xffc00b31UL; ctx->state[5] = 0x68581511UL; ctx->state[6] = 0x64f98fa7UL; ctx->state[7] = 0xbefa4fa4UL; ctx->total[0] = ctx->total[1] = 0; ctx->buflen = 0; } /* Copy the value from v into the memory location pointed to by *cp, If your architecture allows unaligned access this is equivalent to * (uint32_t *) cp = v */ static inline void set_uint32 (char *cp, uint32_t v) { memcpy (cp, &v, sizeof v); } /* Put result from CTX in first 32 bytes following RESBUF. The result must be in little endian byte order. */ void * sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf) { int i; char *r = resbuf; for (i = 0; i < 8; i++) set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); return resbuf; } void * sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf) { int i; char *r = resbuf; for (i = 0; i < 7; i++) set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); return resbuf; } /* Process the remaining bytes in the internal buffer and the usual prolog according to the standard and write the result to RESBUF. */ static void sha256_conclude_ctx (struct sha256_ctx *ctx) { /* Take yet unprocessed bytes into account. */ size_t bytes = ctx->buflen; size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; /* Now count remaining bytes. */ ctx->total[0] += bytes; if (ctx->total[0] < bytes) ++ctx->total[1]; /* Put the 64-bit file length in *bits* at the end of the buffer. Use set_uint32 rather than a simple assignment, to avoid risk of unaligned access. */ set_uint32 ((char *) &ctx->buffer[size - 2], SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29))); set_uint32 ((char *) &ctx->buffer[size - 1], SWAP (ctx->total[0] << 3)); memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); /* Process last bytes. */ sha256_process_block (ctx->buffer, size * 4, ctx); } void * sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf) { sha256_conclude_ctx (ctx); return sha256_read_ctx (ctx, resbuf); } void * sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf) { sha256_conclude_ctx (ctx); return sha224_read_ctx (ctx, resbuf); } /* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ void * sha256_buffer (const char *buffer, size_t len, void *resblock) { struct sha256_ctx ctx; /* Initialize the computation context. */ sha256_init_ctx (&ctx); /* Process whole buffer but last len % 64 bytes. */ sha256_process_bytes (buffer, len, &ctx); /* Put result in desired memory area. */ return sha256_finish_ctx (&ctx, resblock); } void * sha224_buffer (const char *buffer, size_t len, void *resblock) { struct sha256_ctx ctx; /* Initialize the computation context. */ sha224_init_ctx (&ctx); /* Process whole buffer but last len % 64 bytes. */ sha256_process_bytes (buffer, len, &ctx); /* Put result in desired memory area. */ return sha224_finish_ctx (&ctx, resblock); } void sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx) { /* When we already have some bits in our internal buffer concatenate both inputs first. */ if (ctx->buflen != 0) { size_t left_over = ctx->buflen; size_t add = 128 - left_over > len ? len : 128 - left_over; memcpy (&((char *) ctx->buffer)[left_over], buffer, add); ctx->buflen += add; if (ctx->buflen > 64) { sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx); ctx->buflen &= 63; /* The regions in the following copy operation cannot overlap. */ memcpy (ctx->buffer, &((char *) ctx->buffer)[(left_over + add) & ~63], ctx->buflen); } buffer = (const char *) buffer + add; len -= add; } /* Process available complete blocks. */ if (len >= 64) { #if !_STRING_ARCH_unaligned # define alignof(type) offsetof (struct { char c; type x; }, x) # define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) if (UNALIGNED_P (buffer)) while (len > 64) { sha256_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); buffer = (const char *) buffer + 64; len -= 64; } else #endif { sha256_process_block (buffer, len & ~63, ctx); buffer = (const char *) buffer + (len & ~63); len &= 63; } } /* Move remaining bytes in internal buffer. */ if (len > 0) { size_t left_over = ctx->buflen; memcpy (&((char *) ctx->buffer)[left_over], buffer, len); left_over += len; if (left_over >= 64) { sha256_process_block (ctx->buffer, 64, ctx); left_over -= 64; memcpy (ctx->buffer, &ctx->buffer[16], left_over); } ctx->buflen = left_over; } } /* --- Code below is the primary difference between sha1.c and sha256.c --- */ /* SHA256 round constants */ #define K(I) sha256_round_constants[I] static const uint32_t sha256_round_constants[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, }; /* Round functions. */ #define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) ) #define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) ) /* Process LEN bytes of BUFFER, accumulating context into CTX. It is assumed that LEN % 64 == 0. Most of this code comes from GnuPG's cipher/sha1.c. */ void sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx) { const uint32_t *words = buffer; size_t nwords = len / sizeof (uint32_t); const uint32_t *endp = words + nwords; uint32_t x[16]; uint32_t a = ctx->state[0]; uint32_t b = ctx->state[1]; uint32_t c = ctx->state[2]; uint32_t d = ctx->state[3]; uint32_t e = ctx->state[4]; uint32_t f = ctx->state[5]; uint32_t g = ctx->state[6]; uint32_t h = ctx->state[7]; /* First increment the byte count. FIPS PUB 180-2 specifies the possible length of the file up to 2^64 bits. Here we only compute the number of bytes. Do a double word increment. */ ctx->total[0] += len; if (ctx->total[0] < len) ++ctx->total[1]; #define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) #define S0(x) (rol(x,25)^rol(x,14)^(x>>3)) #define S1(x) (rol(x,15)^rol(x,13)^(x>>10)) #define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10)) #define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7)) #define M(I) ( tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] \ + S0(x[(I-15)&0x0f]) + x[I&0x0f] \ , x[I&0x0f] = tm ) #define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \ t1 = H + SS1(E) \ + F1(E,F,G) \ + K \ + M; \ D += t1; H = t0 + t1; \ } while(0) while (words < endp) { uint32_t tm; uint32_t t0, t1; int t; /* FIXME: see sha1.c for a better implementation. */ for (t = 0; t < 16; t++) { x[t] = SWAP (*words); words++; } R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); R( g, h, a, b, c, d, e, f, K(10), x[10] ); R( f, g, h, a, b, c, d, e, K(11), x[11] ); R( e, f, g, h, a, b, c, d, K(12), x[12] ); R( d, e, f, g, h, a, b, c, K(13), x[13] ); R( c, d, e, f, g, h, a, b, K(14), x[14] ); R( b, c, d, e, f, g, h, a, K(15), x[15] ); R( a, b, c, d, e, f, g, h, K(16), M(16) ); R( h, a, b, c, d, e, f, g, K(17), M(17) ); R( g, h, a, b, c, d, e, f, K(18), M(18) ); R( f, g, h, a, b, c, d, e, K(19), M(19) ); R( e, f, g, h, a, b, c, d, K(20), M(20) ); R( d, e, f, g, h, a, b, c, K(21), M(21) ); R( c, d, e, f, g, h, a, b, K(22), M(22) ); R( b, c, d, e, f, g, h, a, K(23), M(23) ); R( a, b, c, d, e, f, g, h, K(24), M(24) ); R( h, a, b, c, d, e, f, g, K(25), M(25) ); R( g, h, a, b, c, d, e, f, K(26), M(26) ); R( f, g, h, a, b, c, d, e, K(27), M(27) ); R( e, f, g, h, a, b, c, d, K(28), M(28) ); R( d, e, f, g, h, a, b, c, K(29), M(29) ); R( c, d, e, f, g, h, a, b, K(30), M(30) ); R( b, c, d, e, f, g, h, a, K(31), M(31) ); R( a, b, c, d, e, f, g, h, K(32), M(32) ); R( h, a, b, c, d, e, f, g, K(33), M(33) ); R( g, h, a, b, c, d, e, f, K(34), M(34) ); R( f, g, h, a, b, c, d, e, K(35), M(35) ); R( e, f, g, h, a, b, c, d, K(36), M(36) ); R( d, e, f, g, h, a, b, c, K(37), M(37) ); R( c, d, e, f, g, h, a, b, K(38), M(38) ); R( b, c, d, e, f, g, h, a, K(39), M(39) ); R( a, b, c, d, e, f, g, h, K(40), M(40) ); R( h, a, b, c, d, e, f, g, K(41), M(41) ); R( g, h, a, b, c, d, e, f, K(42), M(42) ); R( f, g, h, a, b, c, d, e, K(43), M(43) ); R( e, f, g, h, a, b, c, d, K(44), M(44) ); R( d, e, f, g, h, a, b, c, K(45), M(45) ); R( c, d, e, f, g, h, a, b, K(46), M(46) ); R( b, c, d, e, f, g, h, a, K(47), M(47) ); R( a, b, c, d, e, f, g, h, K(48), M(48) ); R( h, a, b, c, d, e, f, g, K(49), M(49) ); R( g, h, a, b, c, d, e, f, K(50), M(50) ); R( f, g, h, a, b, c, d, e, K(51), M(51) ); R( e, f, g, h, a, b, c, d, K(52), M(52) ); R( d, e, f, g, h, a, b, c, K(53), M(53) ); R( c, d, e, f, g, h, a, b, K(54), M(54) ); R( b, c, d, e, f, g, h, a, K(55), M(55) ); R( a, b, c, d, e, f, g, h, K(56), M(56) ); R( h, a, b, c, d, e, f, g, K(57), M(57) ); R( g, h, a, b, c, d, e, f, K(58), M(58) ); R( f, g, h, a, b, c, d, e, K(59), M(59) ); R( e, f, g, h, a, b, c, d, K(60), M(60) ); R( d, e, f, g, h, a, b, c, K(61), M(61) ); R( c, d, e, f, g, h, a, b, K(62), M(62) ); R( b, c, d, e, f, g, h, a, K(63), M(63) ); a = ctx->state[0] += a; b = ctx->state[1] += b; c = ctx->state[2] += c; d = ctx->state[3] += d; e = ctx->state[4] += e; f = ctx->state[5] += f; g = ctx->state[6] += g; h = ctx->state[7] += h; } } /*****************************************************************************/ digup-digup-0.6.57/src/sha256.h000066400000000000000000000102111370707046300160010ustar00rootroot00000000000000/***************************************************************************** * Declaration of functions and data types used for SHA256 and SHA224 * * sum computing. * * * * Copyright (C) 2005, 2006, 2008 * * by Free Software Foundation, Inc. * * * * This file was taken from coreutils-7.4 and adapted for digup. * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ #ifndef _SHA256_H #define _SHA256_H 1 #include #include enum { SHA224_DIGEST_SIZE = 224 / 8 }; enum { SHA256_DIGEST_SIZE = 256 / 8 }; /* Structure to save state of computation between the single steps. */ struct sha256_ctx { uint32_t state[8]; uint32_t total[2]; size_t buflen; uint32_t buffer[32]; }; /* Initialize structure containing state of computation. */ extern void sha256_init_ctx (struct sha256_ctx *ctx); extern void sha224_init_ctx (struct sha256_ctx *ctx); /* Starting with the result of former calls of this function (or the initialization function update the context for the next LEN bytes starting at BUFFER. It is necessary that LEN is a multiple of 64!!! */ extern void sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx); /* Starting with the result of former calls of this function (or the initialization function update the context for the next LEN bytes starting at BUFFER. It is NOT required that LEN is a multiple of 64. */ extern void sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx); /* Process the remaining bytes in the buffer and put result from CTX in first 32 (28) bytes following RESBUF. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ extern void *sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf); extern void *sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf); /* Put result from CTX in first 32 (28) bytes following RESBUF. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ extern void *sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf); extern void *sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf); /* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ extern void *sha256_buffer (const char *buffer, size_t len, void *resblock); extern void *sha224_buffer (const char *buffer, size_t len, void *resblock); #endif /* _SHA256_H */ /*****************************************************************************/ digup-digup-0.6.57/src/sha512.c000066400000000000000000000450201370707046300157750ustar00rootroot00000000000000/***************************************************************************** * Functions to compute SHA512 and SHA384 message digests according to * * the NIST specification FIPS-180-2. * * * * Copyright (C) 2005, 2006, 2008 * * by Free Software Foundation, Inc. * * * * This file was taken from coreutils-7.4 and adapted for digup. * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * Written by David Madore, considerably copypasting from * * Scott G. Miller's sha1.c * *****************************************************************************/ #include "sha512.h" #include #include /* u64 type functions imported from u64.h */ typedef uint64_t u64; #define u64hilo(hi, lo) ((u64) (((u64) (hi) << 32) + (lo))) #define u64init(hi, lo) u64hilo (hi, lo) #define u64lo(x) ((u64) (x)) #define u64lt(x, y) ((x) < (y)) #define u64and(x, y) ((x) & (y)) #define u64or(x, y) ((x) | (y)) #define u64xor(x, y) ((x) ^ (y)) #define u64plus(x, y) ((x) + (y)) #define u64shl(x, n) ((x) << (n)) #define u64shr(x, n) ((x) >> (n)) #define u64rol(x, n) u64or (u64shl (x, n), u64shr (x, 64 - n)) #if HAVE_ENDIAN_H #include #define WORDS_ARE_BIGENDIAN (__BYTE_ORDER == __BIG_ENDIAN) #elif HAVE_SYS_PARAM_H #include #define WORDS_ARE_BIGENDIAN (BYTE_ORDER == BIG_ENDIAN) #else #error "Cannot determine system endianness." #endif #if WORDS_ARE_BIGENDIAN # define SWAP(n) (n) #else # define SWAP(n) \ u64or (u64or (u64or (u64shl (n, 56), \ u64shl (u64and (n, u64lo (0x0000ff00)), 40)), \ u64or (u64shl (u64and (n, u64lo (0x00ff0000)), 24), \ u64shl (u64and (n, u64lo (0xff000000)), 8))), \ u64or (u64or (u64and (u64shr (n, 8), u64lo (0xff000000)), \ u64and (u64shr (n, 24), u64lo (0x00ff0000))), \ u64or (u64and (u64shr (n, 40), u64lo (0x0000ff00)), \ u64shr (n, 56)))) #endif #define BLOCKSIZE 4096 #if BLOCKSIZE % 128 != 0 # error "invalid BLOCKSIZE" #endif /* This array contains the bytes used to pad the buffer to the next 128-byte boundary. */ static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ... */ }; /* Takes a pointer to a 512 bit block of data (eight 64 bit ints) and initializes it to the start constants of the SHA512 algorithm. This must be called before using hash in the call to sha512_hash */ void sha512_init_ctx (struct sha512_ctx *ctx) { ctx->state[0] = u64hilo (0x6a09e667, 0xf3bcc908); ctx->state[1] = u64hilo (0xbb67ae85, 0x84caa73b); ctx->state[2] = u64hilo (0x3c6ef372, 0xfe94f82b); ctx->state[3] = u64hilo (0xa54ff53a, 0x5f1d36f1); ctx->state[4] = u64hilo (0x510e527f, 0xade682d1); ctx->state[5] = u64hilo (0x9b05688c, 0x2b3e6c1f); ctx->state[6] = u64hilo (0x1f83d9ab, 0xfb41bd6b); ctx->state[7] = u64hilo (0x5be0cd19, 0x137e2179); ctx->total[0] = ctx->total[1] = u64lo (0); ctx->buflen = 0; } void sha384_init_ctx (struct sha512_ctx *ctx) { ctx->state[0] = u64hilo (0xcbbb9d5d, 0xc1059ed8); ctx->state[1] = u64hilo (0x629a292a, 0x367cd507); ctx->state[2] = u64hilo (0x9159015a, 0x3070dd17); ctx->state[3] = u64hilo (0x152fecd8, 0xf70e5939); ctx->state[4] = u64hilo (0x67332667, 0xffc00b31); ctx->state[5] = u64hilo (0x8eb44a87, 0x68581511); ctx->state[6] = u64hilo (0xdb0c2e0d, 0x64f98fa7); ctx->state[7] = u64hilo (0x47b5481d, 0xbefa4fa4); ctx->total[0] = ctx->total[1] = u64lo (0); ctx->buflen = 0; } /* Copy the value from V into the memory location pointed to by *CP, If your architecture allows unaligned access, this is equivalent to * (__typeof__ (v) *) cp = v */ static inline void set_uint64 (char *cp, u64 v) { memcpy (cp, &v, sizeof v); } /* Put result from CTX in first 64 bytes following RESBUF. The result must be in little endian byte order. */ void * sha512_read_ctx (const struct sha512_ctx *ctx, void *resbuf) { int i; char *r = resbuf; for (i = 0; i < 8; i++) set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); return resbuf; } void * sha384_read_ctx (const struct sha512_ctx *ctx, void *resbuf) { int i; char *r = resbuf; for (i = 0; i < 6; i++) set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); return resbuf; } /* Process the remaining bytes in the internal buffer and the usual prolog according to the standard and write the result to RESBUF. */ static void sha512_conclude_ctx (struct sha512_ctx *ctx) { /* Take yet unprocessed bytes into account. */ size_t bytes = ctx->buflen; size_t size = (bytes < 112) ? 128 / 8 : 128 * 2 / 8; /* Now count remaining bytes. */ ctx->total[0] = u64plus (ctx->total[0], u64lo (bytes)); if (u64lt (ctx->total[0], u64lo (bytes))) ctx->total[1] = u64plus (ctx->total[1], u64lo (1)); /* Put the 128-bit file length in *bits* at the end of the buffer. Use set_uint64 rather than a simple assignment, to avoid risk of unaligned access. */ set_uint64 ((char *) &ctx->buffer[size - 2], SWAP (u64or (u64shl (ctx->total[1], 3), u64shr (ctx->total[0], 61)))); set_uint64 ((char *) &ctx->buffer[size - 1], SWAP (u64shl (ctx->total[0], 3))); memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 8 - bytes); /* Process last bytes. */ sha512_process_block (ctx->buffer, size * 8, ctx); } void * sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf) { sha512_conclude_ctx (ctx); return sha512_read_ctx (ctx, resbuf); } void * sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf) { sha512_conclude_ctx (ctx); return sha384_read_ctx (ctx, resbuf); } /* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ void * sha512_buffer (const char *buffer, size_t len, void *resblock) { struct sha512_ctx ctx; /* Initialize the computation context. */ sha512_init_ctx (&ctx); /* Process whole buffer but last len % 128 bytes. */ sha512_process_bytes (buffer, len, &ctx); /* Put result in desired memory area. */ return sha512_finish_ctx (&ctx, resblock); } void * sha384_buffer (const char *buffer, size_t len, void *resblock) { struct sha512_ctx ctx; /* Initialize the computation context. */ sha384_init_ctx (&ctx); /* Process whole buffer but last len % 128 bytes. */ sha512_process_bytes (buffer, len, &ctx); /* Put result in desired memory area. */ return sha384_finish_ctx (&ctx, resblock); } void sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx) { /* When we already have some bits in our internal buffer concatenate both inputs first. */ if (ctx->buflen != 0) { size_t left_over = ctx->buflen; size_t add = 256 - left_over > len ? len : 256 - left_over; memcpy (&((char *) ctx->buffer)[left_over], buffer, add); ctx->buflen += add; if (ctx->buflen > 128) { sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx); ctx->buflen &= 127; /* The regions in the following copy operation cannot overlap. */ memcpy (ctx->buffer, &((char *) ctx->buffer)[(left_over + add) & ~127], ctx->buflen); } buffer = (const char *) buffer + add; len -= add; } /* Process available complete blocks. */ if (len >= 128) { #if !_STRING_ARCH_unaligned # define alignof(type) offsetof (struct { char c; type x; }, x) # define UNALIGNED_P(p) (((size_t) p) % alignof (u64) != 0) if (UNALIGNED_P (buffer)) while (len > 128) { sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128, ctx); buffer = (const char *) buffer + 128; len -= 128; } else #endif { sha512_process_block (buffer, len & ~127, ctx); buffer = (const char *) buffer + (len & ~127); len &= 127; } } /* Move remaining bytes in internal buffer. */ if (len > 0) { size_t left_over = ctx->buflen; memcpy (&((char *) ctx->buffer)[left_over], buffer, len); left_over += len; if (left_over >= 128) { sha512_process_block (ctx->buffer, 128, ctx); left_over -= 128; memcpy (ctx->buffer, &ctx->buffer[16], left_over); } ctx->buflen = left_over; } } /* --- Code below is the primary difference between sha1.c and sha512.c --- */ /* SHA512 round constants */ #define K(I) sha512_round_constants[I] static u64 const sha512_round_constants[80] = { u64init (0x428a2f98, 0xd728ae22), u64init (0x71374491, 0x23ef65cd), u64init (0xb5c0fbcf, 0xec4d3b2f), u64init (0xe9b5dba5, 0x8189dbbc), u64init (0x3956c25b, 0xf348b538), u64init (0x59f111f1, 0xb605d019), u64init (0x923f82a4, 0xaf194f9b), u64init (0xab1c5ed5, 0xda6d8118), u64init (0xd807aa98, 0xa3030242), u64init (0x12835b01, 0x45706fbe), u64init (0x243185be, 0x4ee4b28c), u64init (0x550c7dc3, 0xd5ffb4e2), u64init (0x72be5d74, 0xf27b896f), u64init (0x80deb1fe, 0x3b1696b1), u64init (0x9bdc06a7, 0x25c71235), u64init (0xc19bf174, 0xcf692694), u64init (0xe49b69c1, 0x9ef14ad2), u64init (0xefbe4786, 0x384f25e3), u64init (0x0fc19dc6, 0x8b8cd5b5), u64init (0x240ca1cc, 0x77ac9c65), u64init (0x2de92c6f, 0x592b0275), u64init (0x4a7484aa, 0x6ea6e483), u64init (0x5cb0a9dc, 0xbd41fbd4), u64init (0x76f988da, 0x831153b5), u64init (0x983e5152, 0xee66dfab), u64init (0xa831c66d, 0x2db43210), u64init (0xb00327c8, 0x98fb213f), u64init (0xbf597fc7, 0xbeef0ee4), u64init (0xc6e00bf3, 0x3da88fc2), u64init (0xd5a79147, 0x930aa725), u64init (0x06ca6351, 0xe003826f), u64init (0x14292967, 0x0a0e6e70), u64init (0x27b70a85, 0x46d22ffc), u64init (0x2e1b2138, 0x5c26c926), u64init (0x4d2c6dfc, 0x5ac42aed), u64init (0x53380d13, 0x9d95b3df), u64init (0x650a7354, 0x8baf63de), u64init (0x766a0abb, 0x3c77b2a8), u64init (0x81c2c92e, 0x47edaee6), u64init (0x92722c85, 0x1482353b), u64init (0xa2bfe8a1, 0x4cf10364), u64init (0xa81a664b, 0xbc423001), u64init (0xc24b8b70, 0xd0f89791), u64init (0xc76c51a3, 0x0654be30), u64init (0xd192e819, 0xd6ef5218), u64init (0xd6990624, 0x5565a910), u64init (0xf40e3585, 0x5771202a), u64init (0x106aa070, 0x32bbd1b8), u64init (0x19a4c116, 0xb8d2d0c8), u64init (0x1e376c08, 0x5141ab53), u64init (0x2748774c, 0xdf8eeb99), u64init (0x34b0bcb5, 0xe19b48a8), u64init (0x391c0cb3, 0xc5c95a63), u64init (0x4ed8aa4a, 0xe3418acb), u64init (0x5b9cca4f, 0x7763e373), u64init (0x682e6ff3, 0xd6b2b8a3), u64init (0x748f82ee, 0x5defb2fc), u64init (0x78a5636f, 0x43172f60), u64init (0x84c87814, 0xa1f0ab72), u64init (0x8cc70208, 0x1a6439ec), u64init (0x90befffa, 0x23631e28), u64init (0xa4506ceb, 0xde82bde9), u64init (0xbef9a3f7, 0xb2c67915), u64init (0xc67178f2, 0xe372532b), u64init (0xca273ece, 0xea26619c), u64init (0xd186b8c7, 0x21c0c207), u64init (0xeada7dd6, 0xcde0eb1e), u64init (0xf57d4f7f, 0xee6ed178), u64init (0x06f067aa, 0x72176fba), u64init (0x0a637dc5, 0xa2c898a6), u64init (0x113f9804, 0xbef90dae), u64init (0x1b710b35, 0x131c471b), u64init (0x28db77f5, 0x23047d84), u64init (0x32caab7b, 0x40c72493), u64init (0x3c9ebe0a, 0x15c9bebc), u64init (0x431d67c4, 0x9c100d4c), u64init (0x4cc5d4be, 0xcb3e42b6), u64init (0x597f299c, 0xfc657e2a), u64init (0x5fcb6fab, 0x3ad6faec), u64init (0x6c44198c, 0x4a475817), }; /* Round functions. */ #define F2(A, B, C) u64or (u64and (A, B), u64and (C, u64or (A, B))) #define F1(E, F, G) u64xor (G, u64and (E, u64xor (F, G))) /* Process LEN bytes of BUFFER, accumulating context into CTX. It is assumed that LEN % 128 == 0. Most of this code comes from GnuPG's cipher/sha1.c. */ void sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx) { u64 const *words = buffer; u64 const *endp = words + len / sizeof (u64); u64 x[16]; u64 a = ctx->state[0]; u64 b = ctx->state[1]; u64 c = ctx->state[2]; u64 d = ctx->state[3]; u64 e = ctx->state[4]; u64 f = ctx->state[5]; u64 g = ctx->state[6]; u64 h = ctx->state[7]; /* First increment the byte count. FIPS PUB 180-2 specifies the possible length of the file up to 2^128 bits. Here we only compute the number of bytes. Do a double word increment. */ ctx->total[0] = u64plus (ctx->total[0], u64lo (len)); if (u64lt (ctx->total[0], u64lo (len))) ctx->total[1] = u64plus (ctx->total[1], u64lo (1)); #define S0(x) u64xor (u64rol(x, 63), u64xor (u64rol (x, 56), u64shr (x, 7))) #define S1(x) u64xor (u64rol (x, 45), u64xor (u64rol (x, 3), u64shr (x, 6))) #define SS0(x) u64xor (u64rol (x, 36), u64xor (u64rol (x, 30), u64rol (x, 25))) #define SS1(x) u64xor (u64rol(x, 50), u64xor (u64rol (x, 46), u64rol (x, 23))) #define M(I) (x[(I) & 15] \ = u64plus (x[(I) & 15], \ u64plus (S1 (x[((I) - 2) & 15]), \ u64plus (x[((I) - 7) & 15], \ S0 (x[((I) - 15) & 15]))))) #define R(A, B, C, D, E, F, G, H, K, M) \ do \ { \ u64 t0 = u64plus (SS0 (A), F2 (A, B, C)); \ u64 t1 = \ u64plus (H, u64plus (SS1 (E), \ u64plus (F1 (E, F, G), u64plus (K, M)))); \ D = u64plus (D, t1); \ H = u64plus (t0, t1); \ } \ while (0) while (words < endp) { int t; /* FIXME: see sha1.c for a better implementation. */ for (t = 0; t < 16; t++) { x[t] = SWAP (*words); words++; } R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); R( g, h, a, b, c, d, e, f, K(10), x[10] ); R( f, g, h, a, b, c, d, e, K(11), x[11] ); R( e, f, g, h, a, b, c, d, K(12), x[12] ); R( d, e, f, g, h, a, b, c, K(13), x[13] ); R( c, d, e, f, g, h, a, b, K(14), x[14] ); R( b, c, d, e, f, g, h, a, K(15), x[15] ); R( a, b, c, d, e, f, g, h, K(16), M(16) ); R( h, a, b, c, d, e, f, g, K(17), M(17) ); R( g, h, a, b, c, d, e, f, K(18), M(18) ); R( f, g, h, a, b, c, d, e, K(19), M(19) ); R( e, f, g, h, a, b, c, d, K(20), M(20) ); R( d, e, f, g, h, a, b, c, K(21), M(21) ); R( c, d, e, f, g, h, a, b, K(22), M(22) ); R( b, c, d, e, f, g, h, a, K(23), M(23) ); R( a, b, c, d, e, f, g, h, K(24), M(24) ); R( h, a, b, c, d, e, f, g, K(25), M(25) ); R( g, h, a, b, c, d, e, f, K(26), M(26) ); R( f, g, h, a, b, c, d, e, K(27), M(27) ); R( e, f, g, h, a, b, c, d, K(28), M(28) ); R( d, e, f, g, h, a, b, c, K(29), M(29) ); R( c, d, e, f, g, h, a, b, K(30), M(30) ); R( b, c, d, e, f, g, h, a, K(31), M(31) ); R( a, b, c, d, e, f, g, h, K(32), M(32) ); R( h, a, b, c, d, e, f, g, K(33), M(33) ); R( g, h, a, b, c, d, e, f, K(34), M(34) ); R( f, g, h, a, b, c, d, e, K(35), M(35) ); R( e, f, g, h, a, b, c, d, K(36), M(36) ); R( d, e, f, g, h, a, b, c, K(37), M(37) ); R( c, d, e, f, g, h, a, b, K(38), M(38) ); R( b, c, d, e, f, g, h, a, K(39), M(39) ); R( a, b, c, d, e, f, g, h, K(40), M(40) ); R( h, a, b, c, d, e, f, g, K(41), M(41) ); R( g, h, a, b, c, d, e, f, K(42), M(42) ); R( f, g, h, a, b, c, d, e, K(43), M(43) ); R( e, f, g, h, a, b, c, d, K(44), M(44) ); R( d, e, f, g, h, a, b, c, K(45), M(45) ); R( c, d, e, f, g, h, a, b, K(46), M(46) ); R( b, c, d, e, f, g, h, a, K(47), M(47) ); R( a, b, c, d, e, f, g, h, K(48), M(48) ); R( h, a, b, c, d, e, f, g, K(49), M(49) ); R( g, h, a, b, c, d, e, f, K(50), M(50) ); R( f, g, h, a, b, c, d, e, K(51), M(51) ); R( e, f, g, h, a, b, c, d, K(52), M(52) ); R( d, e, f, g, h, a, b, c, K(53), M(53) ); R( c, d, e, f, g, h, a, b, K(54), M(54) ); R( b, c, d, e, f, g, h, a, K(55), M(55) ); R( a, b, c, d, e, f, g, h, K(56), M(56) ); R( h, a, b, c, d, e, f, g, K(57), M(57) ); R( g, h, a, b, c, d, e, f, K(58), M(58) ); R( f, g, h, a, b, c, d, e, K(59), M(59) ); R( e, f, g, h, a, b, c, d, K(60), M(60) ); R( d, e, f, g, h, a, b, c, K(61), M(61) ); R( c, d, e, f, g, h, a, b, K(62), M(62) ); R( b, c, d, e, f, g, h, a, K(63), M(63) ); R( a, b, c, d, e, f, g, h, K(64), M(64) ); R( h, a, b, c, d, e, f, g, K(65), M(65) ); R( g, h, a, b, c, d, e, f, K(66), M(66) ); R( f, g, h, a, b, c, d, e, K(67), M(67) ); R( e, f, g, h, a, b, c, d, K(68), M(68) ); R( d, e, f, g, h, a, b, c, K(69), M(69) ); R( c, d, e, f, g, h, a, b, K(70), M(70) ); R( b, c, d, e, f, g, h, a, K(71), M(71) ); R( a, b, c, d, e, f, g, h, K(72), M(72) ); R( h, a, b, c, d, e, f, g, K(73), M(73) ); R( g, h, a, b, c, d, e, f, K(74), M(74) ); R( f, g, h, a, b, c, d, e, K(75), M(75) ); R( e, f, g, h, a, b, c, d, K(76), M(76) ); R( d, e, f, g, h, a, b, c, K(77), M(77) ); R( c, d, e, f, g, h, a, b, K(78), M(78) ); R( b, c, d, e, f, g, h, a, K(79), M(79) ); a = ctx->state[0] = u64plus (ctx->state[0], a); b = ctx->state[1] = u64plus (ctx->state[1], b); c = ctx->state[2] = u64plus (ctx->state[2], c); d = ctx->state[3] = u64plus (ctx->state[3], d); e = ctx->state[4] = u64plus (ctx->state[4], e); f = ctx->state[5] = u64plus (ctx->state[5], f); g = ctx->state[6] = u64plus (ctx->state[6], g); h = ctx->state[7] = u64plus (ctx->state[7], h); } } /*****************************************************************************/ digup-digup-0.6.57/src/sha512.h000066400000000000000000000103571370707046300160070ustar00rootroot00000000000000/***************************************************************************** * Declaration of functions and data types used for SHA512 and SHA384 * * sum computing. * * * * Copyright (C) 2005, 2006, 2008 * * by Free Software Foundation, Inc. * * * * This file was taken from coreutils-7.4 and adapted for digup. * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ #ifndef _SHA512_H #define _SHA512_H 1 #include #include /* Structure to save state of computation between the single steps. */ struct sha512_ctx { uint64_t state[8]; uint64_t total[2]; size_t buflen; uint64_t buffer[32]; }; enum { SHA384_DIGEST_SIZE = 384 / 8 }; enum { SHA512_DIGEST_SIZE = 512 / 8 }; /* Initialize structure containing state of computation. */ extern void sha512_init_ctx (struct sha512_ctx *ctx); extern void sha384_init_ctx (struct sha512_ctx *ctx); /* Starting with the result of former calls of this function (or the initialization function update the context for the next LEN bytes starting at BUFFER. It is necessary that LEN is a multiple of 128!!! */ extern void sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx); /* Starting with the result of former calls of this function (or the initialization function update the context for the next LEN bytes starting at BUFFER. It is NOT required that LEN is a multiple of 128. */ extern void sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx); /* Process the remaining bytes in the buffer and put result from CTX in first 64 (48) bytes following RESBUF. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ extern void *sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf); extern void *sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf); /* Put result from CTX in first 64 (48) bytes following RESBUF. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. IMPORTANT: On some systems it is required that RESBUF is correctly aligned for a 32 bits value. */ extern void *sha512_read_ctx (const struct sha512_ctx *ctx, void *resbuf); extern void *sha384_read_ctx (const struct sha512_ctx *ctx, void *resbuf); /* Compute SHA512 (SHA384) message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message digest. */ extern void *sha512_buffer (const char *buffer, size_t len, void *resblock); extern void *sha384_buffer (const char *buffer, size_t len, void *resblock); #endif /* _SHA512_H */ /*****************************************************************************/ digup-digup-0.6.57/src/test_digest.c000066400000000000000000000101701370707046300173060ustar00rootroot00000000000000/***************************************************************************** * Message Digest Functions Tests * * * * Test cases: two sets of precalculated message digest results. * * * * Copyright (C) 2009 Timo Bingmann * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ #include "digest.h" #include #include #include void check(const void* str, unsigned int slen, struct digest_ctx* digctx, const char* refhex) { struct digest_result *digres, *digref; digctx->init(digctx); digctx->process(digctx, str, slen); digres = digctx->finish(digctx); digref = digest_hex2bin(refhex, -1); if ( !digest_equal(digres, digref) ) { fprintf(stderr, "Digest result mismatches: %s != %s\n", digest_bin2hex_dup(digres), digest_bin2hex_dup(digref)); } assert( digest_equal(digres, digref) ); free(digres); /* redo test with process_buffer() function */ digres = digctx->process_buffer(str, slen); assert( digest_equal(digres, digref) ); free(digres); free(digref); } int main(void) { struct digest_ctx digest_md5; struct digest_ctx digest_sha1; struct digest_ctx digest_sha256; struct digest_ctx digest_sha512; struct digest_ctx digest_crc32; digest_init_md5(&digest_md5); digest_init_sha1(&digest_sha1); digest_init_sha256(&digest_sha256); digest_init_sha512(&digest_sha512); digest_init_crc32(&digest_crc32); { const char *str1 = "test string"; check(str1, strlen(str1), &digest_md5, "6f8db599de986fab7a21625b7916589c"); check(str1, strlen(str1), &digest_sha1, "661295c9cbf9d6b2f6428414504a8deed3020641"); check(str1, strlen(str1), &digest_sha256, "d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b"); check(str1, strlen(str1), &digest_sha512, "10e6d647af44624442f388c2c14a787ff8b17e6165b83d767ec047768d8cbcb7" "1a1a3226e7cc7816bc79c0427d94a9da688c41a3992c7bf5e4d7cc3e0be5dbac"); check(str1, strlen(str1), &digest_crc32, "45154713"); } { size_t i; unsigned char str2[65536]; for (i = 0; i < sizeof(str2); ++i) { str2[i] = i & 0xFF; } check(str2, sizeof(str2), &digest_md5, "8f1445bafe2c2095044af7789462f475"); check(str2, sizeof(str2), &digest_sha1, "f04977267a391b2c8f7ad8e070f149bc19b0fc25"); check(str2, sizeof(str2), &digest_sha256, "7daca2095d0438260fa849183dfc67faa459fdf4936e1bc91eec6b281b27e4c2"); check(str2, sizeof(str2), &digest_sha512, "76a59ba2dd234dfb4136e2e33a7e3b344d82f4885a17e3b297eab9a5ded81043" "292217b8126b1cfba29170dce2780259dc68ab4f382efe91aa4bb404912741f4"); check(str2, sizeof(str2), &digest_crc32, "a1e61db1"); } return 0; } /*****************************************************************************/ digup-digup-0.6.57/src/test_digup.c000066400000000000000000000057521370707046300171510ustar00rootroot00000000000000/***************************************************************************** * test_digup - Tests within Digest File Update Program * * * * Test cases: TODO * * * * Copyright (C) 2009 Timo Bingmann * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ #include #include #include /* evil but simple way to include the main program to run tests on it */ #define main __mainx #include "digup.c" #undef main void test_filename_escaping(void) { char* str1 = strdup("test-file-name"); char* str2 = strdup("test-file\\nname\\\\"); char* str3 = strdup("illegal escaping \\a test"); char* str4 = strdup("illegal escaping at end \\"); /* unescape examples */ assert( unescape_filename(str1) == TRUE ); assert( strcmp(str1, "test-file-name") == 0 ); assert( unescape_filename(str2) == TRUE ); assert( strcmp(str2, "test-file\nname\\") == 0 ); assert( unescape_filename(str3) == FALSE ); assert( unescape_filename(str4) == FALSE ); /* escape examples again */ assert( needescape_filename(&str1) == FALSE ); assert( needescape_filename(&str2) == TRUE ); assert( strcmp(str2, "test-file\\nname\\\\") == 0 ); assert( needescape_filename(&str3) == TRUE ); assert( strcmp(str3, "illegal escaping \\\\a test") == 0 ); assert( needescape_filename(&str4) == TRUE ); assert( strcmp(str4, "illegal escaping at end \\\\") == 0 ); free(str1); free(str2); free(str3); free(str4); } int main(void) { test_filename_escaping(); return 0; } /*****************************************************************************/ digup-digup-0.6.57/src/test_rbtree.c000066400000000000000000000126651370707046300173250ustar00rootroot00000000000000/***************************************************************************** * Tests for the Red-Black Balanced Binary Tree Implementation in Plain C * * * * Test cases: strings, integer keys and multiple integer keys. * * * * Copyright (C) 2009 Timo Bingmann * * * * This program is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3, or (at your option) any * * later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * *****************************************************************************/ #include "rbtree.h" #include #include #include #include #include void string_free(void *a) { free((char*)a); } int string_cmp(const void *a, const void *b) { return strcmp(a, b); } void string_print(const void *a) { printf("%s", (char*)a); } void test_strings(void) { int i; char str[512]; struct rb_node *node; struct rb_tree *tree = rb_create(string_cmp, string_free, string_free, string_print, string_print); assert( rb_isempty(tree) == 1 ); srand(4545); for (i = 0; i < 10000; i++) { snprintf(str, sizeof(str), "test%d", rand() % 1000000); rb_insert(tree, strdup(str), strdup("value")); } srand(4545); for (i = 0; i < 10000; i++) { snprintf(str, sizeof(str), "test%d", rand() % 1000000); node = rb_find(tree, str); assert(node); } { node = rb_find(tree, "test46554A"); assert(node == NULL); } assert( rb_isempty(tree) == 0 ); assert( rb_size(tree) == 10000 ); srand(4545); for (i = 0; i < 10000; i++) { snprintf(str, sizeof(str), "test%d", rand() % 1000000); node = rb_find(tree, str); assert(node); rb_delete(tree, node); } assert( rb_isempty(tree) == 1 ); assert( rb_size(tree) == 0 ); rb_destroy(tree); } void integer_free(void *a) { (void)a; } int integer_cmp(const void *a, const void *b) { if ((intptr_t)a < (intptr_t)b) return -1; if ((intptr_t)a > (intptr_t)b) return +1; return 0; } void integer_print(const void *a) { printf("%d", (int)(intptr_t)a); } void test_integers(void) { int i; intptr_t val; struct rb_node *node; struct rb_tree *tree = rb_create(integer_cmp, integer_free, integer_free, integer_print, integer_print); assert( rb_isempty(tree) == 1 ); srand(4545); for (i = 0; i < 10000; i++) { val = rand() % 1000000; rb_insert(tree, (void*)val, (void*)val); } srand(4545); for (i = 0; i < 10000; i++) { val = rand() % 1000000; node = rb_find(tree, (void*)val); assert(node); } { node = rb_find(tree, (void*)234324); assert(node == NULL); } assert( rb_isempty(tree) == 0 ); assert( rb_size(tree) == 10000 ); srand(4545); for (i = 0; i < 10000; i++) { val = rand() % 1000000; node = rb_find(tree, (void*)val); assert(node); rb_delete(tree, node); } assert( rb_isempty(tree) == 1 ); assert( rb_size(tree) == 0 ); rb_destroy(tree); } void test_integers_multi(int factor) { int i; intptr_t val; unsigned int count; struct rb_node *node; struct rb_tree *tree = rb_create(integer_cmp, integer_free, integer_free, integer_print, integer_print); assert( rb_isempty(tree) == 1 ); for (i = 0; i < 100 * factor; i++) { val = i % factor; rb_insert(tree, (void*)val, (void*)val); } assert( rb_isempty(tree) == 0 ); assert( rb_size(tree) == (unsigned int)100 * factor); for (i = 0; i < factor; i++) { val = i; node = rb_find(tree, (void*)val); assert(node); count = 0; while (node != rb_end(tree) && (intptr_t)node->key == i) { ++count; node = rb_successor(tree, node); } assert(count == 100); } { count = 0; for(node = rb_begin(tree); node != rb_end(tree); node = rb_successor(tree, node)) { assert((intptr_t)node->key == (count++ / 100)); } } for (i = 0; i < 100 * factor; i++) { val = i % factor; node = rb_find(tree, (void*)val); assert(node); rb_delete(tree, node); } assert( rb_isempty(tree) == 1 ); rb_destroy(tree); } int main(void) { int i; test_strings(); test_integers(); for (i = 10; i < 100; ++i) test_integers_multi(i); return 0; } /*****************************************************************************/