summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2018-09-12 20:43:25 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2018-09-12 20:43:25 +0000
commitce6306613e7dff9faae2e3d4fc4aee7b7fab5da2 (patch)
treec3386ae7b39f7e199d580a1a0bb9803b23f16466
parentInitial commit. (diff)
downloadreprepro-ce6306613e7dff9faae2e3d4fc4aee7b7fab5da2.zip
reprepro-ce6306613e7dff9faae2e3d4fc4aee7b7fab5da2.tar.xz
Adding upstream version 5.2.0.upstream/5.2.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--AUTHORS1
-rw-r--r--COPYING340
-rw-r--r--ChangeLog2207
-rw-r--r--INSTALL192
-rw-r--r--Makefile.am47
-rw-r--r--Makefile.in1258
-rw-r--r--NEWS708
-rw-r--r--README94
-rw-r--r--TODO24
-rwxr-xr-xac/compile348
-rwxr-xr-xac/depcomp791
-rwxr-xr-xac/install-sh518
-rwxr-xr-xac/missing215
-rw-r--r--acinclude.m447
-rw-r--r--aclocal.m41201
-rw-r--r--aptmethod.c1216
-rw-r--r--aptmethod.h27
-rw-r--r--ar.c299
-rw-r--r--ar.h22
-rw-r--r--archallflood.c717
-rw-r--r--archallflood.h6
-rw-r--r--atoms.c392
-rw-r--r--atoms.h74
-rwxr-xr-xautogen.sh27
-rw-r--r--binaries.c797
-rw-r--r--binaries.h57
-rw-r--r--byhandhook.c241
-rw-r--r--byhandhook.h26
-rw-r--r--changes.c333
-rw-r--r--changes.h24
-rw-r--r--checkin.c1612
-rw-r--r--checkin.h26
-rw-r--r--checkindeb.c401
-rw-r--r--checkindeb.h28
-rw-r--r--checkindsc.c435
-rw-r--r--checkindsc.h31
-rw-r--r--checks.c382
-rw-r--r--checks.h16
-rw-r--r--checksums.c1467
-rw-r--r--checksums.h140
-rw-r--r--chunkedit.c452
-rw-r--r--chunkedit.h58
-rw-r--r--chunks.c798
-rw-r--r--chunks.h61
-rw-r--r--config.h.in155
-rw-r--r--configparser.c1532
-rw-r--r--configparser.h300
-rwxr-xr-xconfigure7590
-rw-r--r--configure.ac170
-rw-r--r--contents.c370
-rw-r--r--contents.h32
-rw-r--r--copypackages.c953
-rw-r--r--copypackages.h21
-rw-r--r--database.c2329
-rw-r--r--database.h60
-rw-r--r--database_p.h14
-rw-r--r--debfile.c229
-rw-r--r--debfile.h15
-rw-r--r--debfilecontents.c212
-rw-r--r--descriptions.c207
-rw-r--r--descriptions.h21
-rw-r--r--diffindex.c227
-rw-r--r--diffindex.h19
-rw-r--r--dirs.c230
-rw-r--r--dirs.h29
-rw-r--r--distribution.c1145
-rw-r--r--distribution.h153
-rw-r--r--docs/FAQ219
-rw-r--r--docs/Makefile.am4
-rw-r--r--docs/Makefile.in487
-rwxr-xr-xdocs/bzip.example35
-rwxr-xr-xdocs/changelogs.example246
-rw-r--r--docs/changestool.1172
-rwxr-xr-xdocs/copybyhand.example28
-rw-r--r--docs/di.example/DI-filter.sh40
-rw-r--r--docs/di.example/README13
-rw-r--r--docs/di.example/distributions23
-rw-r--r--docs/di.example/updates5
-rw-r--r--docs/manual.html1497
-rwxr-xr-xdocs/outsftphook.py589
-rwxr-xr-xdocs/outstore.py237
-rwxr-xr-xdocs/pdiff.example255
-rw-r--r--docs/recovery67
-rw-r--r--docs/reprepro.12786
-rw-r--r--docs/reprepro.bash_completion738
-rw-r--r--docs/reprepro.zsh_completion554
-rw-r--r--docs/rredtool.190
-rwxr-xr-xdocs/sftp.py886
-rw-r--r--docs/short-howto209
-rw-r--r--docs/xz.example30
-rw-r--r--donefile.c242
-rw-r--r--donefile.h24
-rw-r--r--downloadcache.c315
-rw-r--r--downloadcache.h49
-rw-r--r--dpkgversions.c150
-rw-r--r--dpkgversions.h13
-rw-r--r--error.h55
-rw-r--r--exports.c548
-rw-r--r--exports.h26
-rw-r--r--extractcontrol.c458
-rw-r--r--filecntl.c89
-rw-r--r--filecntl.h13
-rw-r--r--filelist.c735
-rw-r--r--filelist.h33
-rw-r--r--files.c817
-rw-r--r--files.h86
-rw-r--r--filterlist.c599
-rw-r--r--filterlist.h41
-rw-r--r--freespace.c243
-rw-r--r--freespace.h20
-rw-r--r--globals.h94
-rw-r--r--globmatch.c187
-rw-r--r--globmatch.h7
-rw-r--r--guesscomponent.c108
-rw-r--r--guesscomponent.h14
-rw-r--r--hooks.c62
-rw-r--r--hooks.h16
-rw-r--r--ignore.c101
-rw-r--r--ignore.h66
-rw-r--r--incoming.c2625
-rw-r--r--incoming.h10
-rw-r--r--indexfile.c304
-rw-r--r--indexfile.h19
-rw-r--r--log.c1153
-rw-r--r--log.h30
-rw-r--r--main.c5222
-rw-r--r--md5.c251
-rw-r--r--md5.h41
-rw-r--r--mprintf.c70
-rw-r--r--mprintf.h12
-rw-r--r--names.c150
-rw-r--r--names.h38
-rw-r--r--needbuild.c303
-rw-r--r--needbuild.h16
-rw-r--r--optionsfile.c128
-rw-r--r--optionsfile.h13
-rw-r--r--outhook.c196
-rw-r--r--outhook.h13
-rw-r--r--override.c410
-rw-r--r--override.h35
-rw-r--r--package.h85
-rw-r--r--pool.c869
-rw-r--r--pool.h33
-rw-r--r--printlistformat.c228
-rw-r--r--printlistformat.h7
-rw-r--r--pull.c1112
-rw-r--r--pull.h31
-rw-r--r--readtextfile.c140
-rw-r--r--readtextfile.h16
-rw-r--r--reference.c213
-rw-r--r--reference.h50
-rw-r--r--release.c1896
-rw-r--r--release.h68
-rw-r--r--remoterepository.c2103
-rw-r--r--remoterepository.h68
-rw-r--r--rredpatch.c772
-rw-r--r--rredpatch.h19
-rw-r--r--rredtool.c1459
-rw-r--r--sha1.c201
-rw-r--r--sha1.h15
-rw-r--r--sha256.c274
-rw-r--r--sha256.h20
-rw-r--r--signature.c559
-rw-r--r--signature.h66
-rw-r--r--signature_check.c924
-rw-r--r--signature_p.h18
-rw-r--r--signedfile.c502
-rw-r--r--sizes.c256
-rw-r--r--sizes.h6
-rw-r--r--sourcecheck.c482
-rw-r--r--sourcecheck.h8
-rw-r--r--sourceextraction.c715
-rw-r--r--sourceextraction.h21
-rw-r--r--sources.c731
-rw-r--r--sources.h48
-rw-r--r--strlist.c283
-rw-r--r--strlist.h50
-rw-r--r--target.c1033
-rw-r--r--target.h110
-rw-r--r--termdecide.c302
-rw-r--r--termdecide.h19
-rw-r--r--terms.c386
-rw-r--r--terms.h65
-rw-r--r--tests/Makefile.am52
-rw-r--r--tests/Makefile.in457
-rw-r--r--tests/atoms.test180
-rwxr-xr-xtests/brokenuncompressor.sh13
-rw-r--r--tests/buildinfo.test656
-rw-r--r--tests/buildneeding.test631
-rw-r--r--tests/check.test225
-rw-r--r--tests/copy.test210
-rw-r--r--tests/descriptions.test143
-rw-r--r--tests/diffgeneration.test271
-rw-r--r--tests/easyupdate.test142
-rw-r--r--tests/evil.key18
-rw-r--r--tests/expired.key19
-rw-r--r--tests/expiredwithsubkey-working.key52
-rw-r--r--tests/expiredwithsubkey.key52
-rw-r--r--tests/export.test79
-rw-r--r--tests/exporthooks.test79
-rw-r--r--tests/flat.test518
-rw-r--r--tests/flood.test744
-rwxr-xr-xtests/genpackage.sh68
-rw-r--r--tests/good.key18
-rw-r--r--tests/includeasc.test221
-rw-r--r--tests/includeextra.test857
-rw-r--r--tests/layeredupdate.test684
-rw-r--r--tests/layeredupdate2.test683
-rw-r--r--tests/listcodenames.test41
-rw-r--r--tests/morgue.test276
-rw-r--r--tests/onlysmalldeletes.test142
-rw-r--r--tests/override.test172
-rw-r--r--tests/packagediff.test287
-rw-r--r--tests/revoked.keybin0 -> 624 bytes
-rw-r--r--tests/revoked.pkeybin0 -> 690 bytes
-rw-r--r--tests/signatures.test286
-rw-r--r--tests/signed.test68
-rw-r--r--tests/snapshotcopyrestore.test597
-rw-r--r--tests/srcfilterlist.test221
-rw-r--r--tests/subcomponents.test502
-rw-r--r--tests/template.test4
-rw-r--r--tests/test.inc237
-rwxr-xr-xtests/test.sh271
-rw-r--r--tests/trackingcorruption.test79
-rw-r--r--tests/uncompress.test514
-rw-r--r--tests/updatecorners.test176
-rw-r--r--tests/updatepullreject.test555
-rw-r--r--tests/uploaders.test253
-rw-r--r--tests/various1.test1436
-rw-r--r--tests/various2.test2465
-rw-r--r--tests/various3.test980
-rw-r--r--tests/verify.test437
-rw-r--r--tests/withsubkeys-works.key52
-rw-r--r--tests/withsubkeys.key52
-rw-r--r--tests/wrongarch.test86
-rw-r--r--tool.c3089
-rw-r--r--tracking.c1440
-rw-r--r--tracking.h52
-rw-r--r--trackingt.h38
-rw-r--r--uncompression.c1766
-rw-r--r--uncompression.h69
-rw-r--r--updates.c2699
-rw-r--r--updates.h40
-rw-r--r--upgradelist.c754
-rw-r--r--upgradelist.h45
-rw-r--r--uploaderslist.c1520
-rw-r--r--uploaderslist.h26
247 files changed, 104691 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..dc9fb06
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Bernhard R. Link <brlink@debian.org>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..3320090
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,2207 @@
+2018-08-26 Bernhard R. Link <brlink@debian.org>
+ * mark .lz support as deprecated
+
+2018-08-12 Bernhard R. Link <brlink@debian.org>
+ * allow to set Signed-By header via conf/distributions
+ * add _listcodenames command (based on work from Benjamin Drung)
+ * drop "FILE LOCATION" headers from Contents files
+ * multiple manpage fixes
+ (thanks to Paul Wise, Simon Kainz, Christoph Biedl)
+
+2017-03-02 Bernhard R. Link <brlink@debian.org>
+ * handle .asc files in source files better
+ (thanks to Marc Laue)
+
+2017-01-31 <flapflap@riseup.net>
+ * allow '+' character in method-URI
+
+2016-12-28 Bernhard R. Link <brlink@debian.org>
+ * improve error handling when extracting .deb file contents
+
+2016-12-23 Bernhard R. Link <brlink@debian.org>
+ * properly report errors of the internal xz and lzma decompressors
+ * when using the builtin .xz uncompressor,
+ support concatenated streams
+ * when using the builtin .gz uncompressor,
+ support concatenated streams
+
+2016-12-22 Bernhard R. Link <brlink@debian.org>
+ * add unreferencesnapshot and removereference commands
+ * document --export=silent-never
+ * when using the builtin .bz2 uncompressor,
+ support concatenated streams
+
+2016-12-21 Bernhard R. Link <brlink@debian.org>
+ * fix behaviour of (Deb|Dsc)Indices without a Release file
+ (if no Release filename was given the default was used
+ instead of not creating a file)
+ * document what is needed to use --ask-passphrase with newer
+ gnupg versions in the manpage
+
+2016-12-21 Bernhard R. Link <brlink@debian.org>
+ * add support for .buildinfo files in .changes files:
+ - new tracking mode includebuildinfos to store them in pool/
+ - ignored by 'include' unless Tracking: includebuildinfos
+ - processincoming with LogDir set stores them like log files
+ - otherwise ignored by 'processincoming' if not used
+ - new Cleanup: unused_buildinfo_files for conf/incoming to
+ remove used buildinfo files.
+
+2016-12-18 Bernhard R. Link <brlink@debian.org>
+ * fix some logical errors in some warnings.
+
+2016-10-22 Bernhard R. Link <brlink@debian.org>
+ * drop workaround for apt-method interface change:
+ answer 103 is now always expected to end the method's doing
+ (in other words the http apt method from squeeze and before is no
+ longer supported)
+
+2016-03-* Bernhard R. Link <brlink@debian.org>
+ * refactor code to use struct package and struct package_cursor
+ most of the time package data is accessed.
+
+2016-03-13 Bernhard R. Link <brlink@debian.org>
+ * fix bug in flood that could get confused which binary package
+ belongs to which source if a destination contains packages
+ belonging to different versions of the same souce.
+ * fix bug in the message about "warning" triggered in FilterList
+ of pull. ('(null)' was printed instead of the package name).
+
+2015-12-28 Bernhard R. Link <brlink@debian.org>
+ * fix duplicated --keeptemporaries description in manpage
+ * add Permit: unlisted_binary for conf/incoming
+ * if encountering a -dbgsym package in a .changes file, check the name
+ without -dbgsym in the Binary: header instead
+
+2015-06-13 Bernhard R. Link <brlink@debian.org>
+ * add Exportoptions: to conf/distributions,
+ allowing to give "noexport" to never export a distribution.
+
+2015-05-09 Bernhard R. Link <brlink@debian.org>
+ * ignores lines starting with '#' in filterlists
+ * fix error parsing control files with multiple spaces/tabs after a colon
+
+2014-11-12 Bernhard R. Link <brlink@debian.org>
+ * fix segfault when verbose exporting with .xz indices
+
+2014-08-24 Bernhard R. Link <brlink@debian.org>
+ * fix DownloadListsAs not accepting .lz
+ * add support for unpacking .xz and .lzma files with liblzma
+ instead of calling unxz and unlzma.
+ * default to linking with liblzma if no --with or --without is given
+
+2014-08-16 Bernhard R. Link <brlink@debian.org>
+ * rename the old python pdiff implementation example script
+ from tiffany.example to pdiff.example and make it use python3.
+
+2014-06-28 Bernhard R. Link <brlink@debian.org>
+ * fix compiling without liblzma.
+ * disable liblzma usage unless explicitly requested
+ (to avoid the double-dependency to liblzma un lzma-utils).
+
+2014-06-14 Bernhard R. Link <brlink@debian.org>
+ * add xz.example to script to generate Packages.gz
+ * improve multiple_distributions description in manpage
+
+2014-06-03 Bernhard R. Link <brlink@debian.org>
+ * multiple fixes to the outsftphook example
+
+2014-05-10 Bernhard R. Link <brlink@debian.org>
+ * add support for linking against liblzma
+ and generating .xz Indices.
+ (no changes to decompressing code yet, that still
+ needs xzcat available)
+
+2014-03-18 Bernhard R. Link <brlink@debian.org>
+ * update ignore source packages with ExtraSourceOnly by default,
+ unless the new OmitExtraSourceOnly option is set in conf/updates
+ to false.
+ * fix override mechanism of .udeb files
+
+2014-02-12 Lukas Anzinger <l.anzinger@gmail.com>
+ * add _addreferences to add multiple references at once
+
+2014-02-11 Bernhard R. Link <brlink@debian.org>
+ * improve the errormessage of processincoming if the inclusion of a
+ package is forbidden by uploaders files.
+
+2013-11-21 Bernhard R. Link <brlink@debian.org>
+ * automatically add long Descriptions when updating from a source that
+ does not have them in the Packages files.
+
+2013-10-05 Bernhard R. Link <brlink@debian.org>
+ * fix docs/outstore.py to work with newer python3 dbm behaviour
+ * more strict checking of all size information in .changes files
+
+2013-06-15 Bernhard R. Link <brlink@debian.org>
+ * use libarchive_read_free instead of libarchive_read_finish
+ with newer libarchive to avoid issues with future versions.
+ * repairdescriptions also repairs udeb descriptions
+
+2013-06-15 Bernhard R. Link <brlink@debian.org>
+ * make reprepro compile with libdb6.0
+
+2013-06-02 Bernhard R. Link <brlink@debian.org>
+ * as gcc got better, remove conditional workarounds for
+ most uninitialized-false-positives and make the remaining
+ cases unconditonal (but marked with SETBUTNOTUSED).
+
+2013-05-30 Bernhard R. Link <brlink@debian.org>
+ * fix bug is restore to only act if the
+ last package looked at is restored.
+
+2013-05-04 Bernhard R. Link <brlink@debian.org>
+ * build-needing properly handles sources with
+ architecture wildcards (linux-any) in them.
+
+2013-04-12 Bernhard R. Link <brlink@debian.org>
+ * fix percomponent udeb Contents filenames
+
+2013-02-17 Bernhard R. Link <brlink@debian.org>
+ * add outsftphook.py example
+
+2012-12-31 Bernhard R. Link <brlink@debian.org>
+ * add --outhook
+
+2012-12-20 Bernhard R. Link <brlink@debian.org>
+ * fix inconsistent spacing of ls command,
+ * fix --nothingiserror ls not treating no result as error
+ * add lsbycomponent command (as ls, but grouped by component)
+
+2012-12-15 Bernhard R. Link <brlink@debian.org>
+ * move around some of the code related to moving
+ (In)Release(.gpg) to it's final place. Side effect
+ is that those files are removed if there are no longer
+ requested.
+
+2012-12-09 Bernhard R. Link <brlink@debian.org>
+ * unify export handling (moving it out of the
+ action specific code)
+
+2012-12-02 Bernhard R. Link <brlink@debian.org>
+ * keep around relative release filenames always
+
+2012-11-24 Bernhard R. Link <brlink@debian.org>
+ * make setting of environment variables for
+ hooks more uniform (and with less code duplication).
+
+2012-11-17 Bernhard R. Link <brlink@debian.org>
+ * '~/' or '+{b,o,c}/' or './' now also special
+ in ByHandHooks and ListHook.
+ * add support for signing hooks (SignWith: !...)
+
+2012-11-11 Bernhard R. Link <brlink@debian.org>
+ * add --endhook to start a script when terminating
+
+2012-11-04 Bernhard R. Link <brlink@debian.org>
+ * add repairdescriptions command to readd missing long
+ descriptions (which you might get as reprepro cannot yet
+ get Translations files and get them from there)
+ from the .deb files.
+
+2012-10-30 Bernhard R. Link <brlink@debian.org>
+ * add ${$basename}, ${$filekey} and ${$fullfilename} to --listformat
+ * fix some bitrot in the non-libarchive code paths
+
+2012-10-21 Bernhard R. Link <brlink@debian.org>
+ * reject absurd large values in ValidFor header
+ * fix wrong include type in termdecide.h
+
+2012-09-03
+ * fix overlong VerifyRelease example in manual.html
+
+2012-07-12
+ * add 'deleteifunreferenced' command to safely delete
+ and forget the given files in a repository with
+ keepunreferencedfiles set.
+
+2012-07-11
+ * fix bug in checking old unchanged {Packages/Sources}.bz2
+ files for existence. (Triggering even an assertion when
+ only .bz2 index files are requested).
+ * ignore diff comments about unterminated lines
+ when parsing .diff files
+
+2012-06-24
+ * support http-method's extended 103 redirect status
+ * actually set REPREPRO_CONFIG_DIR in hooks as
+ documented in manpage.
+ * document more environment variables in manpage
+
+2012-06-07
+ * fix bash and zsh completion to work with
+ conf/distributions and conf/incoming directories.
+ * fix allocation error with more than 16 group
+ members in allocation files.
+
+2012-05-30
+ * add support for -A, -C, -T to *update and *pull.
+
+2012-05-22
+ * try to get InRelease from remote repositories
+ instead of Release (with fall-back of the old behaviour)
+ * new GetInRelease: to conf/updates, defaults to yes
+
+2012-05-21
+ * fix some errors when compiled without libgpgme
+
+2012-05-20
+ * normalize included package control information to
+ always start with the Package: field (as some clients
+ assume that).
+ * don't require md5sum to download binary or source packages
+ in the remote index files (any known hash suffices)
+
+2012-05-19
+ * avoid some problem with gcc-4.7
+
+2012-04-24
+ * change Contents-* files generation default from
+ "allcompontents" to "percomponent compatsymlink".
+ (i.e. best for >= wheezy, only first component visible for
+ <= squeeze)
+
+2012-04-04
+ * 'include' now only warns about section "unknown" instead of
+ rejecting it. add warnings to 'includedsc' and 'includedeb', too.
+
+2012-03-26
+ * allow absolute filenames in !include directives, and
+ expand filenames starting with "~/" "+b/" "+c/" in those
+ and export hooks, filter lists, log scripts, override filenames,
+ and uploaders filenames.
+ * conf/distributions, conf/updates, conf/pulls and conf/incoming
+ or files included by those can be directories with all *.conf
+ files read instead.
+
+2012-03-25
+ * changelogs.example can now also place changelogs in places
+ where apt-get changelog looks for "third party site" changelogs.
+ * add 'supersede' as FilterList keyword to remove the old package
+ if the the new would be installed otherwise.
+ * fix broken test against leading whitespace in config file
+ field names
+ * add support for !include directive in conf/distributions,
+ conf/updates, conf/pulls and conf/incoming.
+
+2012-01-23
+ * reject "any" as Architecture part of a distribution
+
+2012-01-21
+ * build-needing now can list missing architecture 'all'
+ packages. (Will not list .dsc files producing both
+ architecture dependent and architecture indepentent ('all')
+ packages unless they are built with dpkg-dev >= 1.16.1,
+ though).
+
+2012-01-19
+ * build-needing takes 'any' instead of a architecture, too.
+ * uploader files can 'include' other files.
+
+2012-01-17
+ * improve config file parser error messages about missing fields
+
+2010-12-18
+ * rredtool: produce .diff/Index files that reprepro can understand.
+ * warn if uploader files contains key ids too long to handle
+ * don't warn against .git files as unknown extension
+
+2010-12-09
+ * if failing to parse .diff/Index, proceed with other
+ ways to retrieve Packages/Sources.
+
+2010-10-30
+ * don't give spurious warnings about "strange filekey"s if
+ components contain slashes.
+
+2010-10-10
+ * fix NULL-reference segfault if patch in a Packages.diff
+ does not have a history attached to it (or if it is listed
+ two times)
+
+2010-10-03
+ * when using nocompatsymlink in Contents warn about
+ old file/symlink still present.
+
+2010-09-28
+ * fix archive_set_error calls
+ (don't give error messages as format strings)
+ * remove undocumented Contents: options with leading +/-
+ * add compatsymlink nocompatsymlink Contents: options
+ (and document that the default will change in the future)
+
+2010-08-22
+ * add 'redochecksums' command to complete the checksum information
+ in package indices.
+
+2010-08-19
+ * add percomponent and allcomponents to Contents: flags
+ to switch between the format of Contents file to generate.
+ Currently the default is allcomponents but that will switch
+ later.
+ * fix bug that would delete files only to be deleted after an
+ successful export also when aborting an export
+
+2010-07-07
+ * don't give downgrading message if not downgrading but
+ replacing with same version
+
+2010-06-02
+ * fix bug not deleting packages if none added in update
+
+2010-05-05
+ * ignore leading comments in control files
+
+2010-04-18
+ * add --restrict and --restrict-bin to restrict update
+ and pull operations to specific packages.
+ * add --restrict-file and --restrict-file-bin.
+
+2010-04-17
+ * add --export=silent-never like never but silenting
+ all warnings (mostly useful for testsuite).
+ * avoid 'Data seems not to be signed trying to use directly'
+ message if data start like unsigned file should start.
+
+2010-04-16
+ * add 'FilterSrcList'.
+
+2010-04-15
+ * Many clean-ups and coding style fixes.
+
+2010-03-30
+ * Support specifying a version in FilterList
+
+2010-02-29
+ * support compiling with libdb5
+ * fix memory bug in filelist generation
+ (as realloc usually not moves stuff when reducing the size that
+ is no real issue, but newer valgrind detects it and warns).
+
+2010-02-28
+ * 'check' also checks if architectures match
+ * fix 'sourcemissing', 'unusedsources' and 'reportcruft'
+ on distributions without tracking.
+ * fix 'pull' copying packages with wrong architecture
+
+2010-02-21
+ * support reading of Release files without MD5Sum
+ * add all missing Checksums-* when importing from
+ remote repositories
+ * allow md5 in IgnoreHashes
+
+2010-02-16
+ * make 'sourcemissing', 'unusedsources' and 'reportcruft' work on
+ distributions without tracking.
+
+2010-02-14
+ * add 'reportcruft' command
+ * ignore source checking in distributions without 'source' architecture
+
+2010-01-30
+ * add 'sizes' command.
+ * add "distribution 'codename'" support to uploaders files.
+ * some fixes for __checkuploaders
+
+2010-01-27
+ * SignWith can take multiple arguments to denote multiple keys to
+ sign a repository with.
+
+2010-01-22
+ * add removesrcs command (like removesrc but can get multiple
+ source package names)
+
+2010-01-03
+ * add groups to Uploaders:-lists.
+ * add __checkuploaders command so uploaders lists can be tested
+ from the test-suite
+
+2010-12-23
+ * fix some minor memory/resource leaks found by cppcheck
+
+2010-10-16
+ * support "ButAutomaticUpgrades" field to be copied to
+ the generated Release files (Thanks to Modestas Vainius)
+
+2010-10-15
+ * add support for lzip compressed files
+ (Thanks to Daniel Baumann for the patch).
+
+2010-09-10
+ * add special '$Delete' override field to delete fields
+
+2010-09-09
+ * fix reoverride problem with packages only having a $Component
+ special-override-field.
+
+2010-08-12
+ * fix missing #ifdef breaking --without-libbz2 compiles
+ * include sys/stat.h in filecntl.c, thanks to Jeroen van Meeuwen
+
+2010-08-04
+ * add unusedsources and sourcemissing commands.
+
+2010-07-10
+ * create InRelease files when signing...
+
+2010-07-05
+ * special $Component in override files will force
+ placing packages in the specified component
+ upon inclusion (unless -C is given).
+
+2010-07-04
+ * consult override files when importing packages
+ with 'update' or 'pull'.
+
+2010-07-01
+ * fix inconsistency in changelog.example.
+ Thanks to Christoph Mathys.
+
+2010-06-30
+ * allow patterns in override files
+
+2010-06-29
+ * do not stop with error if a downloaded Packages
+ file contains unexpected wrong Architecture lines
+ but only print a warning. Add --ignore=wrongarchitecture
+ to not print that warning.
+
+2010-06-26
+ * store override data in a tree instead of an list and
+ some preparations for patterns in override files.
+
+2010-06-25
+ * Ignore overrides for fields starting with '$' and
+ warn about unknown fields to allow later introduction
+ of special values.
+ * disallow overrides of core fields (Package, Version,
+ Filename, ...)
+
+2010-05-07
+ * add --onlysmalldeletes option that cancels pulls
+ and updates that delete more than 20% of some target
+ (but at least 10 packages). The change also causes
+ update no longer claiming to get packages if there are
+ not any packages to get...
+
+2010-04-30
+ * change parsing of .changes lines to cope with
+ N_V.orig-X.tar.C files where V.orig-X does not survive
+ a proper version check (underscores most prominently).
+
+2010-04-23
+ * Fix typo causing --changes Log-notifiers not being called
+ with processincoming in many cases.
+
+2010-04-07
+ * add '${$source}' and '${$sourceversion}' to --list-format
+
+2010-03-31
+ * describe byhand file in the manpage's "nomenclature".
+
+2010-03-19
+ * add "dumbremove" to changestool.
+
+2010-02-10
+ * fix failure if trying to extract exactly one of
+ section or priority from a tar file.
+
+2010-01-24
+ * add ByHandHooks to conf/distributions for hooks
+ called by processincoming (and in the future perhaps by include)
+
+2010-01-18
+ * properly handle relative LogDir in conf/incoming
+
+2009-12-08
+ * add byhand statement to uploaders files
+
+2009-11-22
+ * fix build with --without-libgpgme
+ (thanks to Reto Gantenbein for reporting)
+
+2009-11-16
+ * include <stdint.h> where *int*_t is used
+
+2009-11-13
+ * 'include' now errors out early if the .changes includes source files but
+ no .dsc file.
+
+2009-11-12
+ * add mode to rredtool to act as reprepro index hook and generate
+ and update a *.diff/Index file.
+
+2009-11-06
+ * when 'include'ing a .changes file, do not insist on section
+ information of non-.dsc source files.
+
+2009-10-27
+ * Do not warn about a missing VerifyRelease if there is a
+ IgnoreRelease.
+ * Handle apt transport methods returning missing files as
+ success with alternate filename suggestion more gracefully.
+ * when getting packages from another architecture while updating,
+ ignore all packages with architecture not fitting into the target.
+ (Fixes a regression introduced in 3.8.0)
+2009-10-21
+ * reduce number of places where new compressions must be added
+ * improve checking for proper filenames in changestool's verify
+ * allow .build as synonym for .log as suffix in changes files
+
+2009-10-20
+ * reduce number of places where new compressions must be added
+
+2009-10-17
+ * support xz compressed files if unxz is installed.
+
+2009-10-02
+ * make 'check' (and some other commands) warn if a file expected
+ is not in the checksums database but found correctly in the pool.
+
+2009-09-23
+ * Method: and Fallback: in conf/updates now strip the last '/' from
+ the URI given. (Some apt methods get confused if they get "//").
+
+2009-09-15
+ * fix exit-code of 'list' with --nothingiserror
+
+2009-09-10
+ * call gpgme_check_version so that libgpgme 1.2.0 does not fail
+ to initialize.
+
+2009-08-24
+ * remove all files.db code (except translatelegacyfilelists).
+ * remove --oldfilesdb option.
+ * remove --overridedir
+
+2009-08-23
+ * warn if old legacy files.db is still used and add new
+ translatelegacyfilelists command for easier migration.
+
+2009-08-21
+ * new --showpercent option to show percent and total
+ download size when downloading packages.
+ * do not output the new warning about a new architecture
+ when all architectures are new (i.e. new distribution)
+
+2009-08-20
+ * new 'Options: limit_arch_all' in conf/incoming causes
+ processincoming to only put architecture all packages into
+ the architectures uploaded with them to allow usage together
+ with 'flood'.
+
+2009-08-18
+ * speed up 'flood' by using an tree instead of a list for source
+ package lookups.
+
+2009-08-17
+ * add new 'flood' command to distribute architecture all packages
+ within one architecture.
+
+2009-08-15
+ * -A, -T and -C can now have multiple arguments separated by '|'.
+
+2009-08-13
+ * FakeComponentPrefix now does not add the prefix to components
+ already having it and removes it from the relative directory where
+ it is put into (so no duplication on the whole path, either).
+
+2009-08-06
+ * command line (and conf/options) options to specify a directory
+ now treat arguments starting with '+b/', '+c/' or '+o/' as relative
+ to the basedir, confdir or outdir.
+ * warn if directories do not start with '/', './' or '+x/'.
+
+2009-08-05
+ * if a package is not accepted by processincoming because no
+ distribution is found for it or no distribution allows it, the
+ existcode is now 243
+
+2009-08-03
+ * add a MorgueDir option to conf/incoming where cleaned up files
+ are moved to.
+ * if a .changes has improper name, version or architectures,
+ trigger the 'Cleanup: on_error' case.
+
+2009-08-01
+ * improve deleteunreferenced's error message with keepunreferencedfiles
+
+2009-07-25
+ * add $Version, $Source, $SourceVersion, $Architecture, $Component,
+ $PackageType as special fields in formulas.
+
+2009-07-21
+ * fix build-needing to look at the correct Architecture field in
+ .dsc files.
+
+2009-07-20
+ * add an --morguedir where files removed from the pool are
+ stored.
+
+2009-07-15
+ * add --create-with-all-fields to changestool that is
+ like --create but also creates Urgency and Changes fields.
+
+2009-07-11
+ * make predelete also call retrack when needed,
+ silence false warning of stale tracking by removesrc
+
+2009-07-10
+ * warn if a distribution with tracking is modified in a form tracking
+ data might get out of data. update and pull automatically cause a
+ retrack on distributions with tracking enabled.
+
+2009-07-09
+ * some more improvements to the build-needing command
+
+2009-07-07
+ * fix bug in processincoming not accepting Suite or AlsoAcceptFor
+ because of counting it two times and erroring out.
+ (Thanks to Wookey for finding this bug).
+
+2009-06-16
+ * add listmatched, removematched, copymatched and restorematched.
+ (For those who think listfilter 'Package (% glob)' is too hard
+ to write, to remember or too slow).
+ * add build-needing command
+
+2009-06-05
+ * add glob-matching in formulas via '(% pattern)'
+ * uploaders list conditions that supported stars
+ now use the generic globmatch (thus more stars and ? and []).
+
+2009-06-03
+ * new --list-max and --list-skip
+
+2009-06-02
+ * new 'architectures' condition for uploader lists and other
+ conditions support 'contains' now.
+
+2009-05-31
+ * add --list-format
+
+2009-05-29
+ * add _listdbidentifiers and _listconfidentifiers
+ * add condition "source 'something'" for uploader lists,
+ to limit a uploader to packages with the specified source.
+
+2009-05-22
+ * allow subkey matching in uploader lists, 'unsigned' now only
+ means unsigned while the new 'anybody' means everybody.
+ Preparations for more conditions.
+
+2009-05-12
+ * copy and copysrc give warnings about not found packages unless
+ verbosity is reduced by --silent. (To help people catch their typos).
+
+2009-04-13
+ * rewrite Release.gpg verification code:
+ - to allow usage of expired or revoced keys, the key-id
+ in VerifyRelease has to be appended with '!' and the corresponding
+ new ignore option given.
+ - subkeys are accepted if the key-id is appended with '+'.
+ - keys are requested from libgpgme before anything is downloaded
+ (helps catching c&p errors and makes subkey checks possible).
+ - if verification fails, the status of all found signatures is printed.
+
+2009-04-07
+ * bugfix: ListHook was not used in rules including the rule with it
+ in "From:"
+ * add "ListShellHook", that is like ListHook but with arguments and
+ the files in stdin and stdout.
+
+2009-04-03
+ * fix bug (caught by assertion) that inverts the logic of downloading
+ .diff files when there is no DownLoadListsAs line.
+
+2009-03-18
+ * support new suffix ".new." for export hooks.
+ (Which moves filename + ".new" to filename on success,
+ but unlike ".new" does not mention the file in Release)
+ * new suffix ".keep" for export hooks tha just ignores that line,
+ for compatibility with future changes.
+ * warn if an (Deb|UDeb|Dsc)Indices line contains no filename.
+ (warn against everything starting with a dot to avoid a user putting
+ forgetting it and putting a compression identifier there).
+
+2009-03-14
+ * fix mishandling of libz return code
+ causing "Zlib error 1"..."stream end" error messages.
+ This defect seems to be only triggered with at least lenny's libz.
+ (And only when extracting Section and Priority from a dsc).
+
+2009-03-05
+ * Implement force.<compression> as DownLoadListAs item to download an
+ index not found in the Release file.
+ * warn if database is in old format
+
+2009-03-04
+ * also continue downloading index files after failure to get the
+ prefered one in the IgnoreRelease case.
+
+2009-03-03
+ * regression fix: when updating with IgnoreRelease, old index
+ files were no longer deleted in 3.8 before telling the apt-methods to
+ download new ones, which can trigger buggy behaviour in those.
+ * if one index file fails to be downloaded, try the next one
+ (except for updates with IgnoreRelease, yet)
+
+2009-03-02
+ * fix bug not taking all DownloadListAs into account when multiple
+ update rules requests the same index file to be downloaded.
+ * if a .diff/Index file does not list the available Packages file
+ or if not for targeted file, proceed with other ways to retrieve
+ it.
+ * add .diff processing as first default when there is no
+ DownloadListsAs.
+
+2009-03-01
+ * support using Packages.diff when updating.
+ (Fallback to other methods not yet supported, so not yet enabled
+ in the default DownloadlistsAs)
+
+2009-02-28
+ * fix some bugs in --nothingiserror handling
+
+2009-02-27
+ * move handling of downloaded files from aptmethod.c to
+ the code queuing the files. (refactorisation in preparation of later
+ changes)
+
+2009-02-24
+ * fix race condition causing external uncompressors sometimes
+ to catch a sigpipe if their output is closed before they receive
+ the signal to kill them.
+ * changestool now supports looking into lzma files
+ (and bz2 files even when not compiled against libbz2), if
+ external uncompressors are available.
+ * fix bug extracting the Section and Priority from .diff
+ files if control was not the first file in it.
+ * fix bug .diff parsing's exception to also allow diff
+ generated files.
+
+2009-02-23
+ * log notifiers get variables REPREPRO_CAUSING_RULE and
+ REPREPRO_FROM set when adding packages via update/pull.
+ The later also in copy* and restore* commands.
+ * delete unexpected (i.e. not registered in the database)
+ files in pool when trying to replace with new ones.
+
+2009-02-21
+ * add --keeptemporaries and without it delete all .new files when
+ exporting fails (and not only Release) and with it keep all
+ (including Release). Also fix gpg error message to not suggest trying
+ it with a file that later will be deleted.
+
+2009-02-20
+ * add 'warning' flag for FilterList files
+
+2009-02-13
+ * add ReadOnly option for conf/distributions
+
+2009-02-08
+ * processincoming support includebyhand and includelogs tracking
+ options
+ * new LogDir for processincoming, that gets the .changes files,
+ .log files and unused byhand (or raw-*) files.
+
+2009-02-06
+ * ignore byhand and logfiles in 'include' unless tracking
+ with includebyhand or includelogs is activated, then store them
+ into the pool.
+
+2009-01-22
+ * fix typo causing copyfilter to fail
+ * add --gnupghome option to set GNUPGHOME environment variable
+ * fix importing of source packages from flat repositories without
+ a Directory field in Sources index.
+
+2009-01-17
+ * fix erroneous "strange filekey" warning for lib files in 3.8.0~alpha
+
+2009-01-16
+ * make Date: more like official Release files by replacing
+ the old "+0000" with "UTC".
+
+2009-01-15
+ * add support to generate Valid-Until in Release
+
+2009-01-09
+ * handle 'raw-*' sections like 'byhand' sections (i.e. mostly not
+ handle them, but give better error messages).
+
+2009-01-06
+ * add DownloadListsAs: option for conf/updates to specify which index
+ files (.gz, .bz2, .lzma, ...) to download when available.
+
+2009-01-04
+ * add support for libdb4.7 (yet with some warnings to note I have not
+ tested it much yet)
+ * bugfix in checkpool with old files.db
+
+2009-01-02
+ * FilterList/FilterFormula can be inherited with From: in update rules.
+ * bugfix: if FilterList return hold, FilterFormula was not asked.
+ Not it is only hold if FilterFormula also includes this package.
+ (pull/update)
+ * if a distribution is both flat and non-flat, do not raise an
+ assert, but emmit a warning and proceed (new flatandnonflat ignore
+ class to ignore that warning).
+
+2008-12-06
+ * add 'upgradeonly' value for FilterList, that only takes
+ an package into account if it already exists.
+
+2008-12-02
+ * implement cleanlists command
+
+2008-11-24
+ * fix bug in sha256 calculation over very large files
+
+2008-11-13
+ * add dumpupdate and dumppull actions that are like checkupdate and
+ checkpull but with less information but that more easily parseable.
+
+2008-11-04
+ * fix parsing error of contents of very big .deb files.
+ Thanks to Aramian Wasielak and Alexander Perlis.
+
+2008-11-03
+ * rework handling of files added to the pool not used by anything.
+ (for example because the package was not added due to error).
+ New --keepunusednewfiles option to not delete such files.
+
+2008-11-01
+ * print number of newly unreferenced file on --keepunreferenced
+ and commands not deleting their references.
+
+2008-10-30
+ * add support for flat repositories with Sources files without
+ Directory lines (Thanks to Cody A.W. Somerville for noting).
+
+2008-10-12
+ * some rework on unreferenced files bookkeeping. Should make no
+ difference yet but only make the "Deleting files not longer
+ referenced" only show up if something is deleted...
+
+2008-10-05
+ * Internaly atomize components architectures and packagetypes.
+ Causes multiple checks for unknown identifiers to be earlier or
+ more strict. (And fields in conf/distributions have more
+ restrictions w.r.t their order).
+ * fix bug in (tracking enabled) removesrc that caused malformed
+ tracking data when a source package's track record contains a
+ file no longer found in any distribution.
+ [2009-01-16: I previously believed this nearly impossible to
+ trigger, but a simply outdated tracking data already suffices
+ to trigger it]
+
+2008-10-01
+ * warn if an update rule references local components or architectures
+ that were not seen in conf/distributions (old behaviour was to check
+ if any distribution that references this rule had this architecture,
+ but that was too complex with the new rule-can-reference-rule
+ possibilities).
+
+2008-09-18
+ * update rules can include other rules with From: allowing
+ leaner conf/updates file and avoiding duplicate downloading
+ of upstream indices.
+ * do not process distributions without Updates: field upon
+ update/checkupdate/predelete...
+
+2008-09-09
+ * also support external uncompression programs for
+ .orig.tar/.debian.tar/.tar uncompression, i.e.:
+ - support Section/Priority extraction from lzma compressed dsc packages
+ - libarchive no longer needs to be linked against zlib/libbz2
+ * fix some corner cases in .diff parsing
+
+2008-09-07
+ * add support for external uncompression programs
+ - speeding up updating, as downloading and uncompressing
+ can happen at the same time
+ - support lzma compressed .deb and .diff (when unlzma is available)
+ - supporting .bz2 compressed files even when compiled without libbz2
+ (but needing runtime bunzip2 then)
+ * make --nooldfilesdb the default
+
+2008-08-24
+ * unify reading of compressed files, adding support for:
+ - extracting section and priority from a .diff.bz2
+ - restoring from a snapshot with only .bz2 indices
+
+2008-08-23
+ * massive refactorisation of the update code to retrieve
+ remote index files. Most important modifications:
+ - when the same remote distribution is needed by multiple
+ updates, then the index files are only downloaded once.
+ (still needs futher changes to allow better detection
+ of the same source).
+ - ListHooks are called once per use (should mostly only
+ make a difference for flat sources or with settings
+ where this is needed).
+ - --nolistsdownload now only not downloads lists and has
+ no other effects (checksums still checked, --noskipold
+ no longer implied).
+ - deleting of old no longer needed lists (the default
+ --nokeepunneeded) no longer exists.
+ - index files are stored uncompressed in lists/ and the
+ way files are named there is less strange...
+ - many other changes are possible now and will hopefully
+ be implemented soon.
+ * support downloading .bz2 indices
+ * add --via to Log-notifiers to only call notification
+ scripts when the action was triggered by a specific
+ command.
+
+2008-08-22
+ * some internal cleanup preparing for future changes...
+
+2008-08-16
+ * allow multiple export hooks
+
+2008-08-12
+ * check for Ctrl-C in file_foreach (dumpunreferenced, ...)
+
+2008-08-08
+ * fix handling of libbz2 return codes
+
+2008-08-07
+ * make reoverride work again...
+ (and not ignore section and priority)
+
+2008-08-03
+ * remove iteratedupdate
+
+2008-07-30
+ * fix double-free whith --export=never
+
+2008-07-27
+ * buffered read of index files upon "update".
+
+2008-07-26
+ * add support to retrieve packages from flat repositories.
+
+2008-07-25
+ * refactor indexfile parsing. (Needed for future changes,
+ perhaps speeding some things up a tiny littly bit).
+ * fix logic error causing restorefilter aborting
+
+2008-07-23
+ * Do not claim --noskipold makes a difference in the update output
+ for targets not having any upstream to pull from.
+
+2008-07-22
+ * better cope with a file needed multiple times when
+ updating
+
+2008-07-12
+ * make list package argument optional, listing all
+ packages if not there.
+ * fix bug causing assert() instead of proper error message
+ if list gets too many arguments.
+
+2008-07-03
+ * add IgnoreHashes directive for conf/updates
+
+2008-06-26 Bernhard R. Link <brlink@debian.org>
+ * add FakeComponentPrefix, that adds a prefix to components
+ in the Release file and removes them from Codename and Suite
+ in the central Release file. This way it looks more like
+ security /updates and thus apt is not confused.
+
+2008-06-25 Bernhard R. Link <brlink@debian.org>
+ * avoid creating symlinks that cannot work because of
+ a '/' in the link to create.
+
+2008-06-23 Bernhard R. Link <brlink@debian.org>
+ * fix bug in optionsfilename calculating introduced in
+ last revision.
+
+2008-06-22 Bernhard R. Link <brlink@debian.org>
+ * move some directoy variables to global variables,
+ some related cleanup in the code
+ * set REPREPRO_BASE_DIR, REPREPRO_OUT_DIR, REPREPRO_DIST_DIR,
+ REPREPRO_CONF_DIR and REPREPRO_LOG_DIR when calling log notifiers,
+ apt methods, update hooks or export hooks.
+
+2008-06-07 Bernhard R. Link <brlink@debian.org>
+ * remove some checks that fail for version 2 or 3 debian
+ source packages. (in reprepro include and changestool verify)
+ * extract missing Section and Priority also from a .debian.tar.{gz,bz2}
+ file.
+
+2008-06-06 Bernhard R. Link <brlink@debian.org>
+ * switch to 'new' AC_INIT and AM_INIT_AUTOMAKE syntax,
+ move automaitcally included autoconf to ac/ subdir
+ * fix typo causing internal error when removesrc
+ is called for a distribution with tracking for an unknown
+ source name.
+
+2008-05-17 Bernhard R. Link <brlink@debian.org>
+ * Add support for sha256.
+ * changestool puts Files: last, makes it easier
+ to use some versions of dupload.
+
+2008-05-16 Bernhard R. Link <brlink@debian.org>
+ * When include'ing a .changes file with Checksums
+ header and limiting to some files with -A or -T, do
+ not errounously complain about not expecting the
+ skipped files in Checksums-* headers
+ * Look at suite names when no distribution with the
+ requested codename exists.
+
+2008-05-15 Bernhard R. Link <brlink@debian.org>
+ * Print warning when not including when not including a
+ package because of unknown key/expire/revocation.
+ (In addition to the warning with -v about those problems
+ with a signature and in addition to the message of not
+ including a package at all if that was the only chance to
+ get it in)
+
+2008-04-17 Bernhard R. Link <brlink@debian.org>
+ * fix free of uninitialized pointer when calling log notifiers
+ while removing (this time for real)
+
+2008-04-12 Bernhard R. Link <brlink@debian.org>
+ * move assertion to not abort() on wrong md5sums in include
+ command, but cleanly error out.
+ * do not close random fd when starting client without
+ control data.
+ * fix free of uninitialized pointer when calling log notifiers
+ while removing
+
+2008-04-05 Bernhard R. Link <brlink@debian.org>
+ * add restore restoresrc restorefilter and _addpackage
+
+2008-04-04 Bernhard R. Link <brlink@debian.org>
+ * add copysrc and copyfilter
+ * reimplement copy command (should no longer invalidate
+ tracking information)
+ * warn against impossible -T values and impossible
+ -A -T combinations (source is dsc and dsc is source)
+
+2008-03-31 Bernhard R. Link <brlink@debian.org>
+ * bugfix: no longer confuse -S and -P (introduced in 3.0.1)
+
+2008-03-25 Bernhard R. Link <brlink@debian.org>
+ * put a fake Suite: field in Release files generated by
+ gensnapshot to avoid apt warning about the distribution
+ name not matching.
+
+2008-03-17 Bernhard R. Link <brlink@debian.org>
+ * Log:-scripts are starting with environment-variable
+ REPREPRO_CAUSING_FILE set to the main file causing this
+ change. (.changes for include/processincoming, .dsc for includedsc,
+ .deb for includedeb);
+
+2008-03-14 Bernhard R. Link <brlink@debian.org>
+ * read Checksums-Sha1 in .changes file in processincoming
+
+2008-03-13 Bernhard R. Link <brlink@debian.org>
+ * changestool can write Checksums-Sha1 headers now
+ * read Checksums-Sha1 in .changes file in the include command
+
+2008-03-12 Bernhard R. Link <brlink@debian.org>
+ * Bugfix: When replacing fields only those matching with
+ the same case were replaced.
+
+2008-03-10 Bernhard R. Link <brlink@debian.org>
+ * write Checksums-Sha1 to Sources.gz when available and
+ remove Checksums-Sha256 to avoid problems with not yet being
+ able to add the .dsc file.
+ * Do not warn about missing Standards-Version as newer dpkg-source
+ no longer include them.
+
+2008-03-09 Bernhard R. Link <brlink@debian.org>
+ * read Checksums-Sha1 in .dsc files
+
+2008-03-08 Bernhard R. Link <brlink@debian.org>
+ * When missing section or priority reprepro's includedsc and
+ changestool's add[dsc] look into the .diff and the .tar file.
+ * changestool's add* commands look for files in the current directory
+ first, adddsc for files referenced in the directory of the dsc file.
+
+2008-03-06 Bernhard R. Link <brlink@debian.org>
+ * fix/improve some messages, based upon many suggestions
+ by Marc Haber.
+
+2008-03-02 Bernhard R. Link <brlink@debian.org>
+ * fix double free error in checksums upgrade case of includedeb
+
+2008-03-01 Bernhard R. Link <brlink@debian.org>
+ * cleaning: port changestool to new checksums code,
+ finally removing the old md5sum code.
+
+2008-02-29 Bernhard R. Link <brlink@debian.org>
+ * improve documentation of listfilter command
+
+2008-02-21 Bernhard R. Link <brlink@debian.org>
+ * make --without-libarchive compile again, thanks to
+ Jesus Roncero for noticing.
+
+2008-02-19 Bernhard R. Link <brlink@debian.org>
+ * Try harder not to leave any newly added files
+ to the pool in the case of an error.
+
+2008-02-15 Bernhard R. Link <brlink@debian.org>
+ * Also ignore missing Changes and Description lines
+ in .changes files with "include".
+
+2008-02-12 Bernhard R. Link <brlink@debian.org>
+ * Add --outdir directive to set the directory the pool
+ hierarchy is put under (and the dists hierarchy unless
+ --distdir puts it somewhere else).
+
+2008-02-11 Bernhard R. Link <brlink@debian.org>
+ * fix --waitforlock parsing on 64 bit size_t architectures.
+ (Thanks to Arno Renevier for reporting the bug)
+
+2008-02-01 Bernhard R. Link <brlink@debian.org>
+ * new --nooldfilesdb switch to only use new-style checksum database
+ * improve db/version generation, set minimum required reprepro version
+ to 3.3.0 when only using checksums.db
+
+2008-01-13 Bernhard R. Link <brlink@debian.org>
+ * improve collecting of not yet known checksums and using
+ already recorded checksums in the database
+
+2008-01-06 Bernhard R. Link <brlink@debian.org>
+ * implement collectnewchecksums
+
+2008-01-04 Bernhard R. Link <brlink@debian.org>
+ * add checksums.db to store all checksums (as opposed to only md5sums
+ in files.db). The old files.db persists for compatibility, but when
+ checksums.db is up to date (when repository is generated with new
+ reprepro or to be implemented collectnewchecksums was run) the old
+ files.db can be deleted and only checksums.db is used then. (Of
+ course you should not run an older reprepro with that repository
+ then, ever).
+
+2008-01-03 Bernhard R. Link <brlink@debian.org>
+ * tracking.c uses database.c instead of libdb directly
+
+2007-12-14 - 2007-12-23 Bernhard R. Link <brlink@debian.org>
+ * collect and advertise more checksums, though not yet stored
+
+2007-12-10 Bernhard R. Link <brlink@debian.org>
+ * support lzma compressed source packages
+
+2007-12-01 Bernhard R. Link <brlink@debian.org>
+ * beautify control data read from .deb or .dsc/.changes files:
+ remove all CR and make sure leading or trailing newlines do
+ not hurt.
+
+2007-11-27 Bernhard R. Link <brlink@debian.org>
+ * rewrite support for reading text files containing a single
+ chunk. (Release, .dsc, .changes). Unsigned .dsc and .changes
+ files are no longer routed through libgpgme.
+
+2007-11-24 Bernhard R. Link <brlink@debian.org>
+ * references.c uses database.c instead of accessing libdb directly
+
+2007-11-19 Bernhard R. Link <brlink@debian.org>
+ * mark more filedescriptors closeonexec,
+ support closefrom and F_CLOSEM when available.
+
+2007-11-18 Bernhard R. Link <brlink@debian.org>
+ * add sha1 hash calculation code
+ * add sha1 hashes of index files into Release files.
+ release.cache.db renmamed to release.caches.db due
+ to modified syntax.
+
+2007-10-31 Bernhard R. Link <brlink@debian.org>
+ * translatefilelists now can be run when both old
+ and new style filelists are there (this can happen
+ when it was translated and an old version of reprepro
+ was run over this database. You should not do this,
+ but when it happens, translatefilelists can be used
+ now instead of having to reextract the lists).
+
+2007-10-29 Bernhard R. Link <brlink@debian.org>
+ * If exporting a distribution fails, warn if something is left
+ in a state that needs manual exporting.
+
+2007-10-26 Bernhard R. Link <brlink@debian.org>
+ * change --export default from "normal" (now also available
+ under the name "lookedat") to "changed".
+
+2007-10-21 Bernhard R. Link <brlink@debian.org>
+ * warn against -A,-C,-T,-S or -P given to an action not
+ using it, with new --ignore=unusedoption to ignore this.
+
+2007-10-07 Bernhard R. Link <brlink@debian.org>
+ * change db/version file to final format,
+ abort if version or libdb version specified
+ there cannot be fulfilled.
+
+2007-09-27 Bernhard R. Link <brlink@debian.org>
+ * allow comments starting within lines in config files
+ * also allow tab as first character for continued lines as
+ manpage already says.
+
+2007-09-23 Bernhard R. Link <brlink@debian.org>
+ * save another 2 seconds while sorting filelists for Contents files
+
+2007-09-22 Bernhard R. Link <brlink@debian.org>
+ * make empty Architectures and Components fields
+ in conf/distributions an error.
+ * Contents: fields no longer has a rate value,
+ ContentsComponents/Architectures/UComponents
+ triggers or disables contents generation if non-/empty.
+ * empty Architecturs/Components/UdebComponents in
+ conf/updates and conf/pulls now mean nothing instead of all.
+ * minimal additional speedup when sorting filelists
+
+2007-09-21 Bernhard R. Link <brlink@debian.org>
+ * save cached filelists of packages for Contents files
+ in a preprocessed form, needing only about half the disk
+ space and only half the time when generating the Contents file.
+ * new translatefilelists command to translate old to new format
+ * filelists reading no longer available without libarchive
+
+2007-09-19 Bernhard R. Link <brlink@debian.org>
+ * files.c uses database.c instead of accessing libdb directly
+ * release.c uses database.c instead of accessing libdb directly
+
+2007-09-16 Bernhard R. Link <brlink@debian.org>
+ * add removesrc and removefilter action
+
+2007-09-15 Bernhard R. Link <brlink@debian.org>
+ * move package database handling from packages.c to database.c
+
+2007-09-14 Bernhard R. Link <brlink@debian.org>
+ * rereference now also refreshes references by tracking data.
+
+2007-09-13 Bernhard R. Link <brlink@debian.org>
+ * retrack no longer create track records for distributions with
+ tracking disabled, dumptracks no longer generated empty databases.
+ * removealltracks now also works on distributions no longer listed
+ in conf/distributions, no longer supports being used on all
+ distributions listed there (i.e. without argumnts)
+ * tidytracks not remove all tracking data from a distribution without
+ tracking activated.
+ * clearvanished removes tracking data from vanished distributions.
+ * in default --nofast mode, check for unexpected tracking data and
+ do not run, unless --ignore=undefinedtracking is defined
+ * retrack refreshes tracking information instead of destroying and
+ starting new.
+ * make update's ListHook relative to confdir
+ * low level part of the includelogs options added
+
+2007-09-11 Bernhard R. Link <brlink@debian.org>
+ * reject spaces and tabs in key-names (i.e. before :) in config files,
+ instead of bubbling about unknown fields.
+
+2007-09-10 Bernhard R. Link <brlink@debian.org>
+ * improve parsing of update's Config lines
+
+2007-09-09 Bernhard R. Link <brlink@debian.org>
+ * never hardlink index files, but copy them always into the lists
+ directory. (Should not make a difference yet, but feels safer).
+ * warn if update rules list components or architectures are always ignored
+
+2007-09-08 Bernhard R. Link <brlink@debian.org>
+ * warn if pull rules list components or architectures are always ignored
+
+2007-09-07 Bernhard R. Link <brlink@debian.org>
+ * create db/version
+ * always create all packages.db subtables, so future
+ versions can detect new architectures/components.
+
+2007-09-06 Bernhard R. Link <brlink@debian.org>
+ * read all distribution definitions before starting
+ any action.
+
+2007-09-04 Bernhard R. Link <brlink@debian.org>
+ * test number of arguments earlier.
+
+2007-09-03 Bernhard R. Link <brlink@debian.org>
+ * remove the dbdirs and all its parents created at startup
+ that are still empty at shutdown. (Does not make much difference
+ yet, as most commands create an empty file database in there.)
+ * obsolete --overridedir, overrides belong to conf dir like all
+ the other config files now.
+
+2007-09-02 Bernhard R. Link <brlink@debian.org>
+ * fix uninitialized use of errno in listclean.
+ (might cause update to report error opening dir: file exists)
+ * new config file parser
+ * remove --ignore from changestool, --ignore=shortkeyid from reprepro
+ * move to C99's bool, false and true
+
+2007-08-21 Bernhard R. Link <brlink@debian.org>
+ * ignore SIGPIPE, so that libgpgme cannot tear us apart
+ so easily.
+
+2007-08-20 Bernhard R. Link <brlink@debian.org>
+ * Print ignored signatures in Release.gpg files
+ when verbosity > 10
+
+2007-08-18 Bernhard R. Link <brlink@debian.org>
+ * stop dumpreferences output when Ctrl-c is received.
+
+2007-08-03 Bernhard R. Link <brlink@debian.org>
+ * add --without-libgpgme to compile without
+ gpgme support (checking and signing are then not
+ available, yet).
+
+2007-08-19 Bernhard R. Link <brlink@debian.org>
+ * [SECURITY] fix bug causing a Release.gpg with only
+ unknown signatures considered as properly signed.
+
+2007-07-28 Bernhard R. Link <brlink@debian.org>
+ * fix segfault in changestool's verify if
+ md5sum of .orig.tar.gz is wrong and not listed
+ in the .changes file.
+ * changestool's verify knows about epochs not showing
+ up in filenames now.
+
+2007-07-26 Bernhard R. Link <brlink@debian.org>
+ * add support for .changes file having the source
+ version in the Sources: header (like binNMUs) to the
+ include and processincoming commands.
+
+2007-07-22 Bernhard R. Link <brlink@debian.org>
+ * include[u]deb allows multiple files to include now
+
+2007-06-25 Bernhard R. Link <brlink@debian.org>
+ * don't complain if suite name and component name are
+ the same in createsymlinks
+
+2007-06-24 Bernhard R. Link <brlink@debian.org>
+ * processincoming allows an optional second argument
+ to limit processing to a specific file for better
+ integration with inoticoming.
+
+2007-06-16 Bernhard R. Link <brlink@debian.org>
+ * when checking a file to have the expected checksum,
+ first check if the file size matches before calculating
+ its md5sum.
+
+2007-06-11 Bernhard R. Link <brlink@debian.org>
+ * detect "false" and "no" as false in boolean headers.
+ (Until now only existence was tested and considered as
+ true, which broke apt-methods telling "Send-Config: false")
+
+2007-06-10 Bernhard R. Link <brlink@debian.org>
+ * don't waste filedescriptors by not closing .done-files
+
+2007-06-09 Bernhard R. Link <brlink@debian.org>
+ * set GPG_TTY when unset and stdin is a terminal.
+ (and new option --noguessgpgtty to suppress this)
+
+2007-06-03 Bernhard R. Link <brlink@debian.org>
+ * fix segfault when running processincoming without notificators
+ (Thanks to Julien Valroff for finding this)
+
+2007-06-02 Bernhard R. Link <brlink@debian.org>
+ * rename --checkspace to --spacecheck, as
+ manpage and error messages hint to that.
+ * fix 64bit problem in errormessages for Log:
+
+2007-05-29 Bernhard R. Link <brlink@debian.org>
+ * adapt name include uses for .changes files to
+ that of processincoming.
+
+2007-05-25 Bernhard R. Link <brlink@debian.org>
+ * some fixed and improvements of the free space calculation
+ ( add --spacecheck, --safetymargin, --dbsafetymargin )
+
+2007-05-24 Bernhard R. Link <brlink@debian.org>
+ * error/warn if trying to include a package via
+ processincoming which is already there newer
+ * do not notify a .changes when no package included
+ (when using Log: --changes)
+ * add Permit: unused_files older_version
+ and Cleanup: unused_files on_deny on_error for conf/incoming
+ * add --waitforlock option
+
+2007-05-23 Bernhard R. Link <brlink@debian.org>
+ * fix remove action not tidy tracked packages.
+ (Thanks to Dan Pascu for finding this, too)
+ * rename cleartracks in removealltracks
+ * new tidytracks command
+
+2007-05-22 Bernhard R. Link <brlink@debian.org>
+ * Add per distribution notification scripts for accepted changes files.
+
+2007-05-21 Bernhard R. Link <brlink@debian.org>
+ * fix problem of not waiting for notificators in some commands
+ (Thanks to Dan Pascu for finding this)
+
+2007-05-07 Bernhard R. Link <brlink@debian.org>
+ * move some code from release.c to signature.c in preperation of
+ later changes
+
+2007-05-06 Bernhard R. Link <brlink@debian.org>
+ * changestool: add adddsc command
+ * changestool: add --create option
+ * changestool: add add command
+ * changestool: add setdistribution command
+
+2007-05-03 Bernhard R. Link <brlink@debian.org>
+ * changestool: add addrawfile command
+
+2007-04-03 Bernhard R. Link <brlink@debian.org>
+ * first code for checking for enough free space
+
+2007-03-29 Bernhard R. Link <brlink@debian.org>
+ * add rerunnotifiers command
+
+2007-03-28 Bernhard R. Link <brlink@debian.org>
+ * add support logging to external notificators
+ (including example to create changelog/ hierachy)
+
+2007-03-26 Bernhard R. Link <brlink@debian.org>
+ * fix bug in term parsing not accepting '<<'
+
+2007-03-23 Bernhard R. Link <brlink@debian.org>
+ * first part of logging code
+
+2007-03-16 Bernhard R. Link <brlink@debian.org>
+ * fix bug not recognizing already existing .bz2 files
+ when exporting only changes.
+ * more changes in verbose output
+
+2007-03-15 Bernhard R. Link <brlink@debian.org>
+ * more output to stdout instead of stderr
+
+2007-03-14 Bernhard R. Link <brlink@debian.org>
+ * processincoming only exports distributions looked at
+ with --export=always (the default) and not every distribution.
+ (other commands should not have changed)
+ * changed output of many status messages to stdout instead of stderr
+ * changed verbosity level needed to see some messages
+
+2007-03-12 Bernhard R. Link <brlink@debian.org>
+ * add --silent option
+ * change some status output to stdout instead of stderr.
+
+2007-02-26 Bernhard R. Link <brlink@debian.org>
+ * add gensnapshot command
+
+2007-02-23 Bernhard R. Link <brlink@debian.org>
+ * rename import to processincoming
+ * describe in manpage
+ * update bash completion example
+
+2007-02-11 Bernhard R. Link <brlink@debian.org>
+ * fix bug in non-libarchive filelist extraction with long
+ filelists
+
+2007-01-25 Bernhard R. Link <brlink@debian.org>
+ * import allow .changes files with multiple distributions
+
+2007-01-21 Bernhard R. Link <brlink@debian.org>
+ * add trackingsupport to "import" command
+
+2007-01-17 Bernhard R. Link <brlink@debian.org>
+ * fail cleanly when getting a .dsc without Format header
+
+2007-01-16 Bernhard R. Link <brlink@debian.org>
+ * improve error message of missing Files: line in .dsc files
+
+2007-01-12 Bernhard R. Link <brlink@debian.org>
+ * add AlsoAcceptFor for distributions
+
+2007-01-06 Bernhard R. Link <brlink@debian.org>
+ * incoming fixups and more testcases
+ * omit some warnings about versions not starting
+ with a digit
+
+2007-01-05 Bernhard R. Link <brlink@debian.org>
+ * better cope with double entries in some
+ lists. (Like Architectures or Components)
+ * incoming fixups and more testcases
+
+2007-01-04 Bernhard R. Link <brlink@debian.org>
+ * more fixups of incoming handling
+
+2007-01-03 Bernhard R. Link <brlink@debian.org>
+ * factor some checkindeb code into binaries.c
+ * incoming.c uses now only binaries.c and not checkindeb.c
+ in preperation of different semantics to come.
+
+2007-01-02 Bernhard R. Link <brlink@debian.org>
+ * factor some checkindsc code into source.c
+ * add dsc support for import from incoming
+
+2007-01-01 Bernhard R. Link <brlink@debian.org>
+ * move uploaderslist load into distribution struct
+ * fix bug in manpage: uploaders list keyword is allow and not accept
+ * some more code for incoming processing
+
+2006-12-31 Bernhard R. Link <brlink@debian.org>
+ * first code for importing from an incoming dir, not
+ yet useable (supports no source, no overrides, no ... yet)
+ * move loaded overrides into distribution struct.
+
+2006-12-17 Bernhard R. Link <brlink@debian.org>
+ * tell about the filename in the non-libarchive
+ case of failure to extract control or filelist
+ from a .deb
+ * add _fakeemptyfilelist action to omit a file
+ when generting Content files.
+
+2006-11-28 Bernhard R. Link <brlink@debian.org>
+ * mostly rewrote "adddeb"
+
+2006-11-27 Bernhard R. Link <brlink@debian.org>
+ * add "adddeb" option to changestool
+
+2006-10-31 Bernhard R. Link <brlink@debian.org>
+ * fix spelling mistakes in manpage (thanks to A. Costa)
+ fixed the same errors in the code and its messages
+
+2006-10-29 Bernhard R. Link <brlink@debian.org>
+ * fix updatechecksums for .changes files not
+ listing entries from the .dsc
+
+2006-10-11 Bernhard R. Link <brlink@debian.org>
+ * add Uploaders: rule to conf/distributions to
+ limit include to .changes files signed with specific keys.
+
+2006-10-07 Bernhard R. Link <brlink@debian.org>
+ * only show control information of to be added packages
+ in checkpull/checkupdate with -V
+ * fixed a missed refcount increasing in yesterdays code
+ * give hints where to look when gpgme reports no error on
+ failure
+
+2006-10-06 Bernhard R. Link <brlink@debian.org>
+ * FilterList in update and pull rules now
+ is a space separated list of files.
+
+2006-10-03 Bernhard R. Link <brlink@debian.org>
+ * fix typos and spelling errors in manpage (Thanks to Bruce Sass)
+ * fix type-mismatch to silence compiler-warning
+ * work around signing problems in gpgme11, fix some memory holes
+
+2006-10-01 Bernhard R. Link <brlink@debian.org>
+ * new includeallsources command for changestool
+ to change a .changes as if it was created with -sa
+
+2006-09-30 Bernhard R. Link <brlink@debian.org>
+ * new updatechecksums command for changestool
+
+2006-09-24 Bernhard R. Link <brlink@debian.org>
+ * ported to libgpgme11
+ * removed --onlyacceptsigned
+
+2006-09-20 Bernhard R. Link <brlink@debian.org>
+ * make strlist_init void
+
+2006-09-19 Bernhard R. Link <brlink@debian.org>
+ * rename modifychanges to changestool
+
+2006-09-17 Bernhard R. Link <brlink@debian.org>
+ * fix return of fingerprints in new signature handling code
+ * move endswith from main.c to names.h
+ * add modifychanges helper program (yet only validating some stuff)
+
+2006-09-12 Bernhard R. Link <brlink@debian.org>
+ * reject .changes with binaries not listed, unless --ignore=surprisingbinary
+ * reject .changes with .dsc or .deb with wrong source version
+ unless --ignore=wrongversion or --ignore=wrongsourceversion
+ * earlier and better error message if source name differs from the one
+ given in the .changes file.
+
+2006-09-11 Bernhard R. Link <brlink@debian.org>
+ * new strlist_add_dup
+ * more fine tuned signature checking (one valid signature suffices)
+ * fix a little memory hole in tracking code
+
+2006-09-07 Bernhard R. Link <brlink@debian.org>
+ * fix some typos (thanks to Jordi Mallach for noting)
+
+2006-09-04 Bernhard R. Link <brlink@debian.org>
+ * support .orig.tar.bz2 .tar.bz2 and .diff.bz2 in source packages
+ * fix bug, causing Contents-* files containing only the first file
+ of a package when this is the first time this package is accessed
+
+2006-08-22 Bernhard R. Link <brlink@debian.org>
+ * fix db3 mention in reprepro.1
+
+2006-08-05 Bernhard R. Link <brlink@debian.org>
+ * some error/status/debug messages improved a little
+
+2006-08-03 Bernhard R. Link <brlink@debian.org>
+ * improve messages when missing files (.tar.gz most likely)
+
+2006-07-28 Bernhard R. Link <brlink@debian.org>
+ * remove unreferenced files when doing removetracks
+ * fix bug omitting an uncompressed Sources entry in
+ Release files when only exporting changed values and
+ the source part changed not. (Thanks to Alexander Kuehn
+ for finding this one).
+ * fix tiny memory in clearvanished
+
+2006-07-26 Bernhard R. Link <brlink@debian.org>
+ * do not error out if one file gets unreferenced by two different
+ reasons at the same time.
+ * implement "minimal" and "all" tracking support for packages losing
+ files because of getting replaced by newer ones...
+
+2006-07-23 Bernhard R. Link <brlink@debian.org>
+ * rewrite some parts of tracking support, implement
+ "minimal" and "all" methods...
+
+2006-07-18 Bernhard R. Link <brlink@debian.org>
+ * fix segfault in non-libarchive control extraction code
+ introduced with the last change
+
+2006-07-16 Bernhard R. Link <brlink@debian.org>
+ * cope with control.tar.gz files without leading ./
+ when not using libarchive.
+
+2006-07-15 Bernhard R. Link <brlink@debian.org>
+ * cope with GNU style ar files when using libarchive
+ (i.e. with .deb files not generated by dpkg-deb)
+
+2006-07-08 Bernhard R. Link <brlink@debian.org>
+ * add clearvanished command
+
+2006-06-21 Bernhard R. Link <brlink@debian.org>
+ * add copy command to pull only a specific package
+ without having to add FilterFormulas to conf/pulls
+ (and also a bit faster)
+
+2006-06-19 Bernhard R. Link <brlink@debian.org>
+ * add predelete action to remove packages from
+ a distribution that would be deleted or replaced
+ by a command.
+
+2006-06-18 Bernhard R. Link <brlink@debian.org>
+ * check for file conflicts and missing files when including
+ .changes files before copying/moving files into the pool
+ (Files missing in .dsc and files having the wrong md5sum
+ are still only noticed after/while moving them in the pool)
+ * delete files from the pool when checks after including
+ the files but before including the packages failed.
+
+2006-06-16 Bernhard R. Link <brlink@debian.org>
+ * manpage mentions includeudeb now. (Thanks to Jordi Mallach for noting)
+ * changed manpage to make clear options are before the command (dito)
+ * catch TERM, ABRT, INT and QUIT and do not start any new stuff after
+ that.
+ * remove force option (rarely worked and caused ugly bugs otherwise)
+
+2006-06-12 Bernhard R. Link <brlink@debian.org>
+ * some prework for predelete action
+
+2006-06-01 Bernhard R. Link <brlink@debian.org>
+ * better usage description in tiffany.example
+ * fix the fix for the export preprocessor
+
+2006-05-30 Bernhard R. Link <brlink@debian.org>
+ * fix bug in communication with Index file preprocessor
+ (so the .diff directories tiffany.example creates are
+ properly advertised so that apt-get can use them)
+
+2006-05-15 Bernhard R. Link <brlink@debian.org>
+ * warn against dobuled fields in
+ config files. (ignorable with --ignore=doublefield)
+ * better error message when trying to forget
+ filekey not existing
+
+2006-05-14 Bernhard R. Link <brlink@debian.org>
+ * add support for libdb4.3 and libdb4.4,
+ default is libdb4.4 now.
+
+2006-05-13 Bernhard R. Link <brlink@debian.org>
+ * add support for contents file when compiled
+ without libarchive.
+
+2006-05-12 Bernhard R. Link <brlink@debian.org>
+ * add content file generation
+
+2006-05-07 Bernhard R. Link <brlink@debian.org>
+ * add support for extracting filelists from
+ Debian packages for future usage and a
+ __extractfilelist action. (only available when
+ compiled with libarchive)
+
+2006-05-06 Bernhard R. Link <brlink@debian.org>
+ * add support for using libarchive to get the
+ control file out of a .deb instead of calling
+ ar and tar.
+
+2006-05-03 Bernhard R. Link <brlink@debian.org>
+ * add new pull and checkpull actions
+ * repair checkupdate statistics of newest available
+ version of checkupdate when using delete rules.
+ (Showed 'unavailable for reload').
+ * fix segfault and memory leak in checkupdate
+ * fix including a changes file with source and restricting
+ to some binary distribution or to binary package type.
+ * add some warnings against impossible combinations of -T and -A
+
+2006-04-29 Bernhard R. Link <brlink@debian.org>
+ * fix some minor memory leaks
+
+2006-04-28 Bernhard R. Link <brlink@debian.org>
+ * rewrite decision for exporting distributions a bit:
+ export all distributions that did not have errors by default
+ (it did not export anything when an error occurred)
+ added new --export option with possible values
+ never, changed, normal and forced.
+
+2006-04-25 Bernhard R. Link <brlink@debian.org>
+ * do not export indices if all upgrades were skipped
+
+2006-04-23 Bernhard R. Link <brlink@debian.org>
+ * unbreak new skipold for delete rules
+
+2006-04-22 Bernhard R. Link <brlink@debian.org>
+ * explicitly save which files are already
+ processed and to be skipped by --skipold.
+
+2006-04-11 Bernhard R. Link <brlink@debian.org>
+ * tell the user running gpg manually sometimes
+ resolves problems while calling it through libgpgme
+ does not help.
+ * add a WORKAROUND part to the manpage
+
+2006-04-09 Bernhard R. Link <brlink@debian.org>
+ * remove the woody reference in signature.c
+
+2006-03-30 Bernhard R. Link <brlink@debian.org>
+ * warn about architectures called 'all'
+
+2006-02-25 Bernhard R. Link <brlink@debian.org>
+ * add --ignore=missingfile to look for .orig.tar.gz
+ files of broken .changes (no -sa though needed) files
+ in the directory of the .changes file.
+
+2006-02-20 Bernhard R. Link <brlink@debian.org>
+ * add optional "NotAutomatic" field for the
+ distribution specification.
+
+2006-02-10 Bernhard R. Link <brlink@debian.org>
+ * add new --ignore=extension, without which
+ it refuses to 'include' files not ending in '.changes',
+ to 'include[u]deb' files not ending in '.[u]deb' or to
+ 'includedsc' files not ending '.dsc'.
+
+2006-01-21 Bernhard R. Link <brlink@debian.org>
+ * fix typesetting error in ratpoison.1
+ and add an example for update's Config option.
+ * fix segfault of FD_ISSET(-1,&...) when
+ method is not used (i.e. --nolistsdownload
+ and only need to get from other sources)
+ * fix minor memory leak of --skipold
+
+2005-12-24 Bernhard R. Link <brlink@debian.org>
+ * add cache database to store md5sums
+ of released files in there.
+
+2005-12-23 Bernhard R. Link <brlink@debian.org>
+ * Implement native .bz2 compression
+ (only when libbz2.so was available at build time)
+
+2005-12-22 Bernhard R. Link <brlink@debian.org>
+ * fix some spelling errors
+ (thanks to Guilherme de S. Pastore for notifying me)
+
+ * make index exportion code more low level, allowing
+ in-place md5sum calculation without needing to reread
+ the generated files.
+
+ * fix problem of bzip2.example script
+
+2005-12-20 Bernhard R. Link <brlink@debian.org>
+ * refactor index exporting/release generation
+ so that is always puts the uncompressed checksums
+ in the Release file.
+ * reverting the changes from 2005-12-15
+ (i.e. again not writing uncompressed Sources
+ by default, as the checksum now shows up
+ in the Release file anyway, as apt needs it)
+ * {Dsc,Deb,UDeb}Indices' external programs
+ are now only called with the uncompressed files.
+
+2005-12-19 Bernhard R. Link <brlink@debian.org>
+ * fix segfault introduced into interatedupdate
+ by --skipold.
+
+2005-12-18 Bernhard R. Link <brlink@debian.org>
+ * split Release reading from release.c to readrelease.c
+
+2005-12-15 Bernhard R. Link <brlink@debian.org>
+ * Generate uncompressed source/Sources by default.
+
+2005-12-11 Bernhard R. Link <brlink@debian.org>
+ * Unless the new --noskipold is used,
+ only targets with newly downloaded index
+ files are updated.
+
+2005-12-10 Bernhard R. Link <brlink@debian.org>
+ * remove pool-directories gotten empty
+ (thanks to Julien Valroff for suggesting this)
+ * new --keepdirectories option to not try this
+
+2005-10-27 Bernhard R. Link <brlink@debian.org>
+ * add colons in description within bzip.example
+ (thanks to Steve Kemp for finding this)
+
+2005-10-05 Bernhard R. Link <brlink@debian.org>
+ * add --ignore=missingfield,brokenold,brokenversioncmp,
+ unusedarch,surpisingarch
+
+2005-10-03 Bernhard R. Link <brlink@debian.org>
+ * replace readdir_r by readdir to be sure errno is
+ set properly.
+
+2005-10-02 Bernhard R. Link <brlink@debian.org>
+ * some cleanups (strict truthvalue-typing
+ and some integer signednesses...)
+
+2005-09-28 Bernhard R. Link <brlink@debian.org>
+ * Fix segfault when update file is empty.
+ (Thanks to Gianluigi Tiesi for noticing this.)
+
+2005-09-26 Bernhard R. Link <brlink@debian.org>
+ * Document override files' format in manpage
+ * Fix integer size in tracking data handling
+
+2005-09-25 Bernhard R. Link <brlink@debian.org>
+ * Documenting --ignore in manpage
+ * some clarifications in manpage
+
+2005-09-24 Bernhard R. Link <brlink@debian.org>
+ * putting a .changes in the wrong distribution
+ is an error now without --ignore=wrongdistribution
+ * puttin new address in GPL notices, redownload
+ COPYING (fixing some typos and addresses)
+
+2005-09-22 Bernhard R. Link <brlink@debian.org>
+ * add --unignore (with alias --noignore)
+ to allow overwriting ignore in config.
+
+2005-09-06 Bernhard R. Link <brlink@debian.org>
+ * fix error in parsing FilterList default action
+ (thanks to Sergio Talens-Oliag for finding that)
+
+2005-08-28 Bernhard R. Link <brlink@debian.org>
+ * add REPREPRO_CONFIG_DIR
+
+2005-08-26 Bernhard R. Link <brlink@debian.org>
+ * read conf/options for default command line options,
+ use REPREPRO_BASE_DIR for default -b value, add --no
+ options to disable previously enabled options again.
+ * add a createsymlinks command to create suite->codename
+ symlinks
+
+2005-08-05 Bernhard R. Link <brlink@debian.org>
+ * do not set execute bit of signed files
+
+2005-08-02 Bernhard R. Link <brlink@debian.org>
+ * allow ~ in versions listed within .changes
+ * changed spacing in dpkgversions.c to make
+ comparing to originals in dpkg easier.
+
+2005-07-20 Bernhard R. Link <brlink@debian.org>
+ * read SignWith:-argument and give it to
+ libgpgme to decide which key to use.
+
+2005-07-05 Bernhard R. Link <brlink@debian.org>
+ * Document tracking
+
+2005-07-03 Bernhard R. Link <brlink@debian.org>
+ * add quick&dirty --ask-passphrase option
+
+2005-06-18 Bernhard R. Link <brlink@debian.org>
+ * add tracking.c and some starting functionality
+ * therefor refactored .deb and .dsc inclusion
+ so that .changes includsion can check those
+ better before doing anything.
+ * some little tidy ups (freeing more memory,
+ fixing bad english
+
+2005-06-02 Bernhard R. Link <brlink@debian.org>
+ * Change default basedir to "."
+
+2005-05-31 Bernhard R. Link <brlink@debian.org>
+ * Fix bogus free causing segfaults
+ * No longer silently ignore additional arguments with include*
+
+2005-05-13 Bernhard R. Link <brlink@debian.org>
+ * add Fallback option to update-methods.
+
+2005-04-16 Bernhard R. Link <brlink@debian.org>
+ * fix broken fix in signature.c from 2005-04-10
+ * fix bug when after a delete rule the second
+ origin has the version already in an archive
+
+2005-04-12 Bernhard R. Link <brlink@debian.org>
+ * fix same more warnings
+
+2005-04-10 Bernhard R. Link <brlink@debian.org>
+ * apply some clean ups:
+ - distinguish between boolean and non-boolean values
+ - split globals from error.h in globals.h
+ * fix bug in signature.c to not treat config error like valid key.
+
+2005-04-07 Bernhard R. Link <brlink@debian.org>
+ * fix wrong handling of bugs in update specifications
+ * adopt short-howto to present
+ * fix typo in manpage
+
+2005-04-05 Bernhard R. Link <brlink@debian.org>
+ * create files without executeable bit set
+ when copying files.
+
+2005-03-29 Bernhard R. Link <brlink@debian.org>
+ * iteratedupdate directly exports indices instead
+ of all at the end...
+
+2005-03-28 Bernhard R. Link <brlink@debian.org>
+ * Implement "interatedupdate" command, which iterates the
+ distributions and targets within them, instead of first
+ downloading all lists, then processing all lists, then
+ downloading all packages and then installing them all.
+ (This can be a bit slower, but needs less memory)
+
+ * Two --force are needed to ignore wrong Release.gpg
+
+2005-03-27 Bernhard R. Link <brlink@debian.org>
+ * Implement ".tobedeleted" feature for
+ export skripts.
+
+2005-03-22 Bernhard R. Link <brlink@debian.org>
+ * Repeat that there were errors at the
+ end of reprepro.
+
+2005-03-11 Bernhard R. Link <brlink@debian.org>
+ * Do not accept multiple -A,-C,-T,-S or -Ps.
+
+2005-03-02 Bernhard R. Link <brlink@debian.org>
+ * Change Override/SrcOverride to
+ DebOverride/UDebOverride/DscOverride
+
+ * add new command reoverride to reapply
+ overrides to all packages.
+
+2005-02-20 Bernhard R. Link <brlink@debian.org>
+ * add docs/tiffany.example, which generates
+ apt-qupdate'able .diff directories.
+
+ * Many small changes to make splint more
+ happy. (Mostly annotations, some clearance
+ and some fixes of memory holes or possible
+ segfaults if running out of memory)
+
+2005-02-19 Bernhard R. Link <brlink@debian.org>
+ * Refactor Index Exporting and Release generation
+ to reduce the time Release files and Package indices
+ are out of sync (Everything is written to files
+ ending in .new now, only when everything is ready
+ all are moved to their final place) and to prepare
+ DebIndices UDebIndices and DscIndices Options.
+
+ * add another test-case
+ * FIX the overflow bug in chunks_replacefield
+
+ * add DebIndices UDebIndices and DscIndices
+ options for conf/distributions. This allows
+ to change which Indices to generate for this
+ type, or calls hook to even generate additional
+ ones. (See docs/bzip.example).
+
+2005-02-14 Bernhard R. Link <brlink@debian.org>
+ * Some little changes to make splint
+ and valgrind happier.
+
+2005-02-13 Bernhard R. Link <brlink@debian.org>
+ * Remove some code duplication in main.c
+ (and renamed _md5sums to _listmd5sums)
+ * change -b to not overwrite prior given
+ --listdir --distdir ...
+
+2005-02-12 Bernhard R. Link <brlink@debian.org>
+ * Some clean up of the code and added some
+ paranoia checks.
+
+2005-02-10 Bernhard R. Link <brlink@debian.org>
+ * No longer shutdown aptmethods when nothing is to do.
+ (This caused problems when index files are already in
+ place but still packages to be downloaded).
+
+ * Do not warn about deleting _changed files from listdir.
+
+2005-02-08 Bernhard R. Link <brlink@debian.org>
+ * Do some more checks reading signed sources.
+
+ * Release 0.1.1
+
+2005-02-07 Bernhard R. Link <brlink@debian.org>
+ * Fix --onlyacceptsigned to safely handle unknown
+ keys or multiple keys of different state.
+
+2005-02-06 Bernhard R. Link <brlink@debian.org>
+ * Release 0.1
+
+2005-02-05 Bernhard R. Link <brlink@debian.org>
+ * Add --onlyacceptsigned to make include and includedsc only
+ accept signed files.
+
+ * Check Codename, Components and Architectures fields
+ of conf/distributions for sane values
+ * fix checks for strange characters
+
+2005-02-03 Bernhard R. Link <brlink@debian.org>
+ * When updating delete files lists/<codename>_ for
+ all updated distributions, which will not be needed any more.
+
+2005-02-01 Bernhard R. Link <brlink@debian.org>
+ * Add some missing files in Makefile.am so they end up in dist
+ * Add some #includes so that it also compiles without
+ warnings on sarge/i386
+
+ * --ignore= allows multiple options separated by commas.
+
+ * Tell about -b if conf/distributions cannot be found
+
+ * Tell which release.gpg file is missing the signature.
+
+ * Some tidy up to reduce number of warnings with -W
+
+ * Allow multiple keys specified in update's ReleaseCheck
+
+2005-01-29 Bernhard R. Link <brlink@debian.org>
+ * Be more descriptive with missing signatures.
+
+2005-01-28 Bernhard R. Link <brlink@debian.org>
+ * readd _detect command
+ * write recovery HOWTO how to deal with database corruptions
+
+2005-01-27(at least GMT) Bernhard R. Link <brlink@debian.org>
+ * add a lockfile
+
+2005-01-26 Bernhard R. Link <brlink@debian.org>
+ * change FilterList to need a defaultaction given
+
+ * tidy up upgradelist.c and report errors properly
+
+ * ListHook is also called when --nolistsdownload is given
+
+ * update/checkupdate only download lists not already here
+
+2005-01-25 Bernhard R. Link <brlink@debian.org>
+ * Add ListHook keyword for external processing
+ of the downloaded index file before updating.
+
+ * Add FilterList keyword for a list in the
+ format of dpkg --get-selections
+
+2005-01-24 Bernhard R. Link <brlink@debian.org>
+ * Make includedeb work again.
+
+ * Fix bugs in override file parsing
+
+ * add a listfilter command
+ * fix bug in term evaluation with non-existing fields
+ * fix another parsing bug when too few spaces where around
+ * implement T_NEGATED flag of parsing
+ * document listfilter command
+
+ * check conf/distributions conf/updates for unknown fields
+ (to rule out typos, lines with # are ignored)
+
+2005-01-22 Bernhard R. Link <brlink@debian.org>
+ * Make -T work everywhere -A works.
+ * rename variables from suffix to packagetype
+
+ * allow colons in .changes filenames.
+ (epoch with colon is stripped, but
+ colons after that are allowed)
+
+ * Add tests/test.sh to test for basic
+ things to work...
+
+ * fix bug that prevented Release regeneration
+ when a index-file is changed to zero entries.
+
+2005-01-19 Bernhard R. Link <brlink@debian.org>
+ * now also include, includedeb, includedsc
+ and update will remove files which are no
+ longer needed due to newer versions available,
+ except when --keepunreferencedfiles is given.
+
+ * change some verbosities of files and refereces
+
+2005-01-17 Bernhard R. Link <brlink@debian.org>
+ * remove short options -e -N -l -r -M -d -D -c -p -o
+ to make it more guessable (and reserving short options
+ for important and likely often called functions).
+
+ * add --keepunreferencedfile option (if you think
+ this is long, remember GNU getopt_long will accept
+ --keep, too)
+
+2005-01-15 Bernhard R. Link <brlink@debian.org>
+ * Seperate parsing and looking for allowed
+ values a bit more. Some more things can
+ be ignored with --ignore now.
+
+ * includedsc and includedeb only export
+ files that changed.
+
+ * remove now deletes files of removed packages
+ not referenced by any other package.
+
+2005-01-10 Bernhard R. Link <brlink@debian.org>
+ * Made updates using --force with failing parts
+ more graceful
+
+ * Make aptmethods less verbose
+
+2005-01-07 Bernhard R. Link <brlink@debian.org>
+ * Changed the meaning of the "Architectures:"
+ field in conf/distributions. Now a distribution
+ will have sources exactly when a "source" is in
+ this line.
+
+2005-01-05 Bernhard R. Link <brlink@debian.org>
+ * Only generate Release (and Release.gpg) files when
+ something changed.
+
+ * Add a --nolistsdownload option to avoid update and
+ checkupdate downloading all those lists again.
+
+2005-01-04 Bernhard R. Link <brlink@debian.org>
+ * Several code clean-ups, should not change anything....
+
+2004-12-30 Bernhard R. Link <brlink@debian.org>
+ * Tidy up (introduce bool_t and replace dpkgversion_isNewer)
+
+ * add a magic rule minus ("-") to mark all packages to be
+ deleted.
+
+ * add a checkupdate command to show what would be done.
+
+2004-12-24 Bernhard R. Link <brlink@debian.org>
+ * Fixed a boolean inversion in the check if | is allowed
+ in formulas.
+
+ * added FilterFormula to docs/reprepro.1
+
+2004-12-19 Bernhard R. Link <brlink@debian.org>
+
+ * change parsing of conf/distributions, the fields only
+ copied to Release files can be omitted now. Additional
+ it warns if required fields are missing intead of
+ silently ignoring this block...
+
+2004-12-18 Bernhard R. Link <brlink@debian.org>
+
+ * remove now tells which packages were removed (with -v)
+ and which could not be deleted. Indicies will only
+ be exported when something was deleted.
+
+2004-12-18 Bernhard R. Link <brlink@debian.org>
+
+ * Modify remove to allow -T to specify the
+ type (deb,dsc,udeb) to delete from.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..c2dd930
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,192 @@
+Build-Dependencies:
+ libdb3, libdb4.x or libdb5.x
+ libz
+Optional Dependencies:
+ libgpgme >= 0.4.1 (In Debian libgpgme11-dev, NOT libgpgme-dev)
+ libbz2
+ libarchive
+When Building from git:
+ autoconf2.50 (autoconf 2.13 will not work)
+
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..bb55266
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,47 @@
+SUBDIRS = docs tests
+
+EXTRA_DIST = autogen.sh
+
+bin_PROGRAMS = reprepro changestool rredtool
+
+if HAVE_LIBARCHIVE
+ARCHIVE_USED = ar.c debfile.c
+ARCHIVE_CONTENTS = debfilecontents.c
+ARCHIVE_UNUSED = extractcontrol.c
+else
+ARCHIVE_USED = extractcontrol.c
+ARCHIVE_CONTENTS =
+ARCHIVE_UNUSED = ar.c debfile.c debfilecontents.c
+endif
+
+AM_CPPFLAGS = $(ARCHIVECPP) $(DBCPPFLAGS)
+reprepro_LDADD = $(ARCHIVELIBS) $(DBLIBS)
+changestool_LDADD = $(ARCHIVELIBS)
+
+reprepro_SOURCES = outhook.c descriptions.c sizes.c sourcecheck.c byhandhook.c archallflood.c needbuild.c globmatch.c printlistformat.c diffindex.c rredpatch.c pool.c atoms.c uncompression.c remoterepository.c indexfile.c copypackages.c sourceextraction.c checksums.c readtextfile.c filecntl.c sha1.c sha256.c configparser.c database.c freespace.c hooks.c log.c changes.c incoming.c uploaderslist.c guesscomponent.c files.c md5.c dirs.c chunks.c reference.c binaries.c sources.c checks.c names.c dpkgversions.c release.c mprintf.c updates.c strlist.c signature_check.c signedfile.c signature.c distribution.c checkindeb.c checkindsc.c checkin.c upgradelist.c target.c aptmethod.c downloadcache.c main.c override.c terms.c termdecide.c ignore.c filterlist.c exports.c tracking.c optionsfile.c donefile.c pull.c contents.c filelist.c $(ARCHIVE_USED) $(ARCHIVE_CONTENTS)
+EXTRA_reprepro_SOURCE = $(ARCHIVE_UNUSED)
+
+changestool_SOURCES = uncompression.c sourceextraction.c readtextfile.c filecntl.c tool.c chunkedit.c strlist.c checksums.c sha1.c sha256.c md5.c mprintf.c chunks.c signature.c dirs.c names.c $(ARCHIVE_USED)
+
+rredtool_SOURCES = rredtool.c rredpatch.c mprintf.c filecntl.c sha1.c
+
+noinst_HEADERS = outhook.h descriptions.h sizes.h sourcecheck.h byhandhook.h archallflood.h needbuild.h globmatch.h printlistformat.h pool.h atoms.h uncompression.h remoterepository.h copypackages.h sourceextraction.h checksums.h readtextfile.h filecntl.h sha1.h sha256.h configparser.h database_p.h database.h freespace.h hooks.h log.h changes.h incoming.h guesscomponent.h md5.h dirs.h files.h chunks.h reference.h binaries.h sources.h checks.h names.h release.h error.h mprintf.h updates.h strlist.h signature.h signature_p.h distribution.h debfile.h checkindeb.h checkindsc.h upgradelist.h target.h aptmethod.h downloadcache.h override.h terms.h termdecide.h ignore.h filterlist.h dpkgversions.h checkin.h exports.h globals.h tracking.h trackingt.h optionsfile.h donefile.h pull.h ar.h filelist.h contents.h chunkedit.h uploaderslist.h indexfile.h rredpatch.h diffindex.h package.h
+
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in $(srcdir)/configure $(srcdir)/stamp-h.in $(srcdir)/aclocal.m4 $(srcdir)/config.h.in
+
+clean-local:
+ -rm -rf autom4te.cache $(srcdir)/autom4te.cache
+
+maintainer-clean-local:
+ -rm -rf $(srcdir)/ac
+
+# Some things for my private laziness
+strictbooleancheck:
+ /home/brl/gcc/b/gcc/cc1 -DHAVE_CONFIG_H -I/home/brl/gcc/b/gcc/include -I/usr/include -I. -Wall -DAVOID_CHECKPROBLEMS=1 -g -W -O2 *.c
+
+SPLINT=splint
+SPLITFLAGSFORVIM= -linelen 10000 -locindentspaces 0
+SPLINTFLAGS= +posixlib -booltype bool -numabstractcast -fixedformalarray -enumint +enumindex +charint $(SPLITFLAGSFORVIM) $(EXTRASPLINTFLAGS)
+
+splint:
+ $(SPLINT) -DSPLINT=1 $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) -D_GNU_SOURCE=1 $(SPLINTFLAGS) $(foreach file,$(reprepro_SOURCES),$(srcdir)/$(file))
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..31d8941
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,1258 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+bin_PROGRAMS = reprepro$(EXEEXT) changestool$(EXEEXT) \
+ rredtool$(EXEEXT)
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+ $(am__configure_deps) $(noinst_HEADERS) $(am__DIST_COMMON)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am__changestool_SOURCES_DIST = uncompression.c sourceextraction.c \
+ readtextfile.c filecntl.c tool.c chunkedit.c strlist.c \
+ checksums.c sha1.c sha256.c md5.c mprintf.c chunks.c \
+ signature.c dirs.c names.c extractcontrol.c ar.c debfile.c
+@HAVE_LIBARCHIVE_FALSE@am__objects_1 = extractcontrol.$(OBJEXT)
+@HAVE_LIBARCHIVE_TRUE@am__objects_1 = ar.$(OBJEXT) debfile.$(OBJEXT)
+am_changestool_OBJECTS = uncompression.$(OBJEXT) \
+ sourceextraction.$(OBJEXT) readtextfile.$(OBJEXT) \
+ filecntl.$(OBJEXT) tool.$(OBJEXT) chunkedit.$(OBJEXT) \
+ strlist.$(OBJEXT) checksums.$(OBJEXT) sha1.$(OBJEXT) \
+ sha256.$(OBJEXT) md5.$(OBJEXT) mprintf.$(OBJEXT) \
+ chunks.$(OBJEXT) signature.$(OBJEXT) dirs.$(OBJEXT) \
+ names.$(OBJEXT) $(am__objects_1)
+changestool_OBJECTS = $(am_changestool_OBJECTS)
+am__DEPENDENCIES_1 =
+changestool_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am__reprepro_SOURCES_DIST = outhook.c descriptions.c sizes.c \
+ sourcecheck.c byhandhook.c archallflood.c needbuild.c \
+ globmatch.c printlistformat.c diffindex.c rredpatch.c pool.c \
+ atoms.c uncompression.c remoterepository.c indexfile.c \
+ copypackages.c sourceextraction.c checksums.c readtextfile.c \
+ filecntl.c sha1.c sha256.c configparser.c database.c \
+ freespace.c hooks.c log.c changes.c incoming.c uploaderslist.c \
+ guesscomponent.c files.c md5.c dirs.c chunks.c reference.c \
+ binaries.c sources.c checks.c names.c dpkgversions.c release.c \
+ mprintf.c updates.c strlist.c signature_check.c signedfile.c \
+ signature.c distribution.c checkindeb.c checkindsc.c checkin.c \
+ upgradelist.c target.c aptmethod.c downloadcache.c main.c \
+ override.c terms.c termdecide.c ignore.c filterlist.c \
+ exports.c tracking.c optionsfile.c donefile.c pull.c \
+ contents.c filelist.c extractcontrol.c ar.c debfile.c \
+ debfilecontents.c
+@HAVE_LIBARCHIVE_TRUE@am__objects_2 = debfilecontents.$(OBJEXT)
+am_reprepro_OBJECTS = outhook.$(OBJEXT) descriptions.$(OBJEXT) \
+ sizes.$(OBJEXT) sourcecheck.$(OBJEXT) byhandhook.$(OBJEXT) \
+ archallflood.$(OBJEXT) needbuild.$(OBJEXT) globmatch.$(OBJEXT) \
+ printlistformat.$(OBJEXT) diffindex.$(OBJEXT) \
+ rredpatch.$(OBJEXT) pool.$(OBJEXT) atoms.$(OBJEXT) \
+ uncompression.$(OBJEXT) remoterepository.$(OBJEXT) \
+ indexfile.$(OBJEXT) copypackages.$(OBJEXT) \
+ sourceextraction.$(OBJEXT) checksums.$(OBJEXT) \
+ readtextfile.$(OBJEXT) filecntl.$(OBJEXT) sha1.$(OBJEXT) \
+ sha256.$(OBJEXT) configparser.$(OBJEXT) database.$(OBJEXT) \
+ freespace.$(OBJEXT) hooks.$(OBJEXT) log.$(OBJEXT) \
+ changes.$(OBJEXT) incoming.$(OBJEXT) uploaderslist.$(OBJEXT) \
+ guesscomponent.$(OBJEXT) files.$(OBJEXT) md5.$(OBJEXT) \
+ dirs.$(OBJEXT) chunks.$(OBJEXT) reference.$(OBJEXT) \
+ binaries.$(OBJEXT) sources.$(OBJEXT) checks.$(OBJEXT) \
+ names.$(OBJEXT) dpkgversions.$(OBJEXT) release.$(OBJEXT) \
+ mprintf.$(OBJEXT) updates.$(OBJEXT) strlist.$(OBJEXT) \
+ signature_check.$(OBJEXT) signedfile.$(OBJEXT) \
+ signature.$(OBJEXT) distribution.$(OBJEXT) \
+ checkindeb.$(OBJEXT) checkindsc.$(OBJEXT) checkin.$(OBJEXT) \
+ upgradelist.$(OBJEXT) target.$(OBJEXT) aptmethod.$(OBJEXT) \
+ downloadcache.$(OBJEXT) main.$(OBJEXT) override.$(OBJEXT) \
+ terms.$(OBJEXT) termdecide.$(OBJEXT) ignore.$(OBJEXT) \
+ filterlist.$(OBJEXT) exports.$(OBJEXT) tracking.$(OBJEXT) \
+ optionsfile.$(OBJEXT) donefile.$(OBJEXT) pull.$(OBJEXT) \
+ contents.$(OBJEXT) filelist.$(OBJEXT) $(am__objects_1) \
+ $(am__objects_2)
+reprepro_OBJECTS = $(am_reprepro_OBJECTS)
+reprepro_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_rredtool_OBJECTS = rredtool.$(OBJEXT) rredpatch.$(OBJEXT) \
+ mprintf.$(OBJEXT) filecntl.$(OBJEXT) sha1.$(OBJEXT)
+rredtool_OBJECTS = $(am_rredtool_OBJECTS)
+rredtool_LDADD = $(LDADD)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/ac/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/aptmethod.Po ./$(DEPDIR)/ar.Po \
+ ./$(DEPDIR)/archallflood.Po ./$(DEPDIR)/atoms.Po \
+ ./$(DEPDIR)/binaries.Po ./$(DEPDIR)/byhandhook.Po \
+ ./$(DEPDIR)/changes.Po ./$(DEPDIR)/checkin.Po \
+ ./$(DEPDIR)/checkindeb.Po ./$(DEPDIR)/checkindsc.Po \
+ ./$(DEPDIR)/checks.Po ./$(DEPDIR)/checksums.Po \
+ ./$(DEPDIR)/chunkedit.Po ./$(DEPDIR)/chunks.Po \
+ ./$(DEPDIR)/configparser.Po ./$(DEPDIR)/contents.Po \
+ ./$(DEPDIR)/copypackages.Po ./$(DEPDIR)/database.Po \
+ ./$(DEPDIR)/debfile.Po ./$(DEPDIR)/debfilecontents.Po \
+ ./$(DEPDIR)/descriptions.Po ./$(DEPDIR)/diffindex.Po \
+ ./$(DEPDIR)/dirs.Po ./$(DEPDIR)/distribution.Po \
+ ./$(DEPDIR)/donefile.Po ./$(DEPDIR)/downloadcache.Po \
+ ./$(DEPDIR)/dpkgversions.Po ./$(DEPDIR)/exports.Po \
+ ./$(DEPDIR)/extractcontrol.Po ./$(DEPDIR)/filecntl.Po \
+ ./$(DEPDIR)/filelist.Po ./$(DEPDIR)/files.Po \
+ ./$(DEPDIR)/filterlist.Po ./$(DEPDIR)/freespace.Po \
+ ./$(DEPDIR)/globmatch.Po ./$(DEPDIR)/guesscomponent.Po \
+ ./$(DEPDIR)/hooks.Po ./$(DEPDIR)/ignore.Po \
+ ./$(DEPDIR)/incoming.Po ./$(DEPDIR)/indexfile.Po \
+ ./$(DEPDIR)/log.Po ./$(DEPDIR)/main.Po ./$(DEPDIR)/md5.Po \
+ ./$(DEPDIR)/mprintf.Po ./$(DEPDIR)/names.Po \
+ ./$(DEPDIR)/needbuild.Po ./$(DEPDIR)/optionsfile.Po \
+ ./$(DEPDIR)/outhook.Po ./$(DEPDIR)/override.Po \
+ ./$(DEPDIR)/pool.Po ./$(DEPDIR)/printlistformat.Po \
+ ./$(DEPDIR)/pull.Po ./$(DEPDIR)/readtextfile.Po \
+ ./$(DEPDIR)/reference.Po ./$(DEPDIR)/release.Po \
+ ./$(DEPDIR)/remoterepository.Po ./$(DEPDIR)/rredpatch.Po \
+ ./$(DEPDIR)/rredtool.Po ./$(DEPDIR)/sha1.Po \
+ ./$(DEPDIR)/sha256.Po ./$(DEPDIR)/signature.Po \
+ ./$(DEPDIR)/signature_check.Po ./$(DEPDIR)/signedfile.Po \
+ ./$(DEPDIR)/sizes.Po ./$(DEPDIR)/sourcecheck.Po \
+ ./$(DEPDIR)/sourceextraction.Po ./$(DEPDIR)/sources.Po \
+ ./$(DEPDIR)/strlist.Po ./$(DEPDIR)/target.Po \
+ ./$(DEPDIR)/termdecide.Po ./$(DEPDIR)/terms.Po \
+ ./$(DEPDIR)/tool.Po ./$(DEPDIR)/tracking.Po \
+ ./$(DEPDIR)/uncompression.Po ./$(DEPDIR)/updates.Po \
+ ./$(DEPDIR)/upgradelist.Po ./$(DEPDIR)/uploaderslist.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(changestool_SOURCES) $(reprepro_SOURCES) \
+ $(rredtool_SOURCES)
+DIST_SOURCES = $(am__changestool_SOURCES_DIST) \
+ $(am__reprepro_SOURCES_DIST) $(rredtool_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ cscope distdir distdir-am dist dist-all distcheck
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+ $(LISP)config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+ $(top_srcdir)/ac/compile $(top_srcdir)/ac/depcomp \
+ $(top_srcdir)/ac/install-sh $(top_srcdir)/ac/missing AUTHORS \
+ COPYING ChangeLog INSTALL NEWS README TODO ac/compile \
+ ac/depcomp ac/install-sh ac/missing
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ if test -d "$(distdir)"; then \
+ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -rf "$(distdir)" \
+ || { sleep 5 && rm -rf "$(distdir)"; }; \
+ else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+DIST_TARGETS = dist-gzip
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+ARCHIVECPP = @ARCHIVECPP@
+ARCHIVELIBS = @ARCHIVELIBS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBLIBS = @DBLIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = docs tests
+EXTRA_DIST = autogen.sh
+@HAVE_LIBARCHIVE_FALSE@ARCHIVE_USED = extractcontrol.c
+@HAVE_LIBARCHIVE_TRUE@ARCHIVE_USED = ar.c debfile.c
+@HAVE_LIBARCHIVE_FALSE@ARCHIVE_CONTENTS =
+@HAVE_LIBARCHIVE_TRUE@ARCHIVE_CONTENTS = debfilecontents.c
+@HAVE_LIBARCHIVE_FALSE@ARCHIVE_UNUSED = ar.c debfile.c debfilecontents.c
+@HAVE_LIBARCHIVE_TRUE@ARCHIVE_UNUSED = extractcontrol.c
+AM_CPPFLAGS = $(ARCHIVECPP) $(DBCPPFLAGS)
+reprepro_LDADD = $(ARCHIVELIBS) $(DBLIBS)
+changestool_LDADD = $(ARCHIVELIBS)
+reprepro_SOURCES = outhook.c descriptions.c sizes.c sourcecheck.c byhandhook.c archallflood.c needbuild.c globmatch.c printlistformat.c diffindex.c rredpatch.c pool.c atoms.c uncompression.c remoterepository.c indexfile.c copypackages.c sourceextraction.c checksums.c readtextfile.c filecntl.c sha1.c sha256.c configparser.c database.c freespace.c hooks.c log.c changes.c incoming.c uploaderslist.c guesscomponent.c files.c md5.c dirs.c chunks.c reference.c binaries.c sources.c checks.c names.c dpkgversions.c release.c mprintf.c updates.c strlist.c signature_check.c signedfile.c signature.c distribution.c checkindeb.c checkindsc.c checkin.c upgradelist.c target.c aptmethod.c downloadcache.c main.c override.c terms.c termdecide.c ignore.c filterlist.c exports.c tracking.c optionsfile.c donefile.c pull.c contents.c filelist.c $(ARCHIVE_USED) $(ARCHIVE_CONTENTS)
+EXTRA_reprepro_SOURCE = $(ARCHIVE_UNUSED)
+changestool_SOURCES = uncompression.c sourceextraction.c readtextfile.c filecntl.c tool.c chunkedit.c strlist.c checksums.c sha1.c sha256.c md5.c mprintf.c chunks.c signature.c dirs.c names.c $(ARCHIVE_USED)
+rredtool_SOURCES = rredtool.c rredpatch.c mprintf.c filecntl.c sha1.c
+noinst_HEADERS = outhook.h descriptions.h sizes.h sourcecheck.h byhandhook.h archallflood.h needbuild.h globmatch.h printlistformat.h pool.h atoms.h uncompression.h remoterepository.h copypackages.h sourceextraction.h checksums.h readtextfile.h filecntl.h sha1.h sha256.h configparser.h database_p.h database.h freespace.h hooks.h log.h changes.h incoming.h guesscomponent.h md5.h dirs.h files.h chunks.h reference.h binaries.h sources.h checks.h names.h release.h error.h mprintf.h updates.h strlist.h signature.h signature_p.h distribution.h debfile.h checkindeb.h checkindsc.h upgradelist.h target.h aptmethod.h downloadcache.h override.h terms.h termdecide.h ignore.h filterlist.h dpkgversions.h checkin.h exports.h globals.h tracking.h trackingt.h optionsfile.h donefile.h pull.h ar.h filelist.h contents.h chunkedit.h uploaderslist.h indexfile.h rredpatch.h diffindex.h package.h
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in $(srcdir)/configure $(srcdir)/stamp-h.in $(srcdir)/aclocal.m4 $(srcdir)/config.h.in
+SPLINT = splint
+SPLITFLAGSFORVIM = -linelen 10000 -locindentspaces 0
+SPLINTFLAGS = +posixlib -booltype bool -numabstractcast -fixedformalarray -enumint +enumindex +charint $(SPLITFLAGSFORVIM) $(EXTRASPLINTFLAGS)
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+am--refresh: Makefile
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+ @test -f $@ || rm -f stamp-h1
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+changestool$(EXEEXT): $(changestool_OBJECTS) $(changestool_DEPENDENCIES) $(EXTRA_changestool_DEPENDENCIES)
+ @rm -f changestool$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(changestool_OBJECTS) $(changestool_LDADD) $(LIBS)
+
+reprepro$(EXEEXT): $(reprepro_OBJECTS) $(reprepro_DEPENDENCIES) $(EXTRA_reprepro_DEPENDENCIES)
+ @rm -f reprepro$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(reprepro_OBJECTS) $(reprepro_LDADD) $(LIBS)
+
+rredtool$(EXEEXT): $(rredtool_OBJECTS) $(rredtool_DEPENDENCIES) $(EXTRA_rredtool_DEPENDENCIES)
+ @rm -f rredtool$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(rredtool_OBJECTS) $(rredtool_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aptmethod.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ar.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archallflood.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atoms.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binaries.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/byhandhook.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/changes.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checkin.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checkindeb.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checkindsc.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checks.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checksums.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chunkedit.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chunks.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/configparser.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/contents.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copypackages.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/database.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debfilecontents.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/descriptions.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/diffindex.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirs.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/distribution.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/donefile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/downloadcache.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dpkgversions.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exports.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extractcontrol.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filecntl.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filelist.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/files.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filterlist.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freespace.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/globmatch.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/guesscomponent.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hooks.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ignore.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incoming.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indexfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mprintf.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/names.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/needbuild.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/optionsfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/outhook.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/override.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/printlistformat.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pull.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readtextfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reference.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/release.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remoterepository.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rredpatch.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rredtool.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signature.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signature_check.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signedfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sizes.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sourcecheck.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sourceextraction.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sources.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlist.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/termdecide.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/terms.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tracking.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uncompression.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/updates.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upgradelist.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uploaderslist.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+ test ! -s cscope.files \
+ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+ -rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+ -rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ $(am__remove_distdir)
+ test -d "$(distdir)" || mkdir "$(distdir)"
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -test -n "$(am__skip_mode_fix)" \
+ || find "$(distdir)" -type d ! -perm -755 \
+ -exec chmod u+rwx,go+rx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
+ $(am__post_remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+ $(am__post_remove_distdir)
+
+dist-lzip: distdir
+ tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+ $(am__post_remove_distdir)
+
+dist-xz: distdir
+ tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+ $(am__post_remove_distdir)
+
+dist-tarZ: distdir
+ @echo WARNING: "Support for distribution archives compressed with" \
+ "legacy program 'compress' is deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__post_remove_distdir)
+
+dist-shar: distdir
+ @echo WARNING: "Support for shar distribution archives is" \
+ "deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
+ $(am__post_remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__post_remove_distdir)
+
+dist dist-all:
+ $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+ $(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lz*) \
+ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+ *.tar.xz*) \
+ xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir)
+ chmod u+w $(distdir)
+ mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
+ chmod a-w $(distdir)
+ test -d $(distdir)/_build || exit 0; \
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && am__cwd=`pwd` \
+ && $(am__cd) $(distdir)/_build/sub \
+ && ../../configure \
+ $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ --srcdir=../.. --prefix="$$dc_install_base" \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+ && cd "$$am__cwd" \
+ || exit 1
+ $(am__post_remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+ @test -n '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: trying to run $@ with an empty' \
+ '$$(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ $(am__cd) '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(PROGRAMS) $(HEADERS) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-recursive
+
+clean-am: clean-binPROGRAMS clean-generic clean-local mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f ./$(DEPDIR)/aptmethod.Po
+ -rm -f ./$(DEPDIR)/ar.Po
+ -rm -f ./$(DEPDIR)/archallflood.Po
+ -rm -f ./$(DEPDIR)/atoms.Po
+ -rm -f ./$(DEPDIR)/binaries.Po
+ -rm -f ./$(DEPDIR)/byhandhook.Po
+ -rm -f ./$(DEPDIR)/changes.Po
+ -rm -f ./$(DEPDIR)/checkin.Po
+ -rm -f ./$(DEPDIR)/checkindeb.Po
+ -rm -f ./$(DEPDIR)/checkindsc.Po
+ -rm -f ./$(DEPDIR)/checks.Po
+ -rm -f ./$(DEPDIR)/checksums.Po
+ -rm -f ./$(DEPDIR)/chunkedit.Po
+ -rm -f ./$(DEPDIR)/chunks.Po
+ -rm -f ./$(DEPDIR)/configparser.Po
+ -rm -f ./$(DEPDIR)/contents.Po
+ -rm -f ./$(DEPDIR)/copypackages.Po
+ -rm -f ./$(DEPDIR)/database.Po
+ -rm -f ./$(DEPDIR)/debfile.Po
+ -rm -f ./$(DEPDIR)/debfilecontents.Po
+ -rm -f ./$(DEPDIR)/descriptions.Po
+ -rm -f ./$(DEPDIR)/diffindex.Po
+ -rm -f ./$(DEPDIR)/dirs.Po
+ -rm -f ./$(DEPDIR)/distribution.Po
+ -rm -f ./$(DEPDIR)/donefile.Po
+ -rm -f ./$(DEPDIR)/downloadcache.Po
+ -rm -f ./$(DEPDIR)/dpkgversions.Po
+ -rm -f ./$(DEPDIR)/exports.Po
+ -rm -f ./$(DEPDIR)/extractcontrol.Po
+ -rm -f ./$(DEPDIR)/filecntl.Po
+ -rm -f ./$(DEPDIR)/filelist.Po
+ -rm -f ./$(DEPDIR)/files.Po
+ -rm -f ./$(DEPDIR)/filterlist.Po
+ -rm -f ./$(DEPDIR)/freespace.Po
+ -rm -f ./$(DEPDIR)/globmatch.Po
+ -rm -f ./$(DEPDIR)/guesscomponent.Po
+ -rm -f ./$(DEPDIR)/hooks.Po
+ -rm -f ./$(DEPDIR)/ignore.Po
+ -rm -f ./$(DEPDIR)/incoming.Po
+ -rm -f ./$(DEPDIR)/indexfile.Po
+ -rm -f ./$(DEPDIR)/log.Po
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/md5.Po
+ -rm -f ./$(DEPDIR)/mprintf.Po
+ -rm -f ./$(DEPDIR)/names.Po
+ -rm -f ./$(DEPDIR)/needbuild.Po
+ -rm -f ./$(DEPDIR)/optionsfile.Po
+ -rm -f ./$(DEPDIR)/outhook.Po
+ -rm -f ./$(DEPDIR)/override.Po
+ -rm -f ./$(DEPDIR)/pool.Po
+ -rm -f ./$(DEPDIR)/printlistformat.Po
+ -rm -f ./$(DEPDIR)/pull.Po
+ -rm -f ./$(DEPDIR)/readtextfile.Po
+ -rm -f ./$(DEPDIR)/reference.Po
+ -rm -f ./$(DEPDIR)/release.Po
+ -rm -f ./$(DEPDIR)/remoterepository.Po
+ -rm -f ./$(DEPDIR)/rredpatch.Po
+ -rm -f ./$(DEPDIR)/rredtool.Po
+ -rm -f ./$(DEPDIR)/sha1.Po
+ -rm -f ./$(DEPDIR)/sha256.Po
+ -rm -f ./$(DEPDIR)/signature.Po
+ -rm -f ./$(DEPDIR)/signature_check.Po
+ -rm -f ./$(DEPDIR)/signedfile.Po
+ -rm -f ./$(DEPDIR)/sizes.Po
+ -rm -f ./$(DEPDIR)/sourcecheck.Po
+ -rm -f ./$(DEPDIR)/sourceextraction.Po
+ -rm -f ./$(DEPDIR)/sources.Po
+ -rm -f ./$(DEPDIR)/strlist.Po
+ -rm -f ./$(DEPDIR)/target.Po
+ -rm -f ./$(DEPDIR)/termdecide.Po
+ -rm -f ./$(DEPDIR)/terms.Po
+ -rm -f ./$(DEPDIR)/tool.Po
+ -rm -f ./$(DEPDIR)/tracking.Po
+ -rm -f ./$(DEPDIR)/uncompression.Po
+ -rm -f ./$(DEPDIR)/updates.Po
+ -rm -f ./$(DEPDIR)/upgradelist.Po
+ -rm -f ./$(DEPDIR)/uploaderslist.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f ./$(DEPDIR)/aptmethod.Po
+ -rm -f ./$(DEPDIR)/ar.Po
+ -rm -f ./$(DEPDIR)/archallflood.Po
+ -rm -f ./$(DEPDIR)/atoms.Po
+ -rm -f ./$(DEPDIR)/binaries.Po
+ -rm -f ./$(DEPDIR)/byhandhook.Po
+ -rm -f ./$(DEPDIR)/changes.Po
+ -rm -f ./$(DEPDIR)/checkin.Po
+ -rm -f ./$(DEPDIR)/checkindeb.Po
+ -rm -f ./$(DEPDIR)/checkindsc.Po
+ -rm -f ./$(DEPDIR)/checks.Po
+ -rm -f ./$(DEPDIR)/checksums.Po
+ -rm -f ./$(DEPDIR)/chunkedit.Po
+ -rm -f ./$(DEPDIR)/chunks.Po
+ -rm -f ./$(DEPDIR)/configparser.Po
+ -rm -f ./$(DEPDIR)/contents.Po
+ -rm -f ./$(DEPDIR)/copypackages.Po
+ -rm -f ./$(DEPDIR)/database.Po
+ -rm -f ./$(DEPDIR)/debfile.Po
+ -rm -f ./$(DEPDIR)/debfilecontents.Po
+ -rm -f ./$(DEPDIR)/descriptions.Po
+ -rm -f ./$(DEPDIR)/diffindex.Po
+ -rm -f ./$(DEPDIR)/dirs.Po
+ -rm -f ./$(DEPDIR)/distribution.Po
+ -rm -f ./$(DEPDIR)/donefile.Po
+ -rm -f ./$(DEPDIR)/downloadcache.Po
+ -rm -f ./$(DEPDIR)/dpkgversions.Po
+ -rm -f ./$(DEPDIR)/exports.Po
+ -rm -f ./$(DEPDIR)/extractcontrol.Po
+ -rm -f ./$(DEPDIR)/filecntl.Po
+ -rm -f ./$(DEPDIR)/filelist.Po
+ -rm -f ./$(DEPDIR)/files.Po
+ -rm -f ./$(DEPDIR)/filterlist.Po
+ -rm -f ./$(DEPDIR)/freespace.Po
+ -rm -f ./$(DEPDIR)/globmatch.Po
+ -rm -f ./$(DEPDIR)/guesscomponent.Po
+ -rm -f ./$(DEPDIR)/hooks.Po
+ -rm -f ./$(DEPDIR)/ignore.Po
+ -rm -f ./$(DEPDIR)/incoming.Po
+ -rm -f ./$(DEPDIR)/indexfile.Po
+ -rm -f ./$(DEPDIR)/log.Po
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/md5.Po
+ -rm -f ./$(DEPDIR)/mprintf.Po
+ -rm -f ./$(DEPDIR)/names.Po
+ -rm -f ./$(DEPDIR)/needbuild.Po
+ -rm -f ./$(DEPDIR)/optionsfile.Po
+ -rm -f ./$(DEPDIR)/outhook.Po
+ -rm -f ./$(DEPDIR)/override.Po
+ -rm -f ./$(DEPDIR)/pool.Po
+ -rm -f ./$(DEPDIR)/printlistformat.Po
+ -rm -f ./$(DEPDIR)/pull.Po
+ -rm -f ./$(DEPDIR)/readtextfile.Po
+ -rm -f ./$(DEPDIR)/reference.Po
+ -rm -f ./$(DEPDIR)/release.Po
+ -rm -f ./$(DEPDIR)/remoterepository.Po
+ -rm -f ./$(DEPDIR)/rredpatch.Po
+ -rm -f ./$(DEPDIR)/rredtool.Po
+ -rm -f ./$(DEPDIR)/sha1.Po
+ -rm -f ./$(DEPDIR)/sha256.Po
+ -rm -f ./$(DEPDIR)/signature.Po
+ -rm -f ./$(DEPDIR)/signature_check.Po
+ -rm -f ./$(DEPDIR)/signedfile.Po
+ -rm -f ./$(DEPDIR)/sizes.Po
+ -rm -f ./$(DEPDIR)/sourcecheck.Po
+ -rm -f ./$(DEPDIR)/sourceextraction.Po
+ -rm -f ./$(DEPDIR)/sources.Po
+ -rm -f ./$(DEPDIR)/strlist.Po
+ -rm -f ./$(DEPDIR)/target.Po
+ -rm -f ./$(DEPDIR)/termdecide.Po
+ -rm -f ./$(DEPDIR)/terms.Po
+ -rm -f ./$(DEPDIR)/tool.Po
+ -rm -f ./$(DEPDIR)/tracking.Po
+ -rm -f ./$(DEPDIR)/uncompression.Po
+ -rm -f ./$(DEPDIR)/updates.Po
+ -rm -f ./$(DEPDIR)/upgradelist.Po
+ -rm -f ./$(DEPDIR)/uploaderslist.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic \
+ maintainer-clean-local
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: $(am__recursive_targets) all install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles am--refresh check check-am clean \
+ clean-binPROGRAMS clean-cscope clean-generic clean-local \
+ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
+ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \
+ distcheck distclean distclean-compile distclean-generic \
+ distclean-hdr distclean-tags distcleancheck distdir \
+ distuninstallcheck dvi dvi-am html html-am info info-am \
+ install install-am install-binPROGRAMS install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic maintainer-clean-local mostlyclean \
+ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+clean-local:
+ -rm -rf autom4te.cache $(srcdir)/autom4te.cache
+
+maintainer-clean-local:
+ -rm -rf $(srcdir)/ac
+
+# Some things for my private laziness
+strictbooleancheck:
+ /home/brl/gcc/b/gcc/cc1 -DHAVE_CONFIG_H -I/home/brl/gcc/b/gcc/include -I/usr/include -I. -Wall -DAVOID_CHECKPROBLEMS=1 -g -W -O2 *.c
+
+splint:
+ $(SPLINT) -DSPLINT=1 $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) -D_GNU_SOURCE=1 $(SPLINTFLAGS) $(foreach file,$(reprepro_SOURCES),$(srcdir)/$(file))
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..081647d
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,708 @@
+Updates between 5.1.1 and 5.2.0:
+- mark .lz support as deprecated
+- add _listcodenames command
+- allow to set Signed-By header via conf/distributions
+- add support for .asc files in source packages
+- some documentation improvements
+- allow '+' character in method-URI
+
+Updates between 5.1.0 and 5.1.1:
+- improve error handling when extracting .deb file contents
+- fix many spelling mistakes
+
+Updates between 5.0.0 and 5.1.0:
+- .gz, .bz2 and .lzma built-in uncompressors now also support
+ concatenated files (as gunzip, bunzip2 and unxz).
+- added add unreferencesnapshot and removereference commands
+- fixed (Deb|Dsc)Indices parsing (did add a default Release even
+ if none was specified)
+- some documentation improvements
+
+Updates between 4.18.0 and 5.0.0:
+- some code refactoring (no new features or bugfixes, only chances to break stuff)
+- require new status 103 behaviour from apt methods
+ (i.e. http from squeeze and before no longer supported)
+- add support for .buildinfo files in .changes files
+
+Updates between 4.17.0 and 4.17.1:
+- fix bug with 'flood' if there are binaries belonging to different versions
+ of the same source package
+- fix output caused by 'warning' FilterList files.
+
+Updates between 4.16.1 and 4.17.0:
+- some manpage fixes
+- '#' in filterlists are comments
+- fix parsing of strangly formatted control files
+- add Exportoptions: noexport option in conf/distributions
+- add Permit: unlisted_binary option in conf/incoming
+- -dbgsym are not differently looked for in changes' Binary field
+
+Updates between 4.16.0 and 4.16.1:
+- fix segfault in verbose exporting of xzed indices
+
+Updates between 4.15.0 and 4.16.0:
+- add support for xz uncompression using liblzma instead of unxz
+- enable using liblzma by default (if found and not --without-liblzma is given)
+- all example scripts in python now use python3
+
+Updates between 4.14.1 and 4.15.0:
+- fixes to outsftphook example, new xz example, manpage improvements
+- support for native Packages.xz generation using liblzma (disabled by default)
+
+Updates between 4.13.1 and 4.14.0:
+- repairdescriptions also repairs udeb descriptions
+- automatically add long descriptions when updating
+ packages from a source that does not have them
+- ignore Extra-Source-Only source packages by default
+- some small bugfixes and improvements
+
+Updates between 4.13.0 and 4.13.1:
+- fix bug in restore
+- fix percomponent udeb Contents filenames
+- add support for sources listing architecture wildcards to build-needing
+
+Updates between 4.12.5 and 4.13.0:
+- new commands: deleteifunreferenced repairdescriptions lsbycomponent
+- add ${$basename}, ${$filekey} and ${$fullfilename} to --listformat
+- reject absurd large values in ValidFor header
+- add --endhook, --outhook
+- SignWith: can now also contain external scripts for signing
+- several small cleanups and fixes
+
+Updates between 4.12.4 and 4.12.5:
+- various documentation improvements
+- fix bitrot in non-libarchive code
+
+Updates between 4.12.3 and 4.12.4:
+- fix bug when only generating .bz2 indices
+- ignore diff comments about unterminated lines when parsing .diff files
+
+Updates between 4.12.2 and 4.12.3:
+- actually set REPREPRO_CONFIG_DIR in hooks as documented in manpage
+- support 103 redirect message from apt's http method.
+ (works best with apt >= 0.9.4)
+
+Updates between 4.12.1 and 4.12.2:
+- fix error with uploader files with more than 16 group members
+
+Updates between 4.12.0 and 4.12.1:
+- fix bash and zsh completion to work with config directories
+- add experimental -A, -C, -T support to the pull/update family of commands
+
+Updates between 4.11.0 and 4.12.0:
+- get InRelease from remote repositories (to disable use new GetInRelease: no)
+- always put Package field first in indices
+- support getting packages from remote repositories without md5sums.
+
+Updates between 4.10.0 and 4.11.0:
+- Contents files default location is now "percomponent compatsymlink".
+- unify handling of "unknown" section.
+
+Updates between 4.9.0 and 4.10.0:
+- allow "!include:" in conf/{distributions,updates,pulls,incoming}
+- conf/{distributions,updates,pulls,incoming} can be directories
+- add FilterList keyword 'supersede' to remove if upstream has newer pkgs
+- improve changelogs.example (CHANGELOGDIR empty stored directly in pool/)
+
+Updates between 4.8.2 and 4.9.0:
+- build-needing now allows one to look for things for 'all' and 'any'
+- improve error messages when parsing config files
+- uploader files now can 'include' other files.
+
+Updates between 4.8.1 and 4.8.2:
+- rredtool: produce .diff/Index files that reprepro can understand.
+- warn if uploader files contains key ids too long to handle
+- make .diff/Index parsing errors non-fatal
+
+Updates between 4.8.0 and 4.8.1:
+- fix NULL-dereference with broken Packages.diff/Index files
+
+Updates between 4.7.0 and 4.8.0:
+- add compatsymlink nocompatsymlink Contents: options
+ (and document that the default will change in the future)
+
+Updates between 4.6.1 and 4.7.0:
+- add 'redochecksums' command
+- add percomponent and allcomponents to Contents: flags
+
+Updates between 4.6.0 and 4.6.1:
+- fix message given when replacing a package with the same version
+- fix bug not deleting packages if none added in update
+
+Updates between 4.5.1 and 4.6.0:
+- add 'FilterSrcList' for update and pull
+- ignore leading comments in control files
+
+Updates between 4.5.0 and 4.5.1:
+- 'check' also checks if architectures match
+- buffix in 'sourcemissing', 'unusedsources' and 'reportcruft' without tracking
+- fix 'pull' copying packages with wrong architecture
+- compile with libdb5
+
+Updates between 4.4.0 and 4.5.0:
+- support reading of Release files without MD5Sum
+- add all missing Checksums-* when importing from remote repositories
+- add 'reportcruft' command
+
+Updates between 4.3.0 and 4.4.0:
+- SignWith allows multiple arguments to denote multiple keys to sign wtih
+- add removesrcs command (like removesrc can you can remove more at once)
+- uploaders files can have groups of uploaders and depend on the
+ distribution to upload to (to share uploaders file between distributions)
+- add 'sizes' command.
+
+Updates between 4.2.0 and 4.3.0:
+- add special "$Delete" override field to get rid of fields
+- add support for ButAtuomaticUpgrades
+- add 'unusedsources' and 'sourcemissing' commands
+- add support for lzip compressed files
+- bugfixes ($component overrides, compiling without libbz2, with gcc4.5)
+
+Updates between 4.1.1 and 4.2.0:
+- allow patterns in override files
+- apply override files when doing 'pull' and 'update'
+- add special '$Component' override field
+- create InRelease file additionally to Release.gpg
+
+Updates between 4.1.1 and 4.1.2:
+- fix parsing of .orig-*.tar.* lines in .changes files,
+ especially do not choke on _ characters.
+- add --onlysmalldeletes option to limit scope of update and pull
+
+Updates between 4.1.0 and 4.1.1:
+- fix calling --changes Log:-notifiers from processincoming
+- add '${$source}' and '${$sourceversion}' to --list-format
+
+Updates between 4.0.2 and 4.1.0:
+- rredtool can be used as index hook to maintain a .diff/Index file.
+- properly handle relative LogDir in conf/incoming
+- add ByHandHooks to conf/distributions (only used by processincoming yet)
+- fix extraction of exactly one of section or priority from a tar file.
+- new byhand statement for uploaders files and ByHandHook for configuration
+
+Updates between 4.0.1 and 4.0.2:
+- add support for xz de-compression
+- fix regression (since 3.8.0) breaking arch1>arch2 update rules.
+- some small warning output fixes in update code
+
+Updates between 4.0.0 and 4.0.1:
+- strip the last '/' from Method and Fallback in conf/updates to work
+ around problems in some apt methods. (to get old behaviour, use "//")
+- 'check' now warns if a file was missing but could be readded
+- much more permissive check for libdb. You are on your own now to check
+ what version to build against.
+
+Updates between 3.12.1 and 4.0.0:
+- disable old files.db handling (remove all support but
+ translatelegacyfilelists), remove --oldfilesdb options
+- remove --overridedir
+- bugfixes in documentation and bash/zsh completion
+
+Updates between 3.12.0 and 3.12.1:
+- fix problems with libgpgme 1.2.0
+
+Updates between 3.11.1 and 3.12.0:
+- warn if directories are relative to the currect directory but do not start
+ with './'
+- directories starting '+b/' '+o/' and '+c/' are relative to basedir, outdir
+ or confdir.
+- FakeComponentPrefix now no longer adds its arguments to components already
+ having it and shortens their dist directories to not duplicate that either.
+- -A, -C and -T can have multiple arguments now, separated with '|'.
+- new 'flood' action to align architecture all packages
+- new '--show-percent' option
+- warn if old legacy files.db is still used
+- add new translatelegacyfilelists command for easier migration.
+ (just a collectnewchecksums and deleting that file was enough, though)
+
+Updates between 3.11.0 and 3.11.1:
+- new changestool option --create-with-all-fields
+- new --morguedir option (or morguedir in conf/options, of course)
+- new $Version, $Source, $SourceVersion et al on formulas
+- bugfixes
+
+Updates between 3.10.0 and 3.11.0:
+- new --list-max and --list-skip options
+- new glob-matching in formulas
+ (e.g. "reprepro listfilter codename 'Package (% linux-image-*)'")
+- new listmatched, removematched, copymatched and restorematched
+- new build-needing command to list source packages likely to need
+ a build for a given architecture.
+- pull, predelete and update call retrack on
+ distributions with tracking enabled.
+
+Updates between 3.9.2 and 3.10.0:
+- fix bug of ListHook not used if in the From: rule of a rule.
+- add ListShelllHook
+- add _listdbidentifiers and _listconfidentifiers
+- add --list-format to change format of list and listfilter
++ rewrite Release.gpg verification code:
+- more hops needed to use expired or revoked keys
+- earlier check of keys. now all keys in VerifyRelease must be known to gpg
+- subkeys are accepted if the key-id is appended with '+'.
+* improve uploader lists:
+- subkeys are accepted if key-if is appended with '+'
+- new 'anybody' while 'unsigned' now means really unsigned
+- new conditions to look as sourcename, binary names and sections
+
+Updates between 3.9.1 and 3.9.2:
++ fix bug (caught by assertion if there is no old index file)
+ that inverts the logic of downloading .diff files when there is no
+ DownLoadListsAs line.
+
+Updates between 3.9.0 and 3.9.1:
++ fix error of misinterpreting newer libz return value
+ when extracting section from a .dsc.
+
+Updates between 3.8.2 and 3.9.0:
++ deprecate old (pre 3.3) file database format. Warn loudly
+ when the database is still using that format.
++ new features
+- support Sources/Package.diff downloading
+ (Use DownloadListsAs if you want to force .gz downloading instead)
+- support falling back to other compressions of index files when
+ not downloadable at first.
+- changestool can now also look in .lzma files for .dsc section/priority
+- delete .new files in dists/ on error unless --keeptemporaries
+- new 'warning' state for FilterList
+- set REPREPRO_FROM and REPREPRO_CAUSING_RULE in some log notifiers
++ bug fixes:
+- re-enable workaround for apt-methods having problem with existing
+ files which got lost in 3.8
+- fix bug not looking at DownloadListsAs in all cases
+- bugfix in misparsing some .diff files for section/priority retrieval
+- do not stop when incomplete downloads or other stray files are in the pool
+
+Updates between 3.8.1 and 3.8.2:
+- add ReadOnly option for conf/distributions
+- support byhand and raw-* files in include and processincoming
+- allow uploading log files with .changes files
+- new LogDir in conf/incoming to store changes and log files.
+
+Updates between 3.8.0 and 3.8.1:
+- make filtercopy work again
+- fix bug not allowing source packages from flat
+ repositories without Directory fields to be imported
+- add gnupghome option to make GNUPGHOME setable via conf/options
+
+Updates between 3.8.0~alpha and 3.8.0:
+- add support for generating Valid-Until fields in Release files
+
+Updates between 3.6.3 and 3.8.0~alpha:
++ different small improvements:
+- log notifiers can be limited to a specific command with --via
+- upgradeonly value for FilterList to only include a package if
+ an older one is already there.
+- new --keepunusednewfiles to keep files just added to the pool
+ but later in the same run decided to no longer be needed
+ (for example because a package was not added because of later
+ detected errors).
+- --keepunreferenced and actions implying this now print
+ the number of files that lost their last reference
+- new dumpupdate and dumppull actions that are like checkupdate and
+ checkpull put with output easier parseable
+- new ls action to list a package in all distributions
++ bugfixes
+- if FilterFormula excludes a package, FilterList can no longer put
+ a package on hold.
++ improved decompression support
+- support looking into lzma compressed .deb, .diff and .tar files.
+- support for external helpers for uncompression
+ (to speed up uncompression on multiple processors, also reprepro
+ can now be compiled without libbz2 and zlib if needed)
+- support for downloading and using bz2 and lzma index files in updates
++ major changes to index file retrieval on updates:
+- iteratedupdate action was removed
+- update-rules can inherit settings from others
+- ListHooks are now called once per usage
+ (mostly only makes a difference for flat upstream repositories)
+- --nolistsdownload no longer includes --noskipold and checks checksums
+ of the lists files.
+- format of lists/ directory contents changed
+ (I doubt anyone cares for the files in there, but if you
+ do, you have been informed hereby that it looks differently)
+- lists/ directory no longer auto-cleaned,
+ thus --(no)keepuneeded longer exists and
+ new action cleanlists to clean files no longer usable...
++ visible effects of internal refactorisations:
+- multiple checks for identifiers more strict now
+- some fields in conf/distributions need a specific order now
+ (Architectures and Components before things using the values
+ defined by those)
+
+Updates between 3.6.2 and 3.6.3:
+- fix sha256 generation of very large files, thanks to Max Bowsher
+- allow multiple export hooks at once
+- use libgpg-error directly (to avoid some warnings in dependency analysis)
+
+Updates between 3.6.1 and 3.6.2:
+- --nooldfilesdb is the default now, create new repositories
+ with --oldfilesdb if you do not want to destroy them by accidentially
+ running reprepro versions before 3.0.0 on them...
+- fix content reading of overlong .deb files
+- fix parsing of flat repositories without Directory in Sources
+- fix tracking database corruption in removesrc with outdated tracking data
+ [previously believed hard to trigger, but outdated tracking data suffices]
+- many improvements and less spelling errors in manpage
+
+Updates between 3.6.0 and 3.6.1:
+- fix reoverride
+- fix bz2 compression (newer libbz2 sometimes uses more return codes
+ than previous versions, triggering a bug in reprepro)
+
+Updates between 3.5.2 and 3.6.0:
+- add IgnoreHashes option
+- allow list to list all packages if not package name specified.
+- support retrieving packages from flat repositories
+- speed up updating by buffering zlib's reading of index files
+- remove iteratedupdate
+- multiple little but nasty bugs fixed
+
+Updates between 3.5.1 and 3.5.2:
+- fix bug in optionsfilename generation introduced in 3.5.1
+- add FakeComponentPrefix to cope with apt's problems with
+ / in distribution names.
+
+Updates between 3.5.0 and 3.5.1:
+- support upcoming version 3 format source packages
+ (priority and section extraction only for wig&pen and quilt format)
+- set environment variables REPREPRO_*_DIR when calling hooks.
+ (note that those are set to the last set values, so for example
+ REPREPRO_CONF_DIR will be the directory with 'distributions' in it,
+ not necessarily the one with 'options' in it that was parsed).
+- other minor bugfixes
+
+Updates between 3.4.2 and 3.5.0:
+- allow suite names as command line arguments
+ (when there is not codename of this name and only one distribution
+ has this suite name)
+- generate and check Sha256, too.
+- changestool puts Files: last in .changes files so etch's dupload
+ works.
+
+Updates between 3.4.1 and 3.4.2:
+now really fix the nasty bug with notifiers 3.4.1 should
+have fixed and be more verbose when rejecting packages because
+of problems with a key
+
+Updates between 3.4.0 and 3.4.1:
+bugfixes only (though of the ugly segfaults kind)
+
+Updates between 3.3.2 and 3.4.0:
++ bugfixes:
+- no longer mix up -S and -P command line arguments (introduced in 3.0.1)
+- some field overriding was erroneously case dependent.
+- many spelling corrections
++ improvements:
+- more support for Checksums-Sha1
+- add copysrc and copyfilter commands (improve copy w.r.t tracking)
+- add restore restoresrc restorefilter and _addpackage commands
+- warn about some impossible -A -T combinations.
+- set fake Suite: in snapshots to quiet apt's signature checks.
+- add REPREPRO_CAUSING_FILE environment variable in log notifiers.
+- update expected fields to new dpkg-dev
+- try to extract missing section and priority of .dsc files from
+ .diff.gz and .tar.gz.
+
+Updates between 3.3.1 and 3.3.2:
+- bugfix in includedeb and a little bit code cleanup
+
+Updates between 3.3.0 and 3.3.1:
+- multiple bugfixes
+
+Updates between 3.1.0 and 3.3.0:
+- add support for different checksums.
+ The new checksums.db which stores all the checksums, while
+ files.db still only stores md5sum and is the canonical information,
+ when it exists. This way repositories keep backward compatible.
+ A repository generated with --nooldfilesdb only has checksums.db
+ and will not work with reprepro version prior to 3.3.
+ New command collectnewchecksums to calculate checksums missing
+ in the database.
+
+Updates between 3.0.1 and 3.1.0:
+- add sha1 hashes to the generated Release files.
+ the changes semantics needed in the release.caches.db file for this
+ should be transient. This will only cause index files without
+ uncompressed variants to be regenerated once upon upgrade, but
+ switching back and forth between previous versions and this or
+ later versions will cause regenerating of unchanged files.
+- internal changes of reading of text files (.dsc/.changes/Release/
+ control from .deb). Should not make any difference with normal input,
+ and make the situation better with strange input.
+- source packages now can have .tar und .diff lzma compressed
+ (still missing is support for lzma compressed binary packages)
+
+Updates between 3.0.0 and 3.0.1:
+- the default for --export is now "changed", as the old default was
+ just too confusing most of the time.
+- translatefilelist know also can convert databases with old and new
+ style entries
+
+Updates between 2.2.4 and 3.0.0:
+- new config file parser:
+ * many error messages now with line numbers
+ * native support of comments (i.e. lines starting with # are now ignored,
+ instead of treated as ignored headers, # within lines is now comment, too)
+ * better support of tabs
+ * meaning of empty fields changed, empty now means nothing and not all.
+- always parse the whole distributions file first before doing anything else
+ (avoids actions started in the wrong base directory and helps to catch more
+ disambiguities, may lead to the need of a valid config file for some actions
+ not needing one, though).
+- check pull and update rules to not list any architectures or components that
+ will never be used, so typos won't go unnoticed.
+- obsolete --overridedir and searching files in overrides/ directory by default.
+ This places are still search, but so is the configuration directory now and
+ future version will stop accepting --overridedir and not search in that
+ directory.
+- added db/version file to document database format
+ (so future versions can warn about incompatibilities)
+- cleaned up tracking handling a bit:
+ * retrack no longer created tracking data for distributions without tracking
+ * retrack only recreates usage data, not all data
+ (so .changes files and old versions are no longer lost when run)
+ also references from tracking data are now refreshed by rereferences instead
+ * removealltracks now needs explicitly needs distribution names
+ * tidytracks now removes all tracking data from a distribution without tracking
+ * clearvanished removes tracking data from vanished distributions.
+- make update's ListHook relative to confdir (unless absolute)
+- added removesrc and removefilter
+- new format for contents.cache.db. Only needs half of the disk space and runtime
+ to generate Contents files, but you need to run translatefilelists to translate
+ the cached items (or delete your contents.cache.db and let reprepro reread
+ all your .deb files). Also format and meaning of the Contents-fields changed, a
+ rate no longer can be specified.
+
+Updates between 2.2.3 and 2.2.4:
+- [SECURITY] fix bug causing a Release.gpg with only
+ unknown signatures considered as properly signed.
+
+Updates between 2.2.2 and 2.2.3:
+- add support for binNMUs (i.e. .changes files having a Version: that is not
+ the source version).
+- add zsh auto-completions script
+
+Updates between 2.2.1 and 2.2.2:
+- processincoming can be limited to a single .changes file
+- fix to support apt-methods stating Send-Config: false
+- set GPG_TTY when stdin is a terminal to ease usage of pinentry-curses
+
+Updates between 2.2.0 and 2.2.1:
+- fix mixup of the name of the --spacecheck option
+- fix missing options in bash completions
+- fix segfault when including changes without notificators
+
+Updates between 2.1.0 and 2.2.0:
+- renamed cleartracks in removealltracks
+- new notifier type for accepted changes files
+- bugs fixed:
+ * not tidy tracking dependencies on package remove
+ * forgot to call some slow notifiers in processincoming
+- new --wait-for-lock option
+- check free space on update (new --spaceheck option to switch this off)
+- extended the changestool helper (add, adddsc, addrawfile, setdistribution)
+- processincoming changes:
+ * reports and error if a package is not included due to an already existing
+ newer version.
+ * allow ignoring of unused files and newer versions (Permit:)
+ * option when to delete rejected or faulty package (Cleanup:)
+- include command names incldued .changes files like processincoming does
+
+Updates between 2.0.0 and 2.1.0:
+- add --silent option
+- change some status output to stdout instead of stderr.
+- fix some uncessary exporting of index files
+- fix bug in term parsing (for FilterFormula and the like)
+- add Log: mechanism to log to file and execute external helpers
+- example-script to generate a packages.debian.org/changelogs like
+ hierachy with changelog and copyright files.
+
+Updates between 1.3.1 and 2.0.0:
+- add "adddeb" action to changestool
+- fix bug in manpage ("accept" should have been "allow" for uploaders)
+- new AlsoAcceptFor:-header for conf/distributions to allow more fine
+ controled which distributions to allow than just codename/suite
+ or everything (via --ignore=wrongdistribution)
+- fail cleanly when getting a .dsc without Format header
+- fix bug in non-libarchive filelist extraction on large lists
+- add processincoming command to scan an incoming directory and add
+ packages from there. (this needed some refactorisations of other
+ code, so beware)
+- add gensnapshot command
+
+Updates between 1.3.0 and 1.3.1:
+- bugfix in changestool updatechecksums
+
+Updates between 1.2.0 and 1.3.0:
+- now uses libgpgme11 instead of libgpgme6.
+- remove --onlyacceptsigned switch (soon to be be replaced by something
+ useable, hopefully)
+- only reject a package because of signatures if it only has bad signatures
+ and no good one. (Rejecting a package because of a missing key when
+ it would have processed without signature did not really make sense)
+- new --ignore=brokensignatures to also accept packages with broken signatures
+ without any valid signature.
+- Now looks at the Binary: and Version: fields of a .changes file.
+ Unless the new --ignore=wrongversion is specified, a dsc must
+ have the same version, and a .deb must have this source version
+ unless --ignore=wrongsourceversion is given. A .deb must also
+ contain a package listed in the Binary: header unless
+ --ignore=surprisingbinary is given. (A .dsc with an different name
+ or a .deb with an different Source than the Source-header if the
+ .changes file is still not ignoreable due to file naming issues)
+- FilterList in update and pull rules now has a space separated list
+ of filenames instead of only a single filename.
+- new Uploaders field in conf/distributions:
+ specifies what a .changes file has to be signed with to be allowed in
+- new helper program "changestool" to preprocess .changes files.
+
+Updates between 1.1.0 and 1.2.0:
+- improve message of missing files
+- checkin now support .tar.bz2, .diff.bz2 and .tar.bz2
+ (checkindsc did not care, binaries may contain tar.bz2 if reprepro
+ is compiled with libarchive and libbz2)
+- fix bug delaying full Contents- generation
+
+Updates between 1.0.2 and 1.1.0:
+- extended the (experimental) package tracking feature
+- cleartracks removes files losing their last reference (unless --keepunreferenced as usual)
+- fix bug of not generating a uncompressed Sources line in Release when no uncompressed
+ Sources file is generated.
+
+Updates between 1.0.1 and 1.0.2:
+- fix segfault in non-libarchive code introduced with 1.0.0
+
+Updates between 1.0.0 and 1.0.1:
+- add clearvanished command
+- cope with GNU ar style .deb files (when using libarchive)
+- cope with strange control.tar.gz files (when not using libarchive)
+
+Updates between 0.9.1 and 1.0.0:
+- reject some .changes earlier, delete added files
+ when checks after copying files to the pool failed.
+- handle some signals (TERM, ABRT, INT and QUIT) a bit
+ more gracefully
+- some little fixes in the documentation
+- add predelete action to delete packages that would be
+ deleted or replaced in an update
+- add new copy command to copy a single package from
+ one distribution to another.
+
+Updates between 0.9.0 and 0.9.1:
+- fix bug in post-export script handling.
+- fixed documentation in tiffany.example how to generate
+ .diff directories the new apt can read.
+
+Updates between 0.8.2 and 0.9.0:
+- added --export= option and harmonized exporting of
+ distributions. (Now every distribution processed
+ without errors is exported by default, with options
+ for always, never or only export it when changed)
+- added pull and checkpull actions.
+ Those are roughly equivalent to upgrade rules with
+ file:/path/to/basedir Method, but faster and a bit
+ more limited (files cannot change components)
+- fix segfault of checkupdate
+- fix including a changes file with source and restricting
+ to some binary distribution or to binary package type.
+- add support to use libarchive instead of calling ar and tar
+- added Contents file generation support
+- now supporting libdb-4.4, libdb-4.3 and libdb3
+
+Updates between 0.8.1 and 0.8.2:
+- mark process list files and only skip those not marked
+ as processed instead those not newly downloaded.
+- change the wording of some warnings, add some new
+- new WORKAROUND part in the manpage
+- add example bash_completion script
+
+Updates between 0.8 and 0.8.1:
+- some bugfixes (segfault, memmory leak, manpage typos)
+- enforcement of extensions of include{,dsc,deb,udeb} files
+ to .changes,.dsc,.deb,.udeb and new --ignore=extension to
+ circumvent it.
+- support generation of the NotAutomatic field.
+- added --ignore=missingfile to ignore files missing in
+ a .changes file, but lying around and requested by
+ a .dsc file.
+
+Updates between 0.7 and 0.8:
+- unless the new --keepdirectories option is given,
+ try to remove pool/ directories that got empty by
+ removing things from them. (To be exact, try to rmdir(2)
+ them every time, which will only work if they are empty).
+- Unless the new --noskipold is used, only targets with newly
+ downloaded index files are updated. (new = downloaded
+ by the instance of reprepro currently running)
+- reprepro now always puts the checksums of the uncompressed
+ index files into the Release file, even if it is not
+ written to disk. This fixes some problems with newer
+ versions of apt. (Take a look at DscIndices to get older
+ versions of reprepro to please them, too).
+- The export hooks (the programs specified as DebIndices,
+ UDebIndices and DscIndices) are now always called once
+ with the uncompressed names.
+- to compile reprepro with woody without a backported zlib
+ use the -DOLDZLIB switch.
+- reprepro now supports bzip2 output natively. (You can
+ still use the example if you want to call bzip2 yourself
+ instead of using the libbz2 library)
+- new db/release.cache.db file storing md5sums of written
+ index and Release files there. (This can cause Release
+ file give old md5sums when the files are not what it
+ expects, but unless you manually changed them that is
+ a good way to find errors, and manually changing if
+ fragile anyway, so better do not do it but ask me
+ if some feature is missing overrides cannot offer yet).
+
+Updates between 0.6 and 0.7:
+- new --ignore=missingfield,brokenold,brokenversioncmp,
+ unusedarch,surpisingarch
+- Fix segfault when update file is empty.
+ (Thanks to Gianluigi Tiesi for noticing this.)
+- improve manpage a little bit
+- many little tidy ups
+
+Updates between 0.5 and 0.6:
+- no longer set execute bit of generated Release.gpg files
+- use REPREPRO_BASE_DIR for default basedir, parse conf/options
+ for further default options. (and add --no options to disable
+ boolean options again, same for ignore)
+- new command createsymlinks (for symlinks like "stable"->"sarge")
+- parse FilterList default action correctly
+- putting .changes in a distribution not listed is now an error
+ without --ignore=wrongdistribution (and without
+ "ignore wrongdistributions" in conf/options)
+
+Updates between 0.4 and 0.5:
+- starts of source package tracking
+- add quick&dirty --ask-passphrase option
+- SignWith's argument is now used, use "yes" or "default" to get old behaviour
+- allow ~ in versions listed in .changes files
+
+Updates between 0.3 and 0.4:
+- minor bugfix: no longer readd existing packages, when after a delete rule
+ a old package was found first.
+- adopt short-howto to changes in keywords.
+- many tidy ups and little bugfixes
+- add Fallback option to specify another host to get mirrored files from
+- default basedir is now "." i.e. the current directory.
+
+Updates between 0.2 and 0.3:
+- Override: SourceOverride: replaced by (Deb|UDeb|Dsc)Override
+- new command reoverride to reapply override information.
+- sometimes be a bit more verbose
+- new experimental iteratedupdate command , which is a variant of
+ update but needs less memory.
+- to ignore Release signature failures two --force's are needed now.
+
+Updates between 0.1.1 and 0.2:
+- _md5sums command got removed. New command to dump
+ the contents of the files database is _listmd5sums
+- --basedir (alias -b) will no longer override prior
+ given values to --confdir, --listdir, ....
+- fix nasty overflow bug
+- write Release, Packages, and Sources files first
+ to .new variants and move then all at once.
+- new Options DebIndices DscIndices UDebIndices
diff --git a/README b/README
new file mode 100644
index 0000000..e73f65b
--- /dev/null
+++ b/README
@@ -0,0 +1,94 @@
+* What it is:
+
+ This project is a leightweight feature complete manager of a debian
+ package (i.e. binary .deb and source .dsc+.tar.gz+.diff.gz) repository.
+ Emphasis is put on having all packages in the pool/-directory,
+ maximal checking of all sources.
+ generation of signed Release file, Contents, ...
+ Libraries needed are libdb{3,4.?,5.?} and libz.
+ Libraries used if available are libgpgme, libbz2 and libarchive.
+
+* Current status:
+
+ The main features work without problems. Some special use cases
+ might not be very well tested.
+
+* Some naming conventions:
+ basename: the name of a file without any directory information.
+ filekey: the position relative to the mirrordir.
+ (as found as "Filename:" in Packages.gz)
+ full filename: the position relative to /
+
+ architecture: The term like "sparc","i386","mips",...
+ component: Things like "main" "non-free" "contrib" ...
+ (somtimes also called sections)
+ section: Things like "base" "interpreters" "oldlibs"
+ (sometimes also called subsections)
+ type: The kind of packages, currently supported:
+ "deb", "udeb" and "dsc".
+ target: The smallest unit packages are in. A target
+ is specified by the codename of the distribution
+ it is in, the architecture, component and type.
+ When architecture is "source" exactly when
+ the type is "dsc".
+ identifier: an internal string to specify a target,
+ it has the form "<codename>|<component>|source"
+ for type dsc, "<codename>|<component>|<architecture>"
+ for type deb and "u|<codename>|<component>|<architecture>"
+ for type udeb.
+
+ md5sum: The checksum of a file, being in the format
+ "<md5sum of file> <length of file>"
+
+
+* Differences to how other standard tools handle the situation:
+
+ - mirroring:
+ This makes no real mirror of the distribution, but
+ only of it contents. Thus the Index-files will
+ be different. (And thus no longer can be verified
+ by the offical signatures). This means people using
+ this mirror have to trust you to not include anything
+ ugly, as they can only check your signature directly.
+ (Or in other words: not useful for mirroring things
+ to be used by strangers).
+ - location:
+ The directory layout under pool/ is only divided
+ by the component and the sourcename. Ecspecially
+ woody and updates/woody will share the same space,
+ thus avoiding multiple instances of the same file.
+ (Can also cause trouble in the rare cases, when both
+ have a file of the same name with different md5sum.
+ Using -f can help here).
+ - 'byhand'-section
+ This is currently just implemented as alias for '-',
+ to make sure lack of implementation does not cause them
+ to land in a byhand-section...
+ - Override files:
+ Only the ExtraOverride style of apt-ftparchive(1) is
+ supported.
+ (i.e. "packagename Section section\npackagename Maintainer maintainer\n")
+ Note that other than apt-ftparchive case is most likely
+ to be significant. (Having the wrong case in might also
+ cause havoc in apt-ftparchive, as that changes the case of
+ the fieldname, which might confuse other programms...)
+
+* Things that might be intresting to know:
+
+ - guessing the component:
+ If inserting a binary or source package without naming
+ an component, this program has to guess of course.
+ This will done the following way: It will take the
+ first component with the name of the section, being
+ prefix to the section, being suffix to the section
+ or having the section as prefix or any.
+ Thus having specifiend the components:
+ "main non-free contrib non-US/main non-US/non-free non-US/contrib"
+ should map .e.g
+ "non-US" to "non-US/main" and "contrib/editors" to "contrib",
+ while having only "main non-free and contrib" as components should
+ map e.g. "non-US/contrib" to "contrib" and "non-US" to "main".
+
+ NOTE: Always specify main as the first component, if you want things
+ to end up there.
+ NOTE: unlike in dak, non-US and non-us are different things...
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..7f3e63f
--- /dev/null
+++ b/TODO
@@ -0,0 +1,24 @@
+TODO:
+ think about a way to make removesrc work on all distributions ('*'?)
+ -> or make things like remove(src)/list/.. work with distribution globs...
+ write something for manual.html how to manually modify snapshots...
+ write more automated test-cases
+ (not even run in the testcase yet: reoverride, ... (probably many))
+ finish import from incoming dir, implement sending mails to uploader
+ extend FilterList et al to specify type/architecture/component
+ add switch to only include if source is present
+ action to redownload missing pool/ files from some update-rules (looking for md5sum)
+ Fields to exclude architectures and components in update rules,
+ (or alternatively allow ! in inclusion lists).
+
+half far goals:
+ rewrite error handling, caching error messages and handling Ctrl-C better.
+
+far goals:
+ check for unmeet Dependencies
+ for unmeet Build-dependencies.
+ write dokumentation, some examples
+ allow multiple versions in a distribution (needs major rewrite I fear)
+ record timestamp when packages are added.
+ option to keep apt-get'able source to each binary (needs mutliple source versions)
+ switch from libdb?.? to sane database
diff --git a/ac/compile b/ac/compile
new file mode 100755
index 0000000..99e5052
--- /dev/null
+++ b/ac/compile
@@ -0,0 +1,348 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" "" $nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+ file=$1
+ case $file in
+ / | /[!/]*) # absolute file, and not a UNC file
+ if test -z "$file_conv"; then
+ # lazily determine how to convert abs files
+ case `uname -s` in
+ MINGW*)
+ file_conv=mingw
+ ;;
+ CYGWIN*)
+ file_conv=cygwin
+ ;;
+ *)
+ file_conv=wine
+ ;;
+ esac
+ fi
+ case $file_conv/,$2, in
+ *,$file_conv,*)
+ ;;
+ mingw/*)
+ file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+ ;;
+ cygwin/*)
+ file=`cygpath -m "$file" || echo "$file"`
+ ;;
+ wine/*)
+ file=`winepath -w "$file" || echo "$file"`
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+ func_file_conv "$1"
+ if test -z "$lib_path"; then
+ lib_path=$file
+ else
+ lib_path="$lib_path;$file"
+ fi
+ linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+ lib=$1
+ found=no
+ save_IFS=$IFS
+ IFS=';'
+ for dir in $lib_path $LIB
+ do
+ IFS=$save_IFS
+ if $shared && test -f "$dir/$lib.dll.lib"; then
+ found=yes
+ lib=$dir/$lib.dll.lib
+ break
+ fi
+ if test -f "$dir/$lib.lib"; then
+ found=yes
+ lib=$dir/$lib.lib
+ break
+ fi
+ if test -f "$dir/lib$lib.a"; then
+ found=yes
+ lib=$dir/lib$lib.a
+ break
+ fi
+ done
+ IFS=$save_IFS
+
+ if test "$found" != yes; then
+ lib=$lib.lib
+ fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+ # Assume a capable shell
+ lib_path=
+ shared=:
+ linker_opts=
+ for arg
+ do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ eat=1
+ case $2 in
+ *.o | *.[oO][bB][jJ])
+ func_file_conv "$2"
+ set x "$@" -Fo"$file"
+ shift
+ ;;
+ *)
+ func_file_conv "$2"
+ set x "$@" -Fe"$file"
+ shift
+ ;;
+ esac
+ ;;
+ -I)
+ eat=1
+ func_file_conv "$2" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -I*)
+ func_file_conv "${1#-I}" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -l)
+ eat=1
+ func_cl_dashl "$2"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -l*)
+ func_cl_dashl "${1#-l}"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -L)
+ eat=1
+ func_cl_dashL "$2"
+ ;;
+ -L*)
+ func_cl_dashL "${1#-L}"
+ ;;
+ -static)
+ shared=false
+ ;;
+ -Wl,*)
+ arg=${1#-Wl,}
+ save_ifs="$IFS"; IFS=','
+ for flag in $arg; do
+ IFS="$save_ifs"
+ linker_opts="$linker_opts $flag"
+ done
+ IFS="$save_ifs"
+ ;;
+ -Xlinker)
+ eat=1
+ linker_opts="$linker_opts $2"
+ ;;
+ -*)
+ set x "$@" "$1"
+ shift
+ ;;
+ *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+ func_file_conv "$1"
+ set x "$@" -Tp"$file"
+ shift
+ ;;
+ *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+ func_file_conv "$1" mingw
+ set x "$@" "$file"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+ done
+ if test -n "$linker_opts"; then
+ linker_opts="-link$linker_opts"
+ fi
+ exec "$@" $linker_opts
+ exit 1
+}
+
+eat=
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+ cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
+ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
+ func_cl_wrapper "$@" # Doesn't return...
+ ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ # So we strip '-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no '-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # '.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/ac/depcomp b/ac/depcomp
new file mode 100755
index 0000000..65cbf70
--- /dev/null
+++ b/ac/depcomp
@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by 'PROGRAMS ARGS'.
+ object Object file output by 'PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputting dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'. Note that this directory component will
+# be either empty or ending with a '/' character. This is deliberate.
+set_dir_from ()
+{
+ case $1 in
+ */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+ *) dir=;;
+ esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+ base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+ echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+ # If the compiler actually managed to produce a dependency file,
+ # post-process it.
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form 'foo.o: dependency.h'.
+ # Do two passes, one to just change these to
+ # $object: dependency.h
+ # and one to simply output
+ # dependency.h:
+ # which is needed to avoid the deleted-header problem.
+ { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+ sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+ } > "$depfile"
+ rm -f "$tmpdepfile"
+ else
+ make_dummy_depfile
+ fi
+}
+
+# A tabulation character.
+tab=' '
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+ # This is just like msvisualcpp but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+ # This is just like msvc7 but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+ # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+ gccflag=-qmakedep=gcc,-MF
+ depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say). Also, it might not be
+## supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The second -e expression handles DOS-style file names with drive
+ # letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'. On the theory
+## that the space means something, we add a space to the output as
+## well. hp depmode also adds that space, but also prefixes the VPATH
+## to the object. Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like '#:fec' to the end of the
+ # dependency line.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+ | tr "$nl" ' ' >> "$depfile"
+ echo >> "$depfile"
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+xlc)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts '$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ aix_post_process_depfile
+ ;;
+
+tcc)
+ # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+ # FIXME: That version still under development at the moment of writing.
+ # Make that this statement remains true also for stable, released
+ # versions.
+ # It will wrap lines (doesn't matter whether long or short) with a
+ # trailing '\', as in:
+ #
+ # foo.o : \
+ # foo.c \
+ # foo.h \
+ #
+ # It will put a trailing '\' even on the last line, and will use leading
+ # spaces rather than leading tabs (at least since its commit 0394caf7
+ # "Emit spaces for -MD").
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+ # We have to change lines of the first kind to '$object: \'.
+ sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+ # And for each line of the second kind, we have to emit a 'dep.h:'
+ # dummy dependency, to avoid the deleted-header problem.
+ sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file. A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+ # Portland's C compiler understands '-MD'.
+ # Will always output deps to 'file.d' where file is the root name of the
+ # source file under compilation, even if file resides in a subdirectory.
+ # The object file name does not affect the name of the '.d' file.
+ # pgcc 10.2 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using '\' :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+ set_dir_from "$object"
+ # Use the source, not the object, to determine the base name, since
+ # that's sadly what pgcc will do too.
+ set_base_from "$source"
+ tmpdepfile=$base.d
+
+ # For projects that build the same source file twice into different object
+ # files, the pgcc approach of using the *source* file root name can cause
+ # problems in parallel builds. Use a locking strategy to avoid stomping on
+ # the same $tmpdepfile.
+ lockdir=$base.d-lock
+ trap "
+ echo '$0: caught signal, cleaning up...' >&2
+ rmdir '$lockdir'
+ exit 1
+ " 1 2 13 15
+ numtries=100
+ i=$numtries
+ while test $i -gt 0; do
+ # mkdir is a portable test-and-set.
+ if mkdir "$lockdir" 2>/dev/null; then
+ # This process acquired the lock.
+ "$@" -MD
+ stat=$?
+ # Release the lock.
+ rmdir "$lockdir"
+ break
+ else
+ # If the lock is being held by a different process, wait
+ # until the winning process is done or we timeout.
+ while test -d "$lockdir" && test $i -gt 0; do
+ sleep 1
+ i=`expr $i - 1`
+ done
+ fi
+ i=`expr $i - 1`
+ done
+ trap - 1 2 13 15
+ if test $i -le 0; then
+ echo "$0: failed to acquire lock after $numtries attempts" >&2
+ echo "$0: check lockdir '$lockdir'" >&2
+ exit 1
+ fi
+
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add 'dependent.h:' lines.
+ sed -ne '2,${
+ s/^ *//
+ s/ \\*$//
+ s/$/:/
+ p
+ }' "$tmpdepfile" >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in 'foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ set_dir_from "$object"
+ set_base_from "$object"
+
+ if test "$libtool" = yes; then
+ # Libtool generates 2 separate objects for the 2 libraries. These
+ # two compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir$base.o.d # libtool 1.5
+ tmpdepfile2=$dir.libs/$base.o.d # Likewise.
+ tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ # Same post-processing that is required for AIX mode.
+ aix_post_process_depfile
+ ;;
+
+msvc7)
+ if test "$libtool" = yes; then
+ showIncludes=-Wc,-showIncludes
+ else
+ showIncludes=-showIncludes
+ fi
+ "$@" $showIncludes > "$tmpdepfile"
+ stat=$?
+ grep -v '^Note: including file: ' "$tmpdepfile"
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The first sed program below extracts the file names and escapes
+ # backslashes for cygpath. The second sed program outputs the file
+ # name when reading, but also accumulates all include files in the
+ # hold buffer in order to output them again at the end. This only
+ # works with sed implementations that can handle large buffers.
+ sed < "$tmpdepfile" -n '
+/^Note: including file: *\(.*\)/ {
+ s//\1/
+ s/\\/\\\\/g
+ p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+ s/.*/'"$tab"'/
+ G
+ p
+}' >> "$depfile"
+ echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+ rm -f "$tmpdepfile"
+ ;;
+
+msvc7msys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for ':'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+ "$@" $dashmflag |
+ sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this sed invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no eat=no
+ for arg
+ do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ if test $eat = yes; then
+ eat=no
+ continue
+ fi
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -arch)
+ eat=yes ;;
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix=`echo "$object" | sed 's/^.*\././'`
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ # makedepend may prepend the VPATH from the source file name to the object.
+ # No need to regex-escape $object, excess matching of '.' is harmless.
+ sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process the last invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed '1,2d' "$tmpdepfile" \
+ | tr ' ' "$nl" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E \
+ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ | sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E 2>/dev/null |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+ echo "$tab" >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvcmsys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/ac/install-sh b/ac/install-sh
new file mode 100755
index 0000000..8175c64
--- /dev/null
+++ b/ac/install-sh
@@ -0,0 +1,518 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2018-03-11.20; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+tab=' '
+nl='
+'
+IFS=" $tab$nl"
+
+# Set DOITPROG to "echo" to test this script.
+
+doit=${DOITPROG-}
+doit_exec=${doit:-exec}
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+is_target_a_directory=possibly
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t)
+ is_target_a_directory=always
+ dst_arg=$2
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
+
+ -T) is_target_a_directory=never;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+ if test -n "$dst_arg"; then
+ echo "$0: target directory not allowed when installing a directory." >&2
+ exit 1
+ fi
+fi
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call 'install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ if test $# -gt 1 || test "$is_target_a_directory" = always; then
+ if test ! -d "$dst_arg"; then
+ echo "$0: $dst_arg: Is not a directory." >&2
+ exit 1
+ fi
+ fi
+fi
+
+if test -z "$dir_arg"; then
+ do_exit='(exit $ret); exit $ret'
+ trap "ret=129; $do_exit" 1
+ trap "ret=130; $do_exit" 2
+ trap "ret=141; $do_exit" 13
+ trap "ret=143; $do_exit" 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names problematic for 'test' and other utilities.
+ case $src in
+ -* | [=\(\)!]) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+ dst=$dst_arg
+
+ # If destination is a directory, append the input filename.
+ if test -d "$dst"; then
+ if test "$is_target_a_directory" = never; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dstbase=`basename "$src"`
+ case $dst in
+ */) dst=$dst$dstbase;;
+ *) dst=$dst/$dstbase;;
+ esac
+ dstdir_status=0
+ else
+ dstdir=`dirname "$dst"`
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ case $dstdir in
+ */) dstdirslash=$dstdir;;
+ *) dstdirslash=$dstdir/;;
+ esac
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ # Note that $RANDOM variable is not portable (e.g. dash); Use it
+ # here however when possible just to lower collision chance.
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+
+ trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ # Because "mkdir -p" follows existing symlinks and we likely work
+ # directly in world-writeable /tmp, make sure that the '$tmpdir'
+ # directory is successfully created first before we actually test
+ # 'mkdir -p' feature.
+ if (umask $mkdir_umask &&
+ $mkdirprog $mkdir_mode "$tmpdir" &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ test_tmpdir="$tmpdir/a"
+ ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ oIFS=$IFS
+ IFS=/
+ set -f
+ set fnord $dstdir
+ shift
+ set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=${dstdirslash}_inst.$$_
+ rmtmp=${dstdirslash}_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+ set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ set +f &&
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/ac/missing b/ac/missing
new file mode 100755
index 0000000..625aeb1
--- /dev/null
+++ b/ac/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+fi
+
+case $1 in
+
+ --is-lightweight)
+ # Used by our autoconf macros to check whether the available missing
+ # script is modern enough.
+ exit 0
+ ;;
+
+ --run)
+ # Back-compat with the calling convention used by older automake.
+ shift
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal autoconf autoheader autom4te automake makeinfo
+ bison yacc flex lex help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: unknown '$1' option"
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch. This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+ msg="probably too old"
+elif test $st -eq 127; then
+ # Program was missing.
+ msg="missing on your system"
+else
+ # Program was found and executed, but failed. Give up.
+ exit $st
+fi
+
+perl_URL=https://www.perl.org/
+flex_URL=https://github.com/westes/flex
+gnu_software_URL=https://www.gnu.org/software
+
+program_details ()
+{
+ case $1 in
+ aclocal|automake)
+ echo "The '$1' program is part of the GNU Automake package:"
+ echo "<$gnu_software_URL/automake>"
+ echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/autoconf>"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ autoconf|autom4te|autoheader)
+ echo "The '$1' program is part of the GNU Autoconf package:"
+ echo "<$gnu_software_URL/autoconf/>"
+ echo "It also requires GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ esac
+}
+
+give_advice ()
+{
+ # Normalize program name to check for.
+ normalized_program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+ printf '%s\n' "'$1' is $msg."
+
+ configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+ case $normalized_program in
+ autoconf*)
+ echo "You should only need it if you modified 'configure.ac',"
+ echo "or m4 files included by it."
+ program_details 'autoconf'
+ ;;
+ autoheader*)
+ echo "You should only need it if you modified 'acconfig.h' or"
+ echo "$configure_deps."
+ program_details 'autoheader'
+ ;;
+ automake*)
+ echo "You should only need it if you modified 'Makefile.am' or"
+ echo "$configure_deps."
+ program_details 'automake'
+ ;;
+ aclocal*)
+ echo "You should only need it if you modified 'acinclude.m4' or"
+ echo "$configure_deps."
+ program_details 'aclocal'
+ ;;
+ autom4te*)
+ echo "You might have modified some maintainer files that require"
+ echo "the 'autom4te' program to be rebuilt."
+ program_details 'autom4te'
+ ;;
+ bison*|yacc*)
+ echo "You should only need it if you modified a '.y' file."
+ echo "You may want to install the GNU Bison package:"
+ echo "<$gnu_software_URL/bison/>"
+ ;;
+ lex*|flex*)
+ echo "You should only need it if you modified a '.l' file."
+ echo "You may want to install the Fast Lexical Analyzer package:"
+ echo "<$flex_URL>"
+ ;;
+ help2man*)
+ echo "You should only need it if you modified a dependency" \
+ "of a man page."
+ echo "You may want to install the GNU Help2man package:"
+ echo "<$gnu_software_URL/help2man/>"
+ ;;
+ makeinfo*)
+ echo "You should only need it if you modified a '.texi' file, or"
+ echo "any other file indirectly affecting the aspect of the manual."
+ echo "You might want to install the Texinfo package:"
+ echo "<$gnu_software_URL/texinfo/>"
+ echo "The spurious makeinfo call might also be the consequence of"
+ echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+ echo "want to install GNU make:"
+ echo "<$gnu_software_URL/make/>"
+ ;;
+ *)
+ echo "You might have modified some files without having the proper"
+ echo "tools for further handling them. Check the 'README' file, it"
+ echo "often tells you about the needed prerequisites for installing"
+ echo "this package. You may also peek at any GNU archive site, in"
+ echo "case some other package contains this missing '$1' program."
+ ;;
+ esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+ -e '2,$s/^/ /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..c14986f
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,47 @@
+dnl CHECK_ENUM and GET_DEFINE autoconf macros are
+dnl Copyright 2004,2006 Bernhard R. Link
+dnl and hereby in the public domain
+# Check for an enum, which seem to be forgotten in autoconf,
+# as this can neighter be checked with cpp, nor is it a symbol
+m4_define([CHECK_ENUM],
+[AS_VAR_PUSHDEF([check_Enum], [rr_cv_check_enum_$1])dnl
+AC_CACHE_CHECK([for $1 in $2], check_Enum,
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT([$5])
+@%:@include <$2>],
+[ if( $1 == 0 )
+ return 0;
+])],
+ [AS_VAR_SET(check_Enum, yes)],
+ [AS_VAR_SET(check_Enum, no)])])
+AS_IF([test AS_VAR_GET(check_Enum) = yes], [$3], [$4])[]dnl
+AS_VAR_POPDEF([check_Enum])dnl
+])dnl
+# extract the value of a #define from a header
+m4_define([GET_DEFINE],
+[AC_LANG_PREPROC_REQUIRE()dnl
+AS_VAR_PUSHDEF(get_Define, [rr_cv_get_define_$1])dnl
+AC_CACHE_CHECK([for $1], get_Define,
+[dnl
+ m4_ifvaln([$2],[dnl
+ echo "#include <$2>" > conftest.$ac_ext
+ echo "$1" >> conftest.$ac_ext
+ ],[dnl
+ echo "$1" > conftest.$ac_ext
+ ])
+ if _AC_EVAL_STDERR([$ac_cpp conftest.$ac_ext >conftest.out]) >/dev/null; then
+ if test -s conftest.err; then
+ AS_VAR_SET(get_Define, $1)
+ else
+ AS_VAR_SET(get_Define, "$(tail -1 conftest.out)")
+ fi
+ else
+ AS_VAR_SET(get_Define, $1)
+ fi
+ rm -f conftest.err conftest.out conftest.$ac_ext
+])
+TMP_GET_DEFINE=AS_VAR_GET(get_Define)
+TMP_GET_DEFINE=${TMP_GET_DEFINE% }
+TMP_GET_DEFINE=${TMP_GET_DEFINE% }
+AS_IF([test "$TMP_GET_DEFINE" = $1], [$3], [$1="$TMP_GET_DEFINE"])[]dnl
+AS_VAR_POPDEF([get_Define])dnl
+])dnl GET_DEFINE
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..bf0774c
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,1201 @@
+# generated automatically by aclocal 1.16.1 -*- Autoconf -*-
+
+# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# Copyright (C) 2002-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.16'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.16.1], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.16.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC], [depcc="$CC" am_compiler_list=],
+ [$1], [CXX], [depcc="$CXX" am_compiler_list=],
+ [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+ [$1], [UPC], [depcc="$UPC" am_compiler_list=],
+ [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+ [--enable-dependency-tracking],
+ [do not reject slow dependency extractors])
+AS_HELP_STRING(
+ [--disable-dependency-tracking],
+ [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ # TODO: see whether this extra hack can be removed once we start
+ # requiring Autoconf 2.70 or later.
+ AS_CASE([$CONFIG_FILES],
+ [*\'*], [eval set x "$CONFIG_FILES"],
+ [*], [set x $CONFIG_FILES])
+ shift
+ # Used to flag and report bootstrapping failures.
+ am_rc=0
+ for am_mf
+ do
+ # Strip MF so we end up with the name of the file.
+ am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile which includes
+ # dependency-tracking related rules and includes.
+ # Grep'ing the whole file directly is not great: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \
+ || continue
+ am_dirpart=`AS_DIRNAME(["$am_mf"])`
+ am_filepart=`AS_BASENAME(["$am_mf"])`
+ AM_RUN_LOG([cd "$am_dirpart" \
+ && sed -e '/# am--include-marker/d' "$am_filepart" \
+ | $MAKE -f - am--depfiles]) || am_rc=$?
+ done
+ if test $am_rc -ne 0; then
+ AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments
+ for automatic dependency tracking. Try re-running configure with the
+ '--disable-dependency-tracking' option to at least be able to build
+ the package (albeit without support for automatic dependency tracking).])
+ fi
+ AS_UNSET([am_dirpart])
+ AS_UNSET([am_filepart])
+ AS_UNSET([am_mf])
+ AS_UNSET([am_rc])
+ rm -f conftest-deps.mk
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking is enabled.
+# This creates each '.Po' and '.Plo' makefile fragment that we'll need in
+# order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+ [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+ m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+ [ok:ok],,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target (and possibly the TAP driver). The
+# system "awk" is bad on some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES([CC])],
+ [m4_define([AC_PROG_CC],
+ m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES([CXX])],
+ [m4_define([AC_PROG_CXX],
+ m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES([OBJC])],
+ [m4_define([AC_PROG_OBJC],
+ m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+ [_AM_DEPENDENCIES([OBJCXX])],
+ [m4_define([AC_PROG_OBJCXX],
+ m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
+
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <https://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+ AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+ fi
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless 'enable' is passed literally.
+# For symmetry, 'disable' may be passed as well. Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+ [enable], [m4_define([am_maintainer_other], [disable])],
+ [disable], [m4_define([am_maintainer_other], [enable])],
+ [m4_define([am_maintainer_other], [enable])
+ m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+ AC_ARG_ENABLE([maintainer-mode],
+ [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
+ am_maintainer_other[ make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer])],
+ [USE_MAINTAINER_MODE=$enableval],
+ [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST([MAINT])dnl
+]
+)
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check whether make has an 'include' directive that can support all
+# the idioms we need for our automatic dependency tracking code.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive])
+cat > confinc.mk << 'END'
+am__doit:
+ @echo this is the am__doit target >confinc.out
+.PHONY: am__doit
+END
+am__include="#"
+am__quote=
+# BSD make does it like this.
+echo '.include "confinc.mk" # ignored' > confmf.BSD
+# Other make implementations (GNU, Solaris 10, AIX) do it like this.
+echo 'include confinc.mk # ignored' > confmf.GNU
+_am_result=no
+for s in GNU BSD; do
+ AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out])
+ AS_CASE([$?:`cat confinc.out 2>/dev/null`],
+ ['0:this is the am__doit target'],
+ [AS_CASE([$s],
+ [BSD], [am__include='.include' am__quote='"'],
+ [am__include='include' am__quote=''])])
+ if test "$am__include" != "#"; then
+ _am_result="yes ($s style)"
+ break
+ fi
+done
+rm -f confinc.* confmf.*
+AC_MSG_RESULT([${_am_result}])
+AC_SUBST([am__include])])
+AC_SUBST([am__quote])])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# -*- Autoconf -*-
+# Obsolete and "removed" macros, that must however still report explicit
+# error messages when used, to smooth transition.
+#
+# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([AM_CONFIG_HEADER],
+[AC_DIAGNOSE([obsolete],
+['$0': this macro is obsolete.
+You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl
+AC_CONFIG_HEADERS($@)])
+
+AC_DEFUN([AM_PROG_CC_STDC],
+[AC_PROG_CC
+am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc
+AC_DIAGNOSE([obsolete],
+['$0': this macro is obsolete.
+You should simply use the 'AC][_PROG_CC' macro instead.
+Also, your code should no longer depend upon 'am_cv_prog_cc_stdc',
+but upon 'ac_cv_prog_cc_stdc'.])])
+
+AC_DEFUN([AM_C_PROTOTYPES],
+ [AC_FATAL([automatic de-ANSI-fication support has been removed])])
+AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+ [whether $CC understands -c and -o together],
+ [am_cv_prog_cc_c_o],
+ [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+ ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+ alias in your environment])
+ fi
+ if test "$[2]" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+ [AC_MSG_CHECKING([that generated files are newer than configure])
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+ [--enable-silent-rules],
+ [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+ [--disable-silent-rules],
+ [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+ [am_cv_make_support_nested_variables],
+ [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+ dnl Using '$V' instead of '$(V)' breaks IRIX make.
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004-2018 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+ [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+ [m4_case([$1],
+ [ustar],
+ [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+ # There is notably a 21 bits limit for the UID and the GID. In fact,
+ # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+ # and bug#13588).
+ am_max_uid=2097151 # 2^21 - 1
+ am_max_gid=$am_max_uid
+ # The $UID and $GID variables are not portable, so we need to resort
+ # to the POSIX-mandated id(1) utility. Errors in the 'id' calls
+ # below are definitely unexpected, so allow the users to see them
+ # (that is, avoid stderr redirection).
+ am_uid=`id -u || echo unknown`
+ am_gid=`id -g || echo unknown`
+ AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+ if test $am_uid -le $am_max_uid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi
+ AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+ if test $am_gid -le $am_max_gid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi],
+
+ [pax],
+ [],
+
+ [m4_fatal([Unknown tar format])])
+
+ AC_MSG_CHECKING([how to create a $1 tar archive])
+
+ # Go ahead even if we have the value already cached. We do so because we
+ # need to set the values for the 'am__tar' and 'am__untar' variables.
+ _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+ for _am_tool in $_am_tools; do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar; do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ AM_RUN_LOG([cat conftest.dir/file])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+ done
+ rm -rf conftest.dir
+
+ AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+ AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([acinclude.m4])
diff --git a/aptmethod.c b/aptmethod.c
new file mode 100644
index 0000000..bcc13cf
--- /dev/null
+++ b/aptmethod.c
@@ -0,0 +1,1216 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2004,2005,2007,2008,2009,2012 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <errno.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include "error.h"
+#include "mprintf.h"
+#include "strlist.h"
+#include "names.h"
+#include "dirs.h"
+#include "chunks.h"
+#include "checksums.h"
+#include "files.h"
+#include "uncompression.h"
+#include "aptmethod.h"
+#include "filecntl.h"
+#include "hooks.h"
+
+struct tobedone {
+ /*@null@*/
+ struct tobedone *next;
+ /* must be saved to know where is should be moved to: */
+ /*@notnull@*/
+ char *uri;
+ /*@notnull@*/
+ char *filename;
+ /* in case of redirection, store the originally requested uri: */
+ /*@null@*/
+ char *original_uri;
+ /* callback and its data: */
+ queue_callback *callback;
+ /*@null@*/void *privdata1, *privdata2;
+ /* there is no fallback or that was already used */
+ bool lasttry;
+ /* how often this was redirected */
+ unsigned int redirect_count;
+};
+
+struct aptmethod {
+ /*@only@*/ /*@null@*/
+ struct aptmethod *next;
+ char *name;
+ char *baseuri;
+ /*@null@*/char *fallbackbaseuri;
+ /*@null@*/char *config;
+ int mstdin, mstdout;
+ pid_t child;
+
+ enum {
+ ams_notstarted=0,
+ ams_waitforcapabilities,
+ ams_ok,
+ ams_failed
+ } status;
+
+ /*@null@*/struct tobedone *tobedone;
+ /*@null@*//*@dependent@*/struct tobedone *lasttobedone;
+ /*@null@*//*@dependent@*/const struct tobedone *nexttosend;
+ /* what is currently read: */
+ /*@null@*/char *inputbuffer;
+ size_t input_size, alreadyread;
+ /* What is currently written: */
+ /*@null@*/char *command;
+ size_t alreadywritten, output_length;
+};
+
+struct aptmethodrun {
+ struct aptmethod *methods;
+};
+
+static void todo_free(/*@only@*/ struct tobedone *todo) {
+ free(todo->filename);
+ free(todo->original_uri);
+ free(todo->uri);
+ free(todo);
+}
+
+static void free_todolist(/*@only@*/ struct tobedone *todo) {
+
+ while (todo != NULL) {
+ struct tobedone *h = todo->next;
+
+ todo_free(todo);
+ todo = h;
+ }
+}
+
+static void aptmethod_free(/*@only@*/struct aptmethod *method) {
+ if (method == NULL)
+ return;
+ free(method->name);
+ free(method->baseuri);
+ free(method->config);
+ free(method->fallbackbaseuri);
+ free(method->inputbuffer);
+ free(method->command);
+
+ free_todolist(method->tobedone);
+
+ free(method);
+}
+
+retvalue aptmethod_shutdown(struct aptmethodrun *run) {
+ retvalue result = RET_OK, r;
+ struct aptmethod *method, *lastmethod, **method_ptr;
+
+ /* first get rid of everything not running: */
+ method_ptr = &run->methods;
+ while (*method_ptr != NULL) {
+
+ if ((*method_ptr)->child > 0) {
+ if (verbose > 10)
+ fprintf(stderr,
+"Still waiting for %d\n", (int)(*method_ptr)->child);
+ method_ptr = &(*method_ptr)->next;
+ continue;
+ } else {
+ /*@only@*/ struct aptmethod *h;
+ h = (*method_ptr);
+ *method_ptr = h->next;
+ h->next = NULL;
+ aptmethod_free(h);
+ }
+ }
+
+ /* finally get rid of all the processes: */
+ for (method = run->methods ; method != NULL ; method = method->next) {
+ if (method->mstdin >= 0) {
+ (void)close(method->mstdin);
+ if (verbose > 30)
+ fprintf(stderr, "Closing stdin of %d\n",
+ (int)method->child);
+ }
+ method->mstdin = -1;
+ if (method->mstdout >= 0) {
+ (void)close(method->mstdout);
+ if (verbose > 30)
+ fprintf(stderr, "Closing stdout of %d\n",
+ (int)method->child);
+ }
+ method->mstdout = -1;
+ }
+ while (run->methods != NULL || uncompress_running()) {
+ pid_t pid;int status;
+
+ pid = wait(&status);
+ lastmethod = NULL; method = run->methods;
+ while (method != NULL) {
+ if (method->child == pid) {
+ struct aptmethod *next = method->next;
+
+ if (lastmethod != NULL) {
+ lastmethod->next = next;
+ } else
+ run->methods = next;
+
+ aptmethod_free(method);
+ pid = -1;
+ break;
+ } else {
+ lastmethod = method;
+ method = method->next;
+ }
+ }
+ if (pid > 0) {
+ r = uncompress_checkpid(pid, status);
+ RET_UPDATE(result, r);
+ }
+ }
+ free(run);
+ return result;
+}
+
+/******************Initialize the data structures***********************/
+
+retvalue aptmethod_initialize_run(struct aptmethodrun **run) {
+ struct aptmethodrun *r;
+
+ r = zNEW(struct aptmethodrun);
+ if (FAILEDTOALLOC(r))
+ return RET_ERROR_OOM;
+ *run = r;
+ return RET_OK;
+}
+
+retvalue aptmethod_newmethod(struct aptmethodrun *run, const char *uri, const char *fallbackuri, const struct strlist *config, struct aptmethod **m) {
+ struct aptmethod *method;
+ const char *p;
+
+ method = zNEW(struct aptmethod);
+ if (FAILEDTOALLOC(method))
+ return RET_ERROR_OOM;
+ method->mstdin = -1;
+ method->mstdout = -1;
+ method->child = -1;
+ method->status = ams_notstarted;
+ p = uri;
+ while (*p != '\0' && (*p == '_' || *p == '-' || *p == '+' ||
+ (*p>='a' && *p<='z') || (*p>='A' && *p<='Z') ||
+ (*p>='0' && *p<='9'))) {
+ p++;
+ }
+ if (*p == '\0') {
+ fprintf(stderr, "No colon found in method-URI '%s'!\n", uri);
+ free(method);
+ return RET_ERROR;
+ }
+ if (*p != ':') {
+ fprintf(stderr,
+"Unexpected character '%c' in method-URI '%s'!\n", *p, uri);
+ free(method);
+ return RET_ERROR;
+ }
+ if (p == uri) {
+ fprintf(stderr,
+"Zero-length name in method-URI '%s'!\n", uri);
+ free(method);
+ return RET_ERROR;
+ }
+
+ method->name = strndup(uri, p-uri);
+ if (FAILEDTOALLOC(method->name)) {
+ free(method);
+ return RET_ERROR_OOM;
+ }
+ method->baseuri = strdup(uri);
+ if (FAILEDTOALLOC(method->baseuri)) {
+ free(method->name);
+ free(method);
+ return RET_ERROR_OOM;
+ }
+ if (fallbackuri == NULL)
+ method->fallbackbaseuri = NULL;
+ else {
+ method->fallbackbaseuri = strdup(fallbackuri);
+ if (FAILEDTOALLOC(method->fallbackbaseuri)) {
+ free(method->baseuri);
+ free(method->name);
+ free(method);
+ return RET_ERROR_OOM;
+ }
+ }
+#define CONF601 "601 Configuration"
+#define CONFITEM "\nConfig-Item: "
+ if (config->count == 0)
+ method->config = strdup(CONF601 CONFITEM "Dir=/" "\n\n");
+ else
+ method->config = strlist_concat(config,
+ CONF601 CONFITEM, CONFITEM, "\n\n");
+ if (FAILEDTOALLOC(method->config)) {
+ free(method->fallbackbaseuri);
+ free(method->baseuri);
+ free(method->name);
+ free(method);
+ return RET_ERROR_OOM;
+ }
+ method->next = run->methods;
+ run->methods = method;
+ *m = method;
+ return RET_OK;
+}
+
+/**************************Fire up a method*****************************/
+
+inline static retvalue aptmethod_startup(struct aptmethod *method) {
+ pid_t f;
+ int mstdin[2];
+ int mstdout[2];
+ int r;
+
+ /* When there is nothing to get, there is no reason to startup
+ * the method. */
+ if (method->tobedone == NULL) {
+ return RET_NOTHING;
+ }
+
+ /* when we are already running, we are already ready...*/
+ if (method->child > 0) {
+ return RET_OK;
+ }
+
+ method->status = ams_waitforcapabilities;
+
+ r = pipe(mstdin);
+ if (r < 0) {
+ int e = errno;
+ fprintf(stderr, "Error %d creating pipe: %s\n",
+ e, strerror(e));
+ return RET_ERRNO(e);
+ }
+ r = pipe(mstdout);
+ if (r < 0) {
+ int e = errno;
+ (void)close(mstdin[0]); (void)close(mstdin[1]);
+ fprintf(stderr, "Error %d in pipe syscall: %s\n",
+ e, strerror(e));
+ return RET_ERRNO(e);
+ }
+
+ if (interrupted()) {
+ (void)close(mstdin[0]);(void)close(mstdin[1]);
+ (void)close(mstdout[0]);(void)close(mstdout[1]);
+ return RET_ERROR_INTERRUPTED;
+ }
+ f = fork();
+ if (f < 0) {
+ int e = errno;
+ (void)close(mstdin[0]); (void)close(mstdin[1]);
+ (void)close(mstdout[0]); (void)close(mstdout[1]);
+ fprintf(stderr, "Error %d forking: %s\n",
+ e, strerror(e));
+ return RET_ERRNO(e);
+ }
+ if (f == 0) {
+ char *methodname;
+ int e;
+ /* child: */
+ (void)close(mstdin[1]);
+ (void)close(mstdout[0]);
+ if (dup2(mstdin[0], 0) < 0) {
+ e = errno;
+ fprintf(stderr, "Error %d while setting stdin: %s\n",
+ e, strerror(e));
+ exit(255);
+ }
+ if (dup2(mstdout[1], 1) < 0) {
+ e = errno;
+ fprintf(stderr, "Error %d while setting stdout: %s\n",
+ e, strerror(e));
+ exit(255);
+ }
+ closefrom(3);
+
+ methodname = calc_dirconcat(global.methoddir, method->name);
+ if (FAILEDTOALLOC(methodname))
+ exit(255);
+
+ /* not really useful here, unless someone write reprepro
+ * specific modules (which I hope no one will) */
+ sethookenvironment(NULL, NULL, NULL, NULL);
+ /* actually call the method without any arguments: */
+ (void)execl(methodname, methodname, ENDOFARGUMENTS);
+
+ e = errno;
+ fprintf(stderr, "Error %d while executing '%s': %s\n",
+ e, methodname, strerror(e));
+ exit(255);
+ }
+ /* the main program continues... */
+ method->child = f;
+ if (verbose > 10)
+ fprintf(stderr,
+"Method '%s' started as %d\n", method->baseuri, (int)f);
+ (void)close(mstdin[0]);
+ (void)close(mstdout[1]);
+ markcloseonexec(mstdin[1]);
+ markcloseonexec(mstdout[0]);
+ method->mstdin = mstdin[1];
+ method->mstdout = mstdout[0];
+ method->inputbuffer = NULL;
+ method->input_size = 0;
+ method->alreadyread = 0;
+ method->command = NULL;
+ method->output_length = 0;
+ method->alreadywritten = 0;
+ return RET_OK;
+}
+
+/**************************how to add files*****************************/
+
+static inline void enqueue(struct aptmethod *method, /*@only@*/struct tobedone *todo) {
+ todo->next = NULL;
+ if (method->lasttobedone == NULL)
+ method->nexttosend = method->lasttobedone = method->tobedone = todo;
+ else {
+ method->lasttobedone->next = todo;
+ method->lasttobedone = todo;
+ if (method->nexttosend == NULL)
+ method->nexttosend = todo;
+ }
+}
+
+static retvalue enqueuenew(struct aptmethod *method, /*@only@*/char *uri, /*@only@*/char *destfile, queue_callback *callback, void *privdata1, void *privdata2) {
+ struct tobedone *todo;
+
+ if (FAILEDTOALLOC(destfile)) {
+ free(uri);
+ return RET_ERROR_OOM;
+ }
+ if (FAILEDTOALLOC(uri)) {
+ free(destfile);
+ return RET_ERROR_OOM;
+ }
+
+ todo = NEW(struct tobedone);
+ if (FAILEDTOALLOC(todo)) {
+ free(uri); free(destfile);
+ return RET_ERROR_OOM;
+ }
+
+ todo->next = NULL;
+ todo->uri = uri;
+ todo->filename = destfile;
+ todo->original_uri = NULL;
+ todo->callback = callback;
+ todo->privdata1 = privdata1;
+ todo->privdata2 = privdata2;
+ todo->lasttry = method->fallbackbaseuri == NULL;
+ todo->redirect_count = 0;
+ enqueue(method, todo);
+ return RET_OK;
+}
+
+retvalue aptmethod_enqueue(struct aptmethod *method, const char *origfile, /*@only@*/char *destfile, queue_callback *callback, void *privdata1, void *privdata2) {
+ return enqueuenew(method,
+ calc_dirconcat(method->baseuri, origfile),
+ destfile, callback, privdata1, privdata2);
+}
+
+retvalue aptmethod_enqueueindex(struct aptmethod *method, const char *suite, const char *origfile, const char *suffix, const char *destfile, const char *downloadsuffix, queue_callback *callback, void *privdata1, void *privdata2) {
+ return enqueuenew(method,
+ mprintf("%s/%s/%s%s",
+ method->baseuri, suite, origfile, suffix),
+ mprintf("%s%s", destfile, downloadsuffix),
+ callback, privdata1, privdata2);
+}
+
+/*****************what to do with received files************************/
+
+static retvalue requeue_or_fail(struct aptmethod *method, /*@only@*/struct tobedone *todo) {
+ retvalue r;
+
+ if (todo->lasttry) {
+ if (todo->callback == NULL)
+ r = RET_ERROR;
+ else
+ r = todo->callback(qa_error,
+ todo->privdata1, todo->privdata2,
+ todo->uri, NULL, todo->filename,
+ NULL, method->name);
+ todo_free(todo);
+ return r;
+ } else {
+ size_t l, old_len, new_len;
+ char *s;
+
+ assert (method->fallbackbaseuri != NULL);
+
+ old_len = strlen(method->baseuri);
+ new_len = strlen(method->fallbackbaseuri);
+ l = strlen(todo->uri);
+ s = malloc(l+new_len+1-old_len);
+ if (FAILEDTOALLOC(s)) {
+ todo_free(todo);
+ return RET_ERROR_OOM;
+ }
+ memcpy(s, method->fallbackbaseuri, new_len);
+ strcpy(s+new_len, todo->uri + old_len);
+ free(todo->uri);
+ todo->uri = s;
+ todo->lasttry = true;
+ todo->redirect_count = 0;
+ enqueue(method, todo);
+ return RET_OK;
+ }
+}
+
+/* look which file could not be received and remove it: */
+static retvalue urierror(struct aptmethod *method, const char *uri, /*@only@*/char *message) {
+ struct tobedone *todo, *lasttodo;
+
+ lasttodo = NULL; todo = method->tobedone;
+ while (todo != NULL) {
+ if (strcmp(todo->uri, uri) == 0) {
+
+ /* remove item: */
+ if (lasttodo == NULL)
+ method->tobedone = todo->next;
+ else
+ lasttodo->next = todo->next;
+ if (method->nexttosend == todo) {
+ /* just in case some method received
+ * files before we request them ;-) */
+ method->nexttosend = todo->next;
+ }
+ if (method->lasttobedone == todo) {
+ method->lasttobedone = todo->next;
+ }
+ fprintf(stderr,
+"aptmethod error receiving '%s':\n'%s'\n",
+ uri, (message != NULL)?message:"");
+ /* put message in failed items to show it later? */
+ free(message);
+ return requeue_or_fail(method, todo);
+ }
+ lasttodo = todo;
+ todo = todo->next;
+ }
+ /* huh? If if have not asked for it, how can there be errors? */
+ fprintf(stderr,
+"Method '%s' reported error with unrequested file '%s':\n'%s'!\n",
+ method->name, uri, message);
+ free(message);
+ return RET_ERROR;
+}
+
+/* look which file could not be received and readd the new name... */
+static retvalue uriredirect(struct aptmethod *method, const char *uri, /*@only@*/char *newuri) {
+ struct tobedone *todo, *lasttodo;
+
+ lasttodo = NULL; todo = method->tobedone;
+ while (todo != NULL) {
+ if (strcmp(todo->uri, uri) == 0) {
+
+ /* remove item: */
+ if (lasttodo == NULL)
+ method->tobedone = todo->next;
+ else
+ lasttodo->next = todo->next;
+ if (method->nexttosend == todo) {
+ /* just in case some method received
+ * files before we request them ;-) */
+ method->nexttosend = todo->next;
+ }
+ if (method->lasttobedone == todo) {
+ method->lasttobedone = todo->next;
+ }
+ if (todo->redirect_count < 10) {
+ if (verbose > 0)
+ fprintf(stderr,
+"aptmethod redirects '%s' to '%s'\n",
+ uri, newuri);
+ /* readd with new uri */
+ if (todo->original_uri != NULL)
+ free(todo->uri);
+ else
+ todo->original_uri = todo->uri;
+ todo->uri = newuri;
+ todo->redirect_count++;
+ enqueue(method, todo);
+ return RET_OK;
+ }
+ fprintf(stderr,
+"redirect loop (or too many redirects) detected, original uri is '%s'\n",
+ todo->original_uri);
+ /* put message in failed items to show it later? */
+ free(newuri);
+ return requeue_or_fail(method, todo);
+ }
+ lasttodo = todo;
+ todo = todo->next;
+ }
+ /* huh? If if have not asked for it, how can there be errors? */
+ fprintf(stderr,
+"Method '%s' reported redirect for unrequested file '%s'-> '%s'\n",
+ method->name, uri, newuri);
+ free(newuri);
+ return RET_ERROR;
+}
+
+/* look where a received file has to go to: */
+static retvalue uridone(struct aptmethod *method, const char *uri, const char *filename, /*@only@*//*@null@*/struct checksums *checksumsfromapt) {
+ struct tobedone *todo, *lasttodo;
+ retvalue r;
+
+ lasttodo = NULL; todo = method->tobedone;
+ while (todo != NULL) {
+ if (strcmp(todo->uri, uri) != 0) {
+ lasttodo = todo;
+ todo = todo->next;
+ continue;
+ }
+
+ r = todo->callback(qa_got,
+ todo->privdata1, todo->privdata2,
+ todo->original_uri? todo->original_uri : todo->uri,
+ filename, todo->filename,
+ checksumsfromapt, method->name);
+ checksums_free(checksumsfromapt);
+
+ /* remove item: */
+ if (lasttodo == NULL)
+ method->tobedone = todo->next;
+ else
+ lasttodo->next = todo->next;
+ if (method->nexttosend == todo) {
+ /* just in case some method received
+ * files before we request them ;-) */
+ method->nexttosend = todo->next;
+ }
+ if (method->lasttobedone == todo) {
+ method->lasttobedone = todo->next;
+ }
+ todo_free(todo);
+ return r;
+ }
+ /* huh? */
+ fprintf(stderr,
+"Method '%s' retrieved unexpected file '%s' at '%s'!\n",
+ method->name, uri, filename);
+ checksums_free(checksumsfromapt);
+ return RET_ERROR;
+}
+
+/***************************Input and Output****************************/
+static retvalue logmessage(const struct aptmethod *method, const char *chunk, const char *type) {
+ retvalue r;
+ char *message;
+
+ r = chunk_getvalue(chunk, "Message", &message);
+ if (RET_WAS_ERROR(r))
+ return r;
+ if (RET_IS_OK(r)) {
+ fprintf(stderr, "aptmethod '%s': '%s'\n",
+ method->baseuri, message);
+ free(message);
+ return RET_OK;
+ }
+ r = chunk_getvalue(chunk, "URI", &message);
+ if (RET_WAS_ERROR(r))
+ return r;
+ if (RET_IS_OK(r)) {
+ fprintf(stderr, "aptmethod %s '%s'\n", type, message);
+ free(message);
+ return RET_OK;
+ }
+ fprintf(stderr, "aptmethod '%s': '%s'\n", method->baseuri, type);
+ return RET_OK;
+}
+static inline retvalue gotcapabilities(struct aptmethod *method, const char *chunk) {
+ retvalue r;
+
+ r = chunk_gettruth(chunk, "Single-Instance");
+ if (RET_WAS_ERROR(r))
+ return r;
+// TODO: what to do with this?
+// if (r != RET_NOTHING) {
+// fprintf(stderr, "WARNING: Single-instance not yet supported!\n");
+// }
+ r = chunk_gettruth(chunk, "Send-Config");
+ if (RET_WAS_ERROR(r))
+ return r;
+ if (r != RET_NOTHING) {
+ assert(method->command == NULL);
+ method->alreadywritten = 0;
+ method->command = method->config;
+ method->config = NULL;
+ method->output_length = strlen(method->command);
+ if (verbose > 11) {
+ fprintf(stderr, "Sending config: '%s'\n",
+ method->command);
+ }
+ } else {
+ free(method->config);
+ method->config = NULL;
+ }
+ method->status = ams_ok;
+ return RET_OK;
+}
+
+static inline retvalue goturidone(struct aptmethod *method, const char *chunk) {
+ static const char * const method_hash_names[cs_COUNT] =
+ { "MD5-Hash", "SHA1-Hash", "SHA256-Hash",
+ "Size" };
+ retvalue result, r;
+ char *uri, *filename;
+ enum checksumtype type;
+ char *hashes[cs_COUNT];
+ struct checksums *checksums = NULL;
+
+ //TODO: is it worth the mess to make this in-situ?
+
+ r = chunk_getvalue(chunk, "URI", &uri);
+ if (r == RET_NOTHING) {
+ fprintf(stderr,
+"Missing URI header in uridone received from '%s' method!\n",
+ method->name);
+ r = RET_ERROR;
+ method->status = ams_failed;
+ }
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ r = chunk_getvalue(chunk, "Filename", &filename);
+ if (r == RET_NOTHING) {
+ char *altfilename;
+
+ r = chunk_getvalue(chunk, "Alt-Filename", &altfilename);
+ if (r == RET_NOTHING) {
+ fprintf(stderr,
+"Missing Filename header in uridone received from '%s' method!\n",
+ method->name);
+ r = urierror(method, uri, strdup(
+"<no error but missing Filename from apt-method>"));
+ } else {
+ r = urierror(method, uri, mprintf(
+"<File not there, apt-method suggests '%s' instead>", altfilename));
+ free(altfilename);
+ }
+ free(uri);
+ return r;
+ }
+ if (RET_WAS_ERROR(r)) {
+ free(uri);
+ return r;
+ }
+ if (verbose >= 1)
+ fprintf(stderr, "aptmethod got '%s'\n", uri);
+
+ result = RET_NOTHING;
+ for (type = cs_md5sum ; type < cs_COUNT ; type++) {
+ hashes[type] = NULL;
+ r = chunk_getvalue(chunk, method_hash_names[type],
+ &hashes[type]);
+ RET_UPDATE(result, r);
+ }
+ if (RET_IS_OK(result) && hashes[cs_md5sum] == NULL) {
+ /* the lenny version also has this, better ask for
+ * in case the old MD5-Hash vanishes in the future */
+ r = chunk_getvalue(chunk, "MD5Sum-Hash", &hashes[cs_md5sum]);
+ RET_UPDATE(result, r);
+ }
+ if (RET_WAS_ERROR(result)) {
+ free(uri); free(filename);
+ for (type = cs_md5sum ; type < cs_COUNT ; type++)
+ free(hashes[type]);
+ return result;
+ }
+ if (RET_IS_OK(result)) {
+ /* ignore errors, we can recompute them from the file */
+ (void)checksums_init(&checksums, hashes);
+ }
+ r = uridone(method, uri, filename, checksums);
+ free(uri);
+ free(filename);
+ return r;
+}
+
+static inline retvalue goturierror(struct aptmethod *method, const char *chunk) {
+ retvalue r;
+ char *uri, *message;
+
+ r = chunk_getvalue(chunk, "URI", &uri);
+ if (r == RET_NOTHING) {
+ fprintf(stderr,
+"Missing URI header in urierror received from '%s' method!\n", method->name);
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ r = chunk_getvalue(chunk, "Message", &message);
+ if (r == RET_NOTHING) {
+ message = NULL;
+ }
+ if (RET_WAS_ERROR(r)) {
+ free(uri);
+ return r;
+ }
+
+ r = urierror(method, uri, message);
+ free(uri);
+ return r;
+}
+
+static inline retvalue gotredirect(struct aptmethod *method, const char *chunk) {
+ char *uri, *newuri;
+ retvalue r;
+
+ r = chunk_getvalue(chunk, "URI", &uri);
+ if (r == RET_NOTHING) {
+ fprintf(stderr,
+"Missing URI header in uriredirect received from '%s' method!\n", method->name);
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r))
+ return r;
+ r = chunk_getvalue(chunk, "New-URI", &newuri);
+ if (r == RET_NOTHING) {
+ fprintf(stderr,
+"Missing New-URI header in uriredirect received from '%s' method!\n", method->name);
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r)) {
+ free(uri);
+ return r;
+ }
+ r = uriredirect(method, uri, newuri);
+ free(uri);
+ return r;
+}
+
+static inline retvalue parsereceivedblock(struct aptmethod *method, const char *input) {
+ const char *p;
+ retvalue r;
+#define OVERLINE {while (*p != '\0' && *p != '\n') p++; if (*p == '\n') p++; }
+
+ while (*input == '\n' || *input == '\r')
+ input++;
+ if (*input == '\0') {
+ fprintf(stderr,
+"Unexpected number of newlines from '%s' method!\n", method->name);
+ return RET_NOTHING;
+ }
+ p = input;
+ switch ((*(input+1)=='0')?*input:'\0') {
+ case '1':
+ switch (*(input+2)) {
+ /* 100 Capabilities */
+ case '0':
+ OVERLINE;
+ if (verbose > 14) {
+ fprintf(stderr, "Got '%s'\n",
+ input);
+ }
+ return gotcapabilities(method, input);
+ /* 101 Log */
+ case '1':
+ if (verbose > 10) {
+ OVERLINE;
+ return logmessage(method, p, "101");
+ }
+ return RET_OK;
+ /* 102 Status */
+ case '2':
+ if (verbose > 5) {
+ OVERLINE;
+ return logmessage(method, p, "102");
+ }
+ return RET_OK;
+ /* 103 Redirect */
+ case '3':
+ OVERLINE;
+ return gotredirect(method, p);
+ default:
+ fprintf(stderr,
+"Error or unsupported message received: '%s'\n",
+ input);
+ return RET_ERROR;
+ }
+ case '2':
+ switch (*(input+2)) {
+ /* 200 URI Start */
+ case '0':
+ if (verbose > 5) {
+ OVERLINE;
+ return logmessage(method, p, "start");
+ }
+ return RET_OK;
+ /* 201 URI Done */
+ case '1':
+ OVERLINE;
+ return goturidone(method, p);
+ default:
+ fprintf(stderr,
+"Error or unsupported message received: '%s'\n",
+ input);
+ return RET_ERROR;
+ }
+
+ case '4':
+ switch (*(input+2)) {
+ case '0':
+ OVERLINE;
+ r = goturierror(method, p);
+ break;
+ case '1':
+ OVERLINE;
+ (void)logmessage(method, p, "general error");
+ method->status = ams_failed;
+ r = RET_ERROR;
+ break;
+ default:
+ fprintf(stderr,
+"Error or unsupported message received: '%s'\n",
+ input);
+ r = RET_ERROR;
+ }
+ /* a failed download is not a error yet, as it might
+ * be redone from another source later */
+ return r;
+ default:
+ fprintf(stderr,
+"Unexpected data from '%s' method: '%s'\n",
+ method->name, input);
+ return RET_ERROR;
+ }
+}
+
+static retvalue receivedata(struct aptmethod *method) {
+ retvalue result;
+ ssize_t r;
+ char *p;
+ int consecutivenewlines;
+
+ assert (method->status != ams_ok || method->tobedone != NULL);
+ if (method->status != ams_waitforcapabilities
+ && method->status != ams_ok)
+ return RET_NOTHING;
+
+ /* First look if we have enough room to read.. */
+ if (method->alreadyread + 1024 >= method->input_size) {
+ char *newptr;
+
+ if (method->input_size >= (size_t)128000) {
+ fprintf(stderr,
+"Ridiculously long answer from method!\n");
+ method->status = ams_failed;
+ return RET_ERROR;
+ }
+
+ newptr = realloc(method->inputbuffer, method->alreadyread+1024);
+ if (FAILEDTOALLOC(newptr)) {
+ return RET_ERROR_OOM;
+ }
+ method->inputbuffer = newptr;
+ method->input_size = method->alreadyread + 1024;
+ }
+ assert (method->inputbuffer != NULL);
+ /* then read as much as the pipe is able to fill of our buffer */
+
+ r = read(method->mstdout, method->inputbuffer + method->alreadyread,
+ method->input_size - method->alreadyread - 1);
+
+ if (r < 0) {
+ int e = errno;
+ fprintf(stderr, "Error %d reading pipe from aptmethod: %s\n",
+ e, strerror(e));
+ method->status = ams_failed;
+ return RET_ERRNO(e);
+ }
+ method->alreadyread += r;
+
+ result = RET_NOTHING;
+ while(true) {
+ retvalue res;
+
+ r = method->alreadyread;
+ p = method->inputbuffer;
+ consecutivenewlines = 0;
+
+ while (r > 0) {
+ if (*p == '\0') {
+ fprintf(stderr,
+"Unexpected Zeroes in method output!\n");
+ method->status = ams_failed;
+ return RET_ERROR;
+ } else if (*p == '\n') {
+ consecutivenewlines++;
+ if (consecutivenewlines >= 2)
+ break;
+ } else if (*p != '\r') {
+ consecutivenewlines = 0;
+ }
+ p++; r--;
+ }
+ if (r <= 0) {
+ return result;
+ }
+ *p ='\0'; p++; r--;
+ res = parsereceivedblock(method, method->inputbuffer);
+ if (r > 0)
+ memmove(method->inputbuffer, p, r);
+ method->alreadyread = r;
+ RET_UPDATE(result, res);
+ }
+}
+
+static retvalue senddata(struct aptmethod *method) {
+ size_t l;
+ ssize_t r;
+
+ if (method->status != ams_ok)
+ return RET_NOTHING;
+
+ if (method->command == NULL) {
+ const struct tobedone *todo;
+
+ /* nothing queued to send, nothing to be queued...*/
+ todo = method->nexttosend;
+ if (todo == NULL)
+ return RET_OK;
+
+ if (interrupted())
+ return RET_ERROR_INTERRUPTED;
+
+ method->alreadywritten = 0;
+ // TODO: make sure this is already checked for earlier...
+ assert (strchr(todo->uri, '\n') == NULL &&
+ strchr(todo->filename, '\n') == NULL);
+ /* http-aptmethod seems to loose the last byte,
+ * if the file is already in place,
+ * so we better unlink the target first...
+ * but this is done elsewhere already
+ unlink(todo->filename);
+ */
+ method->command = mprintf(
+ "600 URI Acquire\nURI: %s\nFilename: %s\n\n",
+ todo->uri, todo->filename);
+ if (FAILEDTOALLOC(method->command)) {
+ return RET_ERROR_OOM;
+ }
+ if (verbose > 20)
+ fprintf(stderr, "Will sent: '%s'\n", method->command);
+ method->output_length = strlen(method->command);
+ method->nexttosend = method->nexttosend->next;
+ }
+
+
+ l = method->output_length - method->alreadywritten;
+
+ r = write(method->mstdin, method->command + method->alreadywritten, l);
+ if (r < 0) {
+ int e = errno;
+
+ fprintf(stderr, "Error %d writing to pipe: %s\n",
+ e, strerror(e));
+ //TODO: disable the whole method??
+ method->status = ams_failed;
+ return RET_ERRNO(e);
+ } else if ((size_t)r < l) {
+ method->alreadywritten += r;
+ return RET_OK;
+ }
+
+ free(method->command);
+ method->command = NULL;
+ return RET_OK;
+}
+
+static retvalue checkchilds(struct aptmethodrun *run) {
+ pid_t child;int status;
+ retvalue result = RET_OK, r;
+
+ while ((child = waitpid(-1, &status, WNOHANG)) > 0) {
+ struct aptmethod *method;
+
+ for (method = run->methods ; method != NULL ;
+ method = method->next) {
+ if (method->child == child)
+ break;
+ }
+ if (method == NULL) {
+ /* perhaps an uncompressor terminated */
+ r = uncompress_checkpid(child, status);
+ if (RET_IS_OK(r))
+ continue;
+ if (RET_WAS_ERROR(r)) {
+ result = r;
+ continue;
+ }
+ else {
+ fprintf(stderr,
+"Unexpected child died (maybe gpg died if signing/verifing was done): %d\n",
+ (int)child);
+ continue;
+ }
+ }
+ /* Make sure we do not cope with this child any more */
+ if (method->mstdin != -1) {
+ (void)close(method->mstdin);
+ method->mstdin = -1;
+ }
+ if (method->mstdout != -1) {
+ (void)close(method->mstdout);
+ method->mstdout = -1;
+ }
+ method->child = -1;
+ if (method->status != ams_failed)
+ method->status = ams_notstarted;
+
+ /* say something if it exited unnormal: */
+ if (WIFEXITED(status)) {
+ int exitcode;
+
+ exitcode = WEXITSTATUS(status);
+ if (exitcode != 0) {
+ fprintf(stderr,
+"Method %s://%s exited with non-zero exit code %d!\n",
+ method->name, method->baseuri,
+ exitcode);
+ method->status = ams_notstarted;
+ result = RET_ERROR;
+ }
+ } else {
+ fprintf(stderr, "Method %s://%s exited unnormally!\n",
+ method->name, method->baseuri);
+ method->status = ams_notstarted;
+ result = RET_ERROR;
+ }
+ }
+ return result;
+}
+
+/* *workleft is always set, even when return indicated error.
+ * (workleft < 0 when critical)*/
+static retvalue readwrite(struct aptmethodrun *run, /*@out@*/int *workleft) {
+ int maxfd, v;
+ fd_set readfds, writefds;
+ struct aptmethod *method;
+ retvalue result, r;
+
+ /* First calculate what to look at: */
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ maxfd = 0;
+ *workleft = 0;
+ for (method = run->methods ; method != NULL ; method = method->next) {
+ if (method->status == ams_ok &&
+ (method->command != NULL || method->nexttosend != NULL)) {
+ FD_SET(method->mstdin, &writefds);
+ if (method->mstdin > maxfd)
+ maxfd = method->mstdin;
+ (*workleft)++;
+ if (verbose > 19)
+ fprintf(stderr, "want to write to '%s'\n",
+ method->baseuri);
+ }
+ if (method->status == ams_waitforcapabilities ||
+ (method->status == ams_ok &&
+ method->tobedone != NULL)) {
+ FD_SET(method->mstdout, &readfds);
+ if (method->mstdout > maxfd)
+ maxfd = method->mstdout;
+ (*workleft)++;
+ if (verbose > 19)
+ fprintf(stderr, "want to read from '%s'\n",
+ method->baseuri);
+ }
+ }
+
+ if (*workleft == 0)
+ return RET_NOTHING;
+
+ // TODO: think about a timeout...
+ v = select(maxfd + 1, &readfds, &writefds, NULL, NULL);
+ if (v < 0) {
+ int e = errno;
+ //TODO: handle (e == EINTR) && interrupted() specially
+ fprintf(stderr, "Select returned error %d: %s\n",
+ e, strerror(e));
+ *workleft = -1;
+ // TODO: what to do here?
+ return RET_ERRNO(e);
+ }
+
+ result = RET_NOTHING;
+
+ maxfd = 0;
+ for (method = run->methods ; method != NULL ; method = method->next) {
+ if (method->mstdout != -1 &&
+ FD_ISSET(method->mstdout, &readfds)) {
+ r = receivedata(method);
+ RET_UPDATE(result, r);
+ }
+ if (method->mstdin != -1 &&
+ FD_ISSET(method->mstdin, &writefds)) {
+ r = senddata(method);
+ RET_UPDATE(result, r);
+ }
+ }
+ return result;
+}
+
+retvalue aptmethod_download(struct aptmethodrun *run) {
+ struct aptmethod *method;
+ retvalue result, r;
+ int workleft;
+
+ result = RET_NOTHING;
+
+ /* fire up all methods, removing those that do not work: */
+ for (method = run->methods; method != NULL ; method = method->next) {
+ r = aptmethod_startup(method);
+ /* do not remove failed methods here any longer,
+ * and not remove methods having nothing to do,
+ * as this breaks when no index files are downloaded
+ * due to all already being in place... */
+ RET_UPDATE(result, r);
+ }
+ /* waiting for them to finish: */
+ do {
+ r = checkchilds(run);
+ RET_UPDATE(result, r);
+ r = readwrite(run, &workleft);
+ RET_UPDATE(result, r);
+ // TODO: check interrupted here...
+ } while (workleft > 0 || uncompress_running());
+
+ return result;
+}
+
diff --git a/aptmethod.h b/aptmethod.h
new file mode 100644
index 0000000..ab0cf8e
--- /dev/null
+++ b/aptmethod.h
@@ -0,0 +1,27 @@
+#ifndef REPREPRO_APTMETHOD_H
+#define REPREPRO_APTMETHOD_H
+
+#ifndef REPREPRO_DATABASE_H
+#include "database.h"
+#endif
+#ifndef REPREPRO_CHECKSUMS_H
+#include "checksums.h"
+#endif
+
+struct aptmethodrun;
+struct aptmethod;
+
+enum queue_action { qa_abort, qa_got, qa_error };
+
+typedef retvalue queue_callback(enum queue_action, void *, void *, const char * /*uri*/, const char * /*gotfilename*/, const char * /*wantedfilename*/, /*@null@*/const struct checksums *, const char * /*methodname*/);
+
+retvalue aptmethod_initialize_run(/*@out@*/struct aptmethodrun **);
+retvalue aptmethod_newmethod(struct aptmethodrun *, const char * /*uri*/, const char * /*fallbackuri*/, const struct strlist * /*config*/, /*@out@*/struct aptmethod **);
+
+retvalue aptmethod_enqueue(struct aptmethod *, const char * /*origfile*/, /*@only@*/char */*destfile*/, queue_callback *, void *, void *);
+retvalue aptmethod_enqueueindex(struct aptmethod *, const char * /*suite*/, const char * /*origfile*/, const char *, const char * /*destfile*/, const char *, queue_callback *, void *, void *);
+
+retvalue aptmethod_download(struct aptmethodrun *);
+retvalue aptmethod_shutdown(/*@only@*/struct aptmethodrun *);
+
+#endif
diff --git a/ar.c b/ar.c
new file mode 100644
index 0000000..02f0bfb
--- /dev/null
+++ b/ar.c
@@ -0,0 +1,299 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2005,2006 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <archive.h>
+
+#include "error.h"
+#include "uncompression.h"
+#include "ar.h"
+
+/* Arr, me matees, Arr */
+
+#define BLOCKSIZE 10240
+#define AR_MAGIC "!<arch>\n"
+#define AR_HEADERMAGIC "`\n"
+
+struct ar_archive {
+ char *filename;
+ int fd;
+ struct ar_header {
+ char ah_filename[16];
+ char ah_date[12];
+ char ah_uid[6];
+ char ah_gid[6];
+ char ah_mode[8];
+ char ah_size[10];
+ char ah_magictrailer[2];
+ } currentheader;
+ off_t member_size, next_position;
+ void *readbuffer;
+ /*@null@*/struct compressedfile *member;
+ enum compression compression;
+};
+
+static ssize_t readwait(int fd, /*@out@*/void *buf, size_t count) {
+ ssize_t totalread;
+
+ totalread = 0;
+
+ while (count > 0) {
+ ssize_t s;
+
+ s = read(fd, buf, count);
+ if (s < 0)
+ return s;
+ if (interrupted()) {
+ errno = EINTR;
+ return -1;
+ }
+ if ((size_t)s > count) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (s == 0)
+ break;
+ totalread += s;
+ buf += s;
+ count -= s;
+ }
+ return totalread;
+}
+
+retvalue ar_open(/*@out@*/struct ar_archive **n, const char *filename) {
+ struct ar_archive *ar;
+ char buffer[sizeof(AR_MAGIC)];
+ ssize_t bytesread;
+
+ if (interrupted())
+ return RET_ERROR_INTERRUPTED;
+ ar = zNEW(struct ar_archive);
+ if (FAILEDTOALLOC(ar))
+ return RET_ERROR_OOM;
+ ar->fd = open(filename, O_NOCTTY|O_RDONLY);
+ if (ar->fd < 0) {
+ int e = errno;
+ fprintf(stderr, "Error %d opening %s: %s\n",
+ e, filename, strerror(e));
+ free(ar);
+ return RET_ERRNO(e);
+ }
+
+ bytesread = readwait(ar->fd, buffer, sizeof(AR_MAGIC) - 1);
+ if (bytesread != sizeof(AR_MAGIC)-1) {
+ int e = errno;
+ (void)close(ar->fd);
+ free(ar);
+ if (bytesread < 0) {
+ fprintf(stderr, "Error %d reading from %s: %s\n",
+ e, filename, strerror(e));
+ return RET_ERRNO(e);
+ } else {
+ fprintf(stderr, "Premature end of reading from %s\n",
+ filename);
+ return RET_ERROR;
+ }
+ }
+ if (memcmp(buffer, AR_MAGIC, sizeof(AR_MAGIC)-1) != 0) {
+ (void)close(ar->fd);
+ free(ar);
+ fprintf(stderr,
+"Missing ar header '!<arch>' at the beginning of %s\n",
+ filename);
+ return RET_ERROR;
+ }
+ ar->filename = strdup(filename);
+ if (FAILEDTOALLOC(ar->filename)) {
+ close(ar->fd);
+ free(ar);
+ return RET_ERROR_OOM;
+ }
+ ar->next_position = sizeof(AR_MAGIC) - 1;
+
+ *n = ar;
+ return RET_OK;
+}
+
+void ar_close(/*@only@*/struct ar_archive *ar) {
+ if (ar != NULL) {
+ if (ar->fd >= 0)
+ (void)close(ar->fd);
+ free(ar->filename);
+ free(ar);
+ }
+}
+
+/* RET_OK = next is there, RET_NOTHING = eof, < 0 = error */
+retvalue ar_nextmember(struct ar_archive *ar, /*@out@*/char **filename) {
+ ssize_t bytesread;
+ char *p;
+ off_t s;
+
+ assert(ar->readbuffer == NULL);
+ assert(ar->fd >= 0);
+
+ /* seek over what is left from the last part: */
+ s = lseek(ar->fd, ar->next_position, SEEK_SET);
+ if (s == (off_t)-1) {
+ int e = errno;
+ fprintf(stderr,
+"Error %d seeking to next member in ar file %s: %s\n",
+ e, ar->filename, strerror(e));
+ return RET_ERRNO(e);
+ }
+ /* read the next header from the file */
+
+ if (interrupted())
+ return RET_ERROR_INTERRUPTED;
+
+ bytesread = readwait(ar->fd, &ar->currentheader,
+ sizeof(ar->currentheader));
+ ar->next_position += sizeof(ar->currentheader);
+ if (bytesread == 0)
+ return RET_NOTHING;
+ if (bytesread != sizeof(ar->currentheader)){
+ int e = errno;
+ if (bytesread < 0) {
+ fprintf(stderr,
+"Error %d reading from ar file %s: %s\n",
+ e, ar->filename, strerror(e));
+ return RET_ERRNO(e);
+ } else {
+ fprintf(stderr, "Premature end of ar file %s\n",
+ ar->filename);
+ return RET_ERROR;
+ }
+ }
+ if (memcmp(ar->currentheader.ah_magictrailer, AR_HEADERMAGIC, 2) != 0) {
+ fprintf(stderr, "Corrupt ar file %s\n", ar->filename);
+ return RET_ERROR;
+ }
+
+ /* calculate the length and mark possible fillers being needed */
+
+ /* make ah_size null-terminated by overwriting the following field */
+ assert (&ar->currentheader.ah_magictrailer[0]
+ == ar->currentheader.ah_size + 10);
+ ar->currentheader.ah_magictrailer[0] = '\0';
+
+ ar->member_size = strtoul(ar->currentheader.ah_size, &p, 10);
+ if (*p != '\0' && *p != ' ') {
+ fprintf(stderr,
+"Error calculating length field in ar file %s\n",
+ ar->filename);
+ return RET_ERROR;
+ }
+ ar->next_position += ar->member_size;
+ if ((ar->member_size & 1) != 0)
+ ar->next_position ++;
+
+ /* get the name of the file */
+ if (false) {
+ /* handle long filenames */
+ // TODO!
+ } else {
+ /* normal filenames */
+ int i = sizeof(ar->currentheader.ah_filename);
+ while (i > 0 && ar->currentheader.ah_filename[i-1] == ' ')
+ i--;
+ /* hop over GNU style filenames, though they should not
+ * be in a .deb file... */
+ if (i > 0 && ar->currentheader.ah_filename[i-1] == '/')
+ i--;
+ *filename = strndup(ar->currentheader.ah_filename, i);
+ }
+ ar->compression = c_none;
+ return RET_OK;
+}
+
+void ar_archivemember_setcompression(struct ar_archive *ar, enum compression compression) {
+ ar->compression = compression;
+}
+
+ssize_t ar_archivemember_read(struct archive *a, void *d, const void **p) {
+ struct ar_archive *ar = d;
+ ssize_t bytesread;
+
+ assert (ar->readbuffer != NULL);
+ if (ar->member == NULL)
+ return 0;
+
+ *p = ar->readbuffer;
+ bytesread = uncompress_read(ar->member, ar->readbuffer, BLOCKSIZE);
+ if (bytesread < 0) {
+ const char *msg;
+ int e;
+
+ // TODO: why _fdclose instead of _abort?
+ (void)uncompress_fdclose(ar->member, &e, &msg);
+ ar->member = NULL;
+ archive_set_error(a, e, "%s", msg);
+ return -1;
+ }
+ return bytesread;
+}
+
+int ar_archivemember_open(struct archive *a, void *d) {
+ struct ar_archive *ar = d;
+ retvalue r;
+ const char *msg;
+ int e;
+
+ assert (uncompression_supported(ar->compression));
+
+ assert (ar->readbuffer == NULL);
+ ar->readbuffer = malloc(BLOCKSIZE);
+ if (FAILEDTOALLOC(ar->readbuffer)) {
+ archive_set_error(a, ENOMEM, "Out of memory");
+ return ARCHIVE_FATAL;
+ }
+ r = uncompress_fdopen(&ar->member, ar->fd, ar->member_size,
+ ar->compression, &e, &msg);
+ if (RET_IS_OK(r))
+ return ARCHIVE_OK;
+ archive_set_error(a, e, "%s", msg);
+ return ARCHIVE_FATAL;
+}
+
+int ar_archivemember_close(struct archive *a, void *d) {
+ struct ar_archive *ar = d;
+ retvalue r;
+ const char *msg;
+ int e;
+
+ free(ar->readbuffer);
+ ar->readbuffer = NULL;
+
+ if (ar->member == NULL)
+ return ARCHIVE_OK;
+
+ r = uncompress_fdclose(ar->member, &e, &msg);
+ ar->member = NULL;
+ if (RET_IS_OK(r))
+ return ARCHIVE_OK;
+ archive_set_error(a, e, "%s", msg);
+ return ARCHIVE_FATAL;
+}
diff --git a/ar.h b/ar.h
new file mode 100644
index 0000000..fe5ff7c
--- /dev/null
+++ b/ar.h
@@ -0,0 +1,22 @@
+#ifndef DEBCOMP_AR_H
+#define DEBCOMP_AR_H
+
+struct ar_archive;
+
+retvalue ar_open(/*@out@*/struct ar_archive **, const char *);
+void ar_close(/*@only@*/struct ar_archive *);
+
+/* RET_OK = next is there, RET_NOTHING = eof, < 0 = error */
+retvalue ar_nextmember(struct ar_archive *, /*@out@*/char ** /*filename*/);
+
+/* set compression for the next member */
+void ar_archivemember_setcompression(struct ar_archive *, enum compression);
+
+/* the following can be used for libarchive to read an file in the ar
+ * after ar_nextmember returned successfully.
+ * All references get invalid after the ar_nextmember is called again. */
+int ar_archivemember_close(struct archive *, void *);
+int ar_archivemember_open(struct archive *, void *);
+ssize_t ar_archivemember_read(struct archive *, void *, const void **);
+
+#endif
diff --git a/archallflood.c b/archallflood.c
new file mode 100644
index 0000000..b36227f
--- /dev/null
+++ b/archallflood.c
@@ -0,0 +1,717 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2009,2016 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "error.h"
+#include "strlist.h"
+#include "indexfile.h"
+#include "dpkgversions.h"
+#include "target.h"
+#include "distribution.h"
+#include "tracking.h"
+#include "files.h"
+#include "package.h"
+#include "archallflood.h"
+
+struct aa_source_name {
+ /*@null@*/struct aa_source_name *parent;
+ /*@null@*/struct aa_source_name *left_child;
+ /*@null@*/struct aa_source_name *right_child;
+
+ char *name;
+
+ /*@null@*/struct aa_source_version *versions;
+};
+
+struct aa_source_version {
+ /*@null@*/struct aa_source_version *next;
+ struct aa_source_name *name;
+ char *version;
+
+ /* if true, it was already verified that there is no
+ * binary package of the same source version already there,
+ * so new architecture 'all' can be added without danger */
+ bool has_no_sibling;
+ /* if true, then there is a binary package of this source
+ * package, so replacing an architecture all is only allowed
+ * if there is already a binary for the new one */
+ bool has_sibling;
+};
+
+struct aa_package_data {
+ struct aa_package_data *next;
+ /* the name of the architecture all package: */
+ char *name;
+
+ /* NULL if does not exists/not yet known */
+ /*@null@*/char *old_version;
+ /*@null@*/struct aa_source_version *old_source;
+ /*@null@*/char *new_version;
+ /*@null@*/struct aa_source_version *new_source;
+ bool new_has_sibling;
+
+ struct checksumsarray new_origfiles;
+ struct strlist new_filekeys;
+ char *new_control;
+};
+
+struct floodlist {
+ /*@dependent@*/struct target *target;
+ struct aa_source_name *sources;
+ struct aa_package_data *list;
+ /* package the next package will most probably be after.
+ * (NULL=before start of list) */
+ /*@null@*//*@dependent@*/struct aa_package_data *last;
+};
+
+static void aa_package_data_free(/*@only@*/struct aa_package_data *data){
+ if (data == NULL)
+ return;
+ free(data->name);
+ free(data->old_version);
+ free(data->new_version);
+ free(data->new_control);
+ strlist_done(&data->new_filekeys);
+ checksumsarray_done(&data->new_origfiles);
+ free(data);
+}
+
+static void floodlist_free(struct floodlist *list) {
+ struct aa_source_name *s;
+ struct aa_package_data *l;
+
+ if (list == NULL)
+ return;
+
+ l = list->list;
+ while (l != NULL) {
+ struct aa_package_data *n = l->next;
+ aa_package_data_free(l);
+ l = n;
+ }
+ s = list->sources;
+ while (s != NULL) {
+ struct aa_source_name *n;
+
+ while (s->left_child != NULL || s->right_child != NULL) {
+ if (s->left_child != NULL) {
+ n = s->left_child;
+ s->left_child = NULL;
+ s = n;
+ } else {
+ n = s->right_child;
+ s->right_child = NULL;
+ s = n;
+ }
+ }
+
+ while (s->versions != NULL) {
+ struct aa_source_version *nv;
+ nv = s->versions->next;
+ free(s->versions->version);
+ free(s->versions);
+ s->versions = nv;
+ }
+ n = s->parent;
+ free(s->name);
+ free(s);
+ s = n;
+ }
+ free(list);
+ return;
+}
+
+static retvalue find_or_add_sourcename(struct floodlist *list, struct package *pkg, /*@out@*/struct aa_source_name **src_p) {
+ struct aa_source_name *parent, **p, *n;
+ int c;
+
+ parent = NULL;
+ p = &list->sources;
+
+ /* if this gets too slow, make it a balanced tree,
+ * but it seems fast enough even as simple tree */
+
+ while (*p != NULL) {
+ c = strcmp(pkg->source, (*p)->name);
+ if (c == 0)
+ break;
+ parent = *p;
+ if (c > 0)
+ p = &parent->right_child;
+ else
+ p = &parent->left_child;
+ }
+ if (*p == NULL) {
+ /* there is not even something with this name */
+ n = zNEW(struct aa_source_name);
+ if (FAILEDTOALLOC(n)) {
+ return RET_ERROR_OOM;
+ }
+ n->name = strdup(pkg->source);
+ if (FAILEDTOALLOC(n->name)) {
+ free(n);
+ return RET_ERROR_OOM;
+ }
+ n->parent = parent;
+ *p = n;
+ *src_p = n;
+ return RET_OK;
+ }
+ *src_p = *p;
+ return RET_OK;
+}
+
+static retvalue find_or_add_source(struct floodlist *list, struct package *pkg, /*@out@*/struct aa_source_version **src_p) {
+ retvalue r;
+ struct aa_source_name *sn;
+ struct aa_source_version **p, *n;
+ int c;
+
+ r = find_or_add_sourcename(list, pkg, &sn);
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ /* source name found (or created), now look for version: */
+
+ p = &sn->versions;
+ c = -1;
+ while (*p != NULL && (c = strcmp(pkg->sourceversion,
+ (*p)->version)) > 0) {
+ p = &(*p)->next;
+ }
+ if (c == 0) {
+ assert (*p != NULL);
+ *src_p = *p;
+ return RET_OK;
+ }
+ n = zNEW(struct aa_source_version);
+ if (FAILEDTOALLOC(n)) {
+ return RET_ERROR_OOM;
+ }
+ n->name = sn;
+ n->version = strdup(pkg->sourceversion);
+ if (FAILEDTOALLOC(n->version)) {
+ free(n);
+ return RET_ERROR_OOM;
+ }
+ n->next = *p;
+ *p = n;
+ *src_p = n;
+ return RET_OK;
+}
+
+static struct aa_source_version *find_source(struct floodlist *list, const char *source, const char *sourceversion) {
+ struct aa_source_name *p;
+ struct aa_source_version *v;
+ int c = -1;
+
+ p = list->sources;
+
+ while (p != NULL) {
+ c = strcmp(source, p->name);
+ if (c == 0)
+ break;
+ if (c > 0)
+ p = p->right_child;
+ else
+ p = p->left_child;
+ }
+ if (p == NULL)
+ return NULL;
+ v = p->versions;
+ while (v != NULL && (c = strcmp(sourceversion, v->version)) > 0)
+ v = v->next;
+ if (c < 0)
+ return NULL;
+ else
+ return v;
+}
+
+/* Before anything else is done the current state of one target is read into
+ * the list: list->list points to the first in the sorted list,
+ * list->last to the last one inserted */
+static retvalue save_package_version(struct floodlist *list, struct package *pkg) {
+ struct aa_source_version *src;
+ retvalue r;
+ struct aa_package_data *package;
+
+ r = package_getarchitecture(pkg);
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ r = package_getsource(pkg);
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ r = find_or_add_source(list, pkg, &src);
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ if (pkg->architecture != architecture_all) {
+ src->has_sibling = true;
+ return RET_NOTHING;
+ }
+
+ r = package_getversion(pkg);
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ package = zNEW(struct aa_package_data);
+ if (FAILEDTOALLOC(package)) {
+ return RET_ERROR_OOM;
+ }
+
+ package->name = strdup(pkg->name);
+ if (FAILEDTOALLOC(package->name)) {
+ free(package);
+ return RET_ERROR_OOM;
+ }
+ package->old_version = package_dupversion(pkg);
+ if (FAILEDTOALLOC(package->old_version)) {
+ free(package->name);
+ free(package);
+ return RET_ERROR_OOM;
+ }
+ package->old_source = src;
+
+ if (list->list == NULL) {
+ /* first chunk to add: */
+ list->list = package;
+ list->last = package;
+ } else {
+ if (strcmp(pkg->name, list->last->name) > 0) {
+ list->last->next = package;
+ list->last = package;
+ } else {
+ /* this should only happen if the underlying
+ * database-method get changed, so just throwing
+ * out here */
+ fprintf(stderr,
+"INTERNAL ERROR: Package database is not sorted!!!\n");
+ assert(false);
+ exit(EXIT_FAILURE);
+ }
+ }
+ return RET_OK;
+}
+
+static retvalue floodlist_initialize(struct floodlist **fl, struct target *t) {
+ struct floodlist *list;
+ retvalue r, r2;
+ struct package_cursor iterator;
+
+ list = zNEW(struct floodlist);
+ if (FAILEDTOALLOC(list))
+ return RET_ERROR_OOM;
+
+ list->target = t;
+
+ /* Begin with the packages currently in the archive */
+
+ r = package_openiterator(t, READONLY, &iterator);
+ if (RET_WAS_ERROR(r)) {
+ floodlist_free(list);
+ return r;
+ }
+ while (package_next(&iterator)) {
+ r2 = save_package_version(list, &iterator.current);
+ RET_UPDATE(r, r2);
+ if (RET_WAS_ERROR(r2))
+ break;
+ }
+ r2 = package_closeiterator(&iterator);
+ RET_UPDATE(r, r2);
+
+ if (RET_WAS_ERROR(r)) {
+ floodlist_free(list);
+ return r;
+ }
+ list->last = NULL;
+ *fl = list;
+ return RET_OK;
+}
+
+static retvalue floodlist_trypackage(struct floodlist *list, struct package *package) {
+ retvalue r;
+ struct aa_package_data *current, *insertafter;
+
+ r = package_getversion(package);
+ if (!RET_IS_OK(r))
+ return r;
+ r = package_getsource(package);
+ if (!RET_IS_OK(r))
+ return r;
+
+ /* insertafter = NULL will mean insert before list */
+ insertafter = list->last;
+ /* the next one to test, current = NULL will mean not found */
+ if (insertafter != NULL)
+ current = insertafter->next;
+ else
+ current = list->list;
+
+ /* the algorithm assumes almost all packages are feed in
+ * alphabetically. */
+
+ while (true) {
+ int cmp;
+
+ assert (insertafter == NULL || insertafter->next == current);
+ assert (insertafter != NULL || current == list->list);
+
+ if (current == NULL)
+ cmp = -1; /* every package is before the end of list */
+ else
+ cmp = strcmp(package->name, current->name);
+
+ if (cmp == 0)
+ break;
+
+ if (cmp < 0) {
+ int precmp;
+
+ if (insertafter == NULL) {
+ /* if we are before the first
+ * package, add us there...*/
+ current = NULL;
+ break;
+ }
+ precmp = strcmp(package->name, insertafter->name);
+ if (precmp == 0) {
+ current = insertafter;
+ break;
+ } else if (precmp < 0) {
+ /* restart at the beginning: */
+ current = list->list;
+ insertafter = NULL;
+ continue;
+ } else { // precmp > 0
+ /* insert after insertafter: */
+ current = NULL;
+ break;
+ }
+ assert ("This is not reached" == NULL);
+ }
+ /* cmp > 0 : may come later... */
+ assert (current != NULL);
+ insertafter = current;
+ current = current->next;
+ if (current == NULL) {
+ /* add behind insertafter at end of list */
+ break;
+ }
+ /* otherwise repeat until place found */
+ }
+ if (current == NULL) {
+ /* adding a package not yet known */
+ struct aa_package_data *new;
+ struct aa_source_version *src;
+
+ src = find_source(list, package->source, package->sourceversion);
+ new = zNEW(struct aa_package_data);
+ if (FAILEDTOALLOC(new)) {
+ return RET_ERROR_OOM;
+ }
+ new->new_source = src;
+ new->new_version = package_dupversion(package);
+ if (FAILEDTOALLOC(new->new_version)) {
+ aa_package_data_free(new);
+ return RET_ERROR_OOM;
+ }
+ new->name = strdup(package->name);
+ if (FAILEDTOALLOC(new->name)) {
+ aa_package_data_free(new);
+ return RET_ERROR_OOM;
+ }
+ r = list->target->getinstalldata(list->target,
+ new->name, new->new_version,
+ architecture_all, package->control,
+ &new->new_control, &new->new_filekeys,
+ &new->new_origfiles);
+ if (RET_WAS_ERROR(r)) {
+ aa_package_data_free(new);
+ return r;
+ }
+ if (insertafter != NULL) {
+ new->next = insertafter->next;
+ insertafter->next = new;
+ } else {
+ new->next = list->list;
+ list->list = new;
+ }
+ list->last = new;
+ } else {
+ /* The package already exists: */
+ char *control;
+ struct strlist files;
+ struct checksumsarray origfiles;
+ struct aa_source_version *src;
+ int versioncmp;
+
+ list->last = current;
+
+ if (current->new_has_sibling) {
+ /* it has a new and that has a binary sibling,
+ * which means this becomes the new version
+ * exactly when it is newer than the old newest */
+ r = dpkgversions_cmp(package->version,
+ current->new_version,
+ &versioncmp);
+ if (RET_WAS_ERROR(r)) {
+ return r;
+ }
+ if (versioncmp <= 0) {
+ return RET_NOTHING;
+ }
+ } else if (current->old_version != NULL) {
+ /* if it is older than the old one, we will
+ * always discard it */
+ r = dpkgversions_cmp(package->version,
+ current->old_version,
+ &versioncmp);
+ if (RET_WAS_ERROR(r)) {
+ return r;
+ }
+ if (versioncmp <= 0) {
+ return RET_NOTHING;
+ }
+ }
+ /* we need to get the source to know more */
+
+ src = find_source(list, package->source, package->sourceversion);
+ if (src == NULL || !src->has_sibling) {
+ /* the new one has no sibling, only allowed
+ * to override those that have: */
+ if (current->new_version == NULL) {
+ if (current->old_source->has_sibling)
+ return RET_NOTHING;
+ } else if (current->new_has_sibling) {
+ return RET_NOTHING;
+ } else {
+ /* the new one has no sibling and the old one
+ * has not too, take the newer one: */
+ r = dpkgversions_cmp(package->version,
+ current->new_version,
+ &versioncmp);
+ if (RET_WAS_ERROR(r)) {
+ return r;
+ }
+ if (versioncmp <= 0) {
+ return RET_NOTHING;
+ }
+ }
+ }
+ char *new_version = package_dupversion(package);
+ if (FAILEDTOALLOC(new_version))
+ return RET_ERROR_OOM;
+
+ r = list->target->getinstalldata(list->target,
+ package->name, package->version,
+ architecture_all, package->control,
+ &control, &files, &origfiles);
+ if (RET_WAS_ERROR(r)) {
+ free(new_version);
+ return r;
+ }
+ free(current->new_version);
+ current->new_version = new_version;
+ current->new_source = src;
+ current->new_has_sibling = src != NULL && src->has_sibling;
+ strlist_done(&current->new_filekeys);
+ strlist_move(&current->new_filekeys, &files);
+ checksumsarray_done(&current->new_origfiles);
+ checksumsarray_move(&current->new_origfiles, &origfiles);
+ free(current->new_control);
+ current->new_control = control;
+ }
+ return RET_OK;
+}
+
+static retvalue floodlist_pull(struct floodlist *list, struct target *source) {
+ retvalue result, r;
+ struct package_cursor iterator;
+
+ list->last = NULL;
+ r = package_openiterator(source, READONLY, &iterator);
+ if (RET_WAS_ERROR(r))
+ return r;
+ result = RET_NOTHING;
+ while (package_next(&iterator)) {
+ r = package_getarchitecture(&iterator.current);
+ if (r == RET_NOTHING)
+ continue;
+ if (!RET_IS_OK(r)) {
+ RET_UPDATE(result, r);
+ break;
+ }
+ if (iterator.current.architecture != architecture_all)
+ continue;
+
+ r = floodlist_trypackage(list, &iterator.current);
+ RET_UPDATE(result, r);
+ if (RET_WAS_ERROR(r))
+ break;
+ if (interrupted()) {
+ result = RET_ERROR_INTERRUPTED;
+ break;
+ }
+ }
+ r = package_closeiterator(&iterator);
+ RET_ENDUPDATE(result, r);
+ return result;
+}
+
+static retvalue floodlist_install(struct floodlist *list, struct logger *logger, /*@NULL@*/struct trackingdata *td) {
+ struct aa_package_data *pkg;
+ retvalue result, r;
+
+ if (list->list == NULL)
+ return RET_NOTHING;
+
+ result = target_initpackagesdb(list->target, READWRITE);
+ if (RET_WAS_ERROR(result))
+ return result;
+ result = RET_NOTHING;
+ for (pkg = list->list ; pkg != NULL ; pkg = pkg->next) {
+ if (pkg->new_version != NULL) {
+ r = files_expectfiles(&pkg->new_filekeys,
+ pkg->new_origfiles.checksums);
+ RET_UPDATE(result, r);
+ if (RET_WAS_ERROR(r))
+ continue;
+ if (interrupted()) {
+ r = RET_ERROR_INTERRUPTED;
+ break;
+ }
+ if (td != NULL) {
+ if (pkg->new_source != NULL) {
+ r = trackingdata_switch(td,
+ pkg->new_source->name->name,
+ pkg->new_source->version);
+ } else {
+ char *source, *sourceversion;
+
+ r = list->target->getsourceandversion(
+ pkg->new_control,
+ pkg->name,
+ &source,
+ &sourceversion);
+ assert (r != RET_NOTHING);
+ if (RET_WAS_ERROR(r)) {
+ RET_UPDATE(result, r);
+ break;
+ }
+ r = trackingdata_switch(td,
+ source, sourceversion);
+ free(source);
+ free(sourceversion);
+ }
+ if (RET_WAS_ERROR(r)) {
+ RET_UPDATE(result, r);
+ break;
+ }
+ }
+ r = target_addpackage(list->target,
+ logger, pkg->name, pkg->new_version,
+ pkg->new_control, &pkg->new_filekeys,
+ false, td, architecture_all,
+ NULL, NULL, NULL);
+ RET_UPDATE(result, r);
+ if (RET_WAS_ERROR(r))
+ break;
+ }
+ }
+ r = target_closepackagesdb(list->target);
+ RET_ENDUPDATE(result, r);
+ return result;
+}
+
+retvalue flood(struct distribution *d, const struct atomlist *components, const struct atomlist *architectures, const struct atomlist *packagetypes, architecture_t architecture, trackingdb tracks) {
+ struct target *t, *s;
+ retvalue result = RET_NOTHING, r;
+ struct trackingdata trackingdata;
+
+ if (tracks != NULL) {
+ r = trackingdata_new(tracks, &trackingdata);
+ if (RET_WAS_ERROR(r))
+ return r;
+ }
+
+ for (t = d->targets ; t != NULL ; t = t->next) {
+ struct floodlist *fl = NULL;
+
+ if (atom_defined(architecture)) {
+ if (architecture != t->architecture)
+ continue;
+ } else if (limitations_missed(architectures,
+ t->architecture))
+ continue;
+ if (limitations_missed(components, t->component))
+ continue;
+ if (limitations_missed(packagetypes, t->packagetype))
+ continue;
+ if (t->packagetype != pt_deb && t->packagetype != pt_udeb)
+ continue;
+
+ r = floodlist_initialize(&fl, t);
+ if (RET_WAS_ERROR(r)) {
+ if (tracks != NULL)
+ trackingdata_done(&trackingdata);
+ return r;
+ }
+
+ for (s = d->targets ; s != NULL ; s = s->next) {
+ if (s->component != t->component)
+ continue;
+ if (s->packagetype != t->packagetype)
+ continue;
+ /* no need to copy things from myself: */
+ if (s->architecture == t->architecture)
+ continue;
+ if (limitations_missed(architectures,
+ s->architecture))
+ continue;
+ r = floodlist_pull(fl, s);
+ RET_UPDATE(d->status, r);
+ if (RET_WAS_ERROR(r)) {
+ if (tracks != NULL)
+ trackingdata_done(&trackingdata);
+ floodlist_free(fl);
+ return r;
+ }
+ }
+ r = floodlist_install(fl, d->logger,
+ (tracks != NULL)?&trackingdata:NULL);
+ RET_UPDATE(result, r);
+ floodlist_free(fl);
+ if (RET_WAS_ERROR(r)) {
+ if (tracks != NULL)
+ trackingdata_done(&trackingdata);
+ return r;
+ }
+ }
+ if (tracks != NULL) {
+ r = trackingdata_finish(tracks, &trackingdata);
+ RET_ENDUPDATE(result, r);
+ }
+ return result;
+}
diff --git a/archallflood.h b/archallflood.h
new file mode 100644
index 0000000..7d5bb04
--- /dev/null
+++ b/archallflood.h
@@ -0,0 +1,6 @@
+#ifndef REPREPRO_ARCHALLFLOOD_H
+#define REPREPRO_ARCHALLFLOOD_H
+
+retvalue flood(struct distribution *, /*@null@*/const struct atomlist * /*components*/, /*@NULL@*/const struct atomlist * /*architectures*/, /*@NULL@*/const struct atomlist * /*packagetypes*/, architecture_t, trackingdb);
+
+#endif
diff --git a/atoms.c b/atoms.c
new file mode 100644
index 0000000..62f8b09
--- /dev/null
+++ b/atoms.c
@@ -0,0 +1,392 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "error.h"
+#include "mprintf.h"
+#include "strlist.h"
+#include "atoms.h"
+
+const char **atoms_architectures;
+const char **atoms_components;
+const char * const packagetypes[4] = { "!!NONE!!", "dsc", "deb", "udeb" };
+const char **atoms_packagetypes = (const char **)&packagetypes;
+const char **atoms_commands;
+static int command_count;
+static const char * const types[4] = {
+ "architecture", "component", "packagetype", "command"
+};
+const char **atomtypes = (const char **)types;
+
+/* trivial implementation for now, perhaps make it more complicated later */
+static struct strlist architectures, components;
+
+retvalue atoms_init(int count) {
+ retvalue r;
+ strlist_init(&architectures);
+ strlist_init(&components);
+
+ /* add a 0th entry to all, so 0 means uninitialized */
+
+ r = strlist_add_dup(&architectures, "!!NONE!!");
+ if (RET_WAS_ERROR(r))
+ return r;
+ r = strlist_add_dup(&architectures, "source");
+ if (RET_WAS_ERROR(r))
+ return r;
+ r = strlist_add_dup(&architectures, "all");
+ if (RET_WAS_ERROR(r))
+ return r;
+ r = strlist_add_dup(&components, "!!NONE!!");
+ if (RET_WAS_ERROR(r))
+ return r;
+ /* a fallback component to put things without a component in */
+ r = strlist_add_dup(&components, "strange");
+ if (RET_WAS_ERROR(r))
+ return r;
+ atoms_components = (const char**)components.values;
+ atoms_architectures = (const char**)architectures.values;
+ command_count = count;
+ if (command_count > 0) {
+ atoms_commands = nzNEW(command_count + 1, const char*);
+ if (FAILEDTOALLOC(atoms_commands))
+ return RET_ERROR_OOM;
+ }
+ return RET_OK;
+}
+
+retvalue architecture_intern(const char *value, architecture_t *atom_p) {
+ retvalue r;
+ int i;
+
+ i = strlist_ofs(&architectures, value);
+ if (i >= 0) {
+ *atom_p = (architecture_t)i;
+ return RET_OK;
+ }
+ i = architectures.count;
+ r = strlist_add_dup(&architectures, value);
+ atoms_architectures = (const char**)architectures.values;
+ if (RET_IS_OK(r)) {
+ *atom_p = (architecture_t)i;
+ return RET_OK;
+ } else
+ return r;
+}
+retvalue component_intern(const char *value, component_t *atom_p) {
+ retvalue r;
+ int i;
+
+ i = strlist_ofs(&components, value);
+ if (i >= 0) {
+ *atom_p = (component_t)i;
+ return RET_OK;
+ }
+ i = components.count;
+ r = strlist_add_dup(&components, value);
+ atoms_components = (const char**)components.values;
+ if (RET_IS_OK(r)) {
+ *atom_p = (component_t)i;
+ return RET_OK;
+ } else
+ return r;
+}
+
+architecture_t architecture_find(const char *value) {
+ int i = strlist_ofs(&architectures, value);
+ if (i < 0)
+ return atom_unknown;
+ else
+ return (architecture_t)i;
+}
+
+architecture_t architecture_find_l(const char *value, size_t l) {
+ architecture_t a;
+
+ for (a = architectures.count - 1 ; a > 0 ; a--) {
+ const char *name = atoms_architectures[a];
+ size_t len = strlen(name);
+
+ if (len == l && memcmp(name, value, len) == 0)
+ return a;
+ }
+ return atom_unknown;
+}
+
+// TODO: this might be called a lot, perhaps optimize it...
+component_t component_find_l(const char *value, size_t l) {
+ component_t a;
+
+ for (a = components.count - 1 ; a > 0 ; a--) {
+ const char *name = atoms_components[a];
+ size_t len = strlen(name);
+
+ if (len == l && memcmp(name, value, len) == 0)
+ return a;
+ }
+ return atom_unknown;
+}
+
+component_t component_find(const char *value) {
+ int i = strlist_ofs(&components, value);
+ if (i < 0)
+ return atom_unknown;
+ else
+ return (architecture_t)i;
+}
+
+packagetype_t packagetype_find(const char *value) {
+ if (strcmp(value, "dsc") == 0)
+ return pt_dsc;
+ else if (strcmp(value, "deb") == 0)
+ return pt_deb;
+ else if (strcmp(value, "udeb") == 0)
+ return pt_udeb;
+ else
+ return atom_unknown;
+}
+
+packagetype_t packagetype_find_l(const char *value, size_t len) {
+ if (len == 3) {
+ if (strncmp(value, "dsc", 3) == 0)
+ return pt_dsc;
+ else if (strncmp(value, "deb", 3) == 0)
+ return pt_deb;
+ } else if (len == 4 && strncmp(value, "udeb", 4) == 0)
+ return pt_udeb;
+ return atom_unknown;
+}
+
+static inline command_t command_find(const char *value) {
+ command_t c;
+
+ for (c = command_count ; c > 0 ; c--) {
+ if (strcmp(atoms_commands[c], value) == 0)
+ return c;
+ }
+ return atom_unknown;
+}
+
+atom_t atom_find(enum atom_type type, const char *value) {
+ switch (type) {
+ case at_packagetype:
+ return packagetype_find(value);
+ case at_architecture:
+ return architecture_find(value);
+ case at_component:
+ return component_find(value);
+ case at_command:
+ return command_find(value);
+ default:
+ return atom_unknown;
+ }
+}
+
+retvalue atom_intern(enum atom_type type, const char *value, atom_t *atom_p) {
+ assert (type == at_architecture || type == at_component);
+ switch (type) {
+ case at_architecture:
+ return architecture_intern(value, atom_p);
+ case at_component:
+ return component_intern(value, atom_p);
+ default:
+ return RET_ERROR;
+ }
+}
+
+void atomlist_init(struct atomlist *list) {
+ list->count = 0; list->size = 0;
+ list->atoms = 0;
+}
+
+void atomlist_done(struct atomlist *list) {
+ if (list->size > 0) {
+ assert (list->atoms != 0);
+ free(list->atoms);
+ }
+ /* reset atoms but not size, so reuse can be caught */
+ list->atoms = NULL;
+}
+
+/* add a atom uniquely (perhaps sorted), RET_NOTHING when already there */
+retvalue atomlist_add_uniq(struct atomlist *list, atom_t atom) {
+ int i;
+ atom_t *n;
+
+ assert (atom_defined(atom));
+
+ for (i = 0 ; i < list->count ; i++) {
+ if (list->atoms[i] == atom)
+ return RET_NOTHING;
+ }
+ if (list->size <= list->count) {
+ n = realloc(list->atoms, (sizeof(atom_t))*(list->count + 8));
+ if (FAILEDTOALLOC(n))
+ return RET_ERROR_OOM;
+ list->size = list->count + 8;
+ list->atoms = n;
+ }
+ list->atoms[list->count++] = atom;
+ return RET_OK;
+}
+
+retvalue atomlist_add(struct atomlist *list, atom_t atom) {
+ atom_t *n;
+
+ assert (atom_defined(atom));
+
+ if (list->size <= list->count) {
+ n = realloc(list->atoms, (sizeof(atom_t))*(list->count + 8));
+ if (FAILEDTOALLOC(n))
+ return RET_ERROR_OOM;
+ list->size = list->count + 8;
+ list->atoms = n;
+ }
+ list->atoms[list->count++] = atom;
+ return RET_OK;
+}
+
+/* replace the contents of dest with those from orig, which get emptied */
+void atomlist_move(struct atomlist *dest, struct atomlist *orig) {
+ dest->atoms = orig->atoms;
+ dest->count = orig->count;
+ dest->size = orig->size;
+ /* reset atoms but not size, so reuse can be caught */
+ orig->atoms = NULL;
+}
+
+bool atomlist_hasexcept(const struct atomlist *list, atom_t atom) {
+ int i;
+
+ for (i = 0 ; i < list->count ; i++) {
+ if (list->atoms[i] != atom)
+ return true;
+ }
+ return false;
+}
+
+bool atomlist_in(const struct atomlist *list, atom_t atom) {
+ int i;
+
+ for (i = 0 ; i < list->count ; i++) {
+ if (list->atoms[i] == atom)
+ return true;
+ }
+ return false;
+}
+int atomlist_ofs(const struct atomlist *list, atom_t atom) {
+ int i;
+
+ for (i = 0 ; i < list->count ; i++) {
+ if (list->atoms[i] == atom)
+ return i;
+ }
+ return -1;
+}
+
+bool atomlist_subset(const struct atomlist *list, const struct atomlist *subset, atom_t *missing) {
+ int i, j;
+
+ for (j = 0 ; j < subset->count ; j++) {
+ atom_t atom = subset->atoms[j];
+
+ for (i = 0 ; i < list->count ; i++) {
+ if (list->atoms[i] == atom)
+ break;
+ }
+ if (i >= list->count) {
+ if (missing != NULL)
+ *missing = atom;
+ return false;
+ }
+ }
+ return true;
+}
+
+retvalue atomlist_fprint(FILE *file, enum atom_type type, const struct atomlist *list) {
+ const char **atoms = NULL;
+ int c;
+ atom_t *p;
+ retvalue result;
+
+ assert(list != NULL);
+ assert(file != NULL);
+
+ switch (type) {
+ case at_architecture:
+ atoms = atoms_architectures;
+ break;
+ case at_component:
+ atoms = atoms_components;
+ break;
+ case at_packagetype:
+ atoms = atoms_packagetypes;
+ break;
+ case at_command:
+ atoms = atoms_commands;
+ break;
+ }
+ assert(atoms != NULL);
+
+ c = list->count;
+ p = list->atoms;
+ result = RET_OK;
+ while (c > 0) {
+ if (fputs(atoms[*(p++)], file) == EOF)
+ result = RET_ERROR;
+ if (--c > 0 && fputc(' ', file) == EOF)
+ result = RET_ERROR;
+ }
+ return result;
+}
+
+component_t components_count(void) {
+ return components.count;
+}
+
+retvalue atomlist_filllist(enum atom_type type, struct atomlist *list, char *string, const char **missing) {
+ struct atomlist l;
+ char *e;
+ retvalue r;
+ atom_t a;
+
+ atomlist_init(&l);
+ while (*string != '\0') {
+ e = strchr(string, '|');
+ if (e == NULL)
+ e = strchr(string, '\0');
+ else
+ *(e++) = '\0';
+ a = atom_find(type, string);
+ if (!atom_defined(a)) {
+ atomlist_done(&l);
+ *missing = string;
+ return RET_NOTHING;
+ }
+ r = atomlist_add(&l, a);
+ if (RET_WAS_ERROR(r)) {
+ atomlist_done(&l);
+ return r;
+ }
+ string = e;
+ }
+ atomlist_move(list, &l);
+ return RET_OK;
+}
diff --git a/atoms.h b/atoms.h
new file mode 100644
index 0000000..be78713
--- /dev/null
+++ b/atoms.h
@@ -0,0 +1,74 @@
+#ifndef REPREPRO_ATOMS_H
+#define REPREPRO_ATOMS_H
+
+typedef int atom_t;
+typedef atom_t architecture_t;
+typedef atom_t component_t;
+typedef atom_t packagetype_t;
+typedef atom_t command_t;
+
+enum atom_type { at_architecture, at_component, at_packagetype, at_command };
+
+#define atom_unknown ((atom_t)0)
+
+#define architecture_source ((architecture_t)1)
+#define architecture_all ((architecture_t)2)
+
+#define component_strange ((component_t)1)
+
+#define pt_dsc ((packagetype_t)1)
+#define pt_deb ((packagetype_t)2)
+#define pt_udeb ((packagetype_t)3)
+
+#define atom_defined(a) ((a) > (atom_t)0)
+
+extern const char **atomtypes, **atoms_architectures, **atoms_components, **atoms_packagetypes, **atoms_commands;
+
+retvalue atoms_init(int command_count);
+
+retvalue architecture_intern(const char *, /*@out@*/architecture_t *);
+architecture_t architecture_find(const char *);
+architecture_t architecture_find_l(const char *, size_t);
+retvalue component_intern(const char *, /*@out@*/component_t *);
+component_t component_find(const char *);
+component_t component_find_l(const char *, size_t);
+component_t components_count(void);
+packagetype_t packagetype_find(const char *);
+packagetype_t packagetype_find_l(const char *, size_t);
+
+atom_t atom_find(enum atom_type, const char *);
+retvalue atom_intern(enum atom_type, const char *, /*@out@*/atom_t *);
+
+#define limitation_missed(a, b) ((atom_defined(a) && (a) != (b)))
+#define limitations_missed(a, b) ((a) != NULL && !atomlist_in(a, b))
+
+
+struct atomlist {
+ atom_t *atoms;
+ int count, size;
+};
+
+void atomlist_init(/*@out@*/struct atomlist *);
+void atomlist_done(/*@special@*/struct atomlist *atomlist) /*@releases atomlist->values @*/;
+
+/* add a atom uniquely (not sorted, component guessing might not like it),
+ * RET_NOTHING when already there */
+retvalue atomlist_add_uniq(struct atomlist *, atom_t);
+/* always add to the end */
+retvalue atomlist_add(struct atomlist *, atom_t);
+
+/* replace the contents of dest with those from orig, which get emptied */
+void atomlist_move(/*@out@*/struct atomlist *, /*@special@*/struct atomlist *orig) /*@releases orig->values @*/;
+
+bool atomlist_hasexcept(const struct atomlist *, atom_t);
+bool atomlist_in(const struct atomlist *, atom_t);
+int atomlist_ofs(const struct atomlist *, atom_t);
+
+/* if missing != NULL And subset no subset of atomlist, set *missing to the first missing one */
+bool atomlist_subset(const struct atomlist *, const struct atomlist * /*subset*/, /*@null@*/atom_t * /*missing*/ );
+
+/* print a space separated list of elements */
+retvalue atomlist_fprint(FILE *, enum atom_type, const struct atomlist *);
+
+retvalue atomlist_filllist(enum atom_type, /*@out@*/struct atomlist *, char * /*string*/, /*@out@*/const char ** /*missing*/);
+#endif
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..1c2e51a
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+set -e
+
+mkdir -p ac
+aclocal
+autoheader
+automake -a -c
+autoconf
+rm -rf autom4te.cache || true
+
+if [ $# -lt 1 ] ; then
+ exit 0
+fi
+
+if [ "x$1" = "x--configure" ] ; then
+ shift
+ repreprodir="`pwd`"
+ if [ $# -gt 0 ] ; then
+ mkdir -p -- "$1"
+ cd "$1" || exit 1
+ shift
+ fi
+ "$repreprodir"/configure --enable-maintainer-mode CFLAGS="-Wall -O2 -g -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wunused-parameter -Wsign-compare" CPPFLAGS="" "$@"
+else
+ echo "unsupported option $1" >&2
+ exit 1
+fi
diff --git a/binaries.c b/binaries.c
new file mode 100644
index 0000000..4d8eb7a
--- /dev/null
+++ b/binaries.c
@@ -0,0 +1,797 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2003,2004,2005,2006,2007,2009,2010 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "error.h"
+#include "mprintf.h"
+#include "strlist.h"
+#include "names.h"
+#include "chunks.h"
+#include "sources.h"
+#include "binaries.h"
+#include "names.h"
+#include "dpkgversions.h"
+#include "log.h"
+#include "override.h"
+#include "tracking.h"
+#include "debfile.h"
+
+static const char * const deb_checksum_headers[cs_COUNT] = {
+ "MD5sum", "SHA1", "SHA256", "Size"};
+
+static char *calc_binary_basename(const char *name, const char *version, architecture_t arch, packagetype_t packagetype) {
+ const char *v;
+ assert (name != NULL);
+ assert (version != NULL);
+ assert (atom_defined(arch));
+ assert (atom_defined(packagetype));
+ v = strchr(version, ':');
+ if (v != NULL)
+ v++;
+ else
+ v = version;
+ return mprintf("%s_%s_%s.%s", name, v, atoms_architectures[arch],
+ atoms_packagetypes[packagetype]);
+}
+
+
+/* get checksums out of a "Packages"-chunk. */
+static retvalue binaries_parse_checksums(const char *chunk, /*@out@*/struct checksums **checksums_p) {
+ retvalue result, r;
+ char *checksums[cs_COUNT];
+ enum checksumtype type;
+ bool gothash = false;
+
+ result = RET_NOTHING;
+
+ for (type = 0 ; type < cs_COUNT ; type++) {
+ checksums[type] = NULL;
+ r = chunk_getvalue(chunk, deb_checksum_headers[type],
+ &checksums[type]);
+ if (type != cs_length && RET_IS_OK(r))
+ gothash = true;
+ RET_UPDATE(result, r);
+ }
+ if (!gothash) {
+ fprintf(stderr,
+"No checksums found in binary control chunk:\n '%s'\n",
+ chunk);
+ RET_UPDATE(result, RET_ERROR_MISSING);
+ }
+ if (checksums[cs_length] == NULL) {
+ fprintf(stderr,
+"Missing 'Size' line in binary control chunk:\n '%s'\n",
+ chunk);
+ RET_UPDATE(result, RET_ERROR_MISSING);
+ }
+ if (RET_WAS_ERROR(result)) {
+ for (type = 0 ; type < cs_COUNT ; type++)
+ free(checksums[type]);
+ return result;
+ }
+ return checksums_init(checksums_p, checksums);
+}
+
+retvalue binaries_getarchitecture(const char *chunk, architecture_t *architecture_p) {
+ char *parch;
+ retvalue r;
+
+ r = chunk_getvalue(chunk, "Architecture", &parch);
+ if (r == RET_NOTHING) {
+ fprintf(stderr,
+"Internal Error: Missing Architecture: header in '%s'!\n",
+ chunk);
+ return RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r))
+ return r;
+ *architecture_p = architecture_find(parch);
+ free(parch);
+
+ if (!atom_defined(*architecture_p)) {
+ fprintf(stderr,
+"Internal Error: Unexpected Architecture: header in '%s'!\n",
+ chunk);
+ return RET_ERROR;
+ }
+ return RET_OK;
+}
+
+/* get somefields out of a "Packages.gz"-chunk.
+ * returns RET_OK on success, RET_NOTHING if incomplete, error otherwise */
+static retvalue binaries_parse_chunk(const char *chunk, const char *packagename, packagetype_t packagetype, architecture_t package_architecture, const char *version, /*@out@*/char **sourcename_p, /*@out@*/char **basename_p) {
+ retvalue r;
+ char *mysourcename, *mybasename;
+
+ assert(packagename!=NULL);
+
+ /* get the sourcename */
+ r = chunk_getname(chunk, "Source", &mysourcename, true);
+ if (r == RET_NOTHING) {
+ mysourcename = strdup(packagename);
+ if (FAILEDTOALLOC(mysourcename))
+ r = RET_ERROR_OOM;
+ }
+ if (RET_WAS_ERROR(r)) {
+ return r;
+ }
+
+ r = properpackagename(packagename);
+ if (!RET_WAS_ERROR(r))
+ r = properversion(version);
+ if (RET_WAS_ERROR(r)) {
+ free(mysourcename);
+ return r;
+ }
+ mybasename = calc_binary_basename(packagename, version,
+ package_architecture, packagetype);
+ if (FAILEDTOALLOC(mybasename)) {
+ free(mysourcename);
+ return RET_ERROR_OOM;
+ }
+
+ *basename_p = mybasename;
+ *sourcename_p = mysourcename;
+ return RET_OK;
+}
+
+/* get files out of a "Packages.gz"-chunk. */
+retvalue binaries_getfilekeys(const char *chunk, struct strlist *files) {
+ retvalue r;
+ char *filename;
+
+ /* Read the filename given there */
+ r = chunk_getvalue(chunk, "Filename", &filename);
+ if (!RET_IS_OK(r)) {
+ if (r == RET_NOTHING) {
+ fprintf(stderr,
+"Data does not look like binary control: '%s'\n",
+ chunk);
+ r = RET_ERROR;
+ }
+ return r;
+ }
+ r = strlist_init_singleton(filename, files);
+ return r;
+}
+
+static retvalue calcfilekeys(component_t component, const char *sourcename, const char *basefilename, struct strlist *filekeys) {
+ char *filekey;
+ retvalue r;
+
+ r = propersourcename(sourcename);
+ if (RET_WAS_ERROR(r)) {
+ return r;
+ }
+ filekey = calc_filekey(component, sourcename, basefilename);
+ if (FAILEDTOALLOC(filekey))
+ return RET_ERROR_OOM;
+ r = strlist_init_singleton(filekey, filekeys);
+ return r;
+}
+
+static inline retvalue calcnewcontrol(const char *chunk, const char *packagename, const char *sourcename, const char *basefilename, component_t component, struct strlist *filekeys, char **newchunk) {
+ retvalue r;
+ char *n;
+
+
+ n = chunk_normalize(chunk, "Package", packagename);
+ if (FAILEDTOALLOC(n))
+ return RET_ERROR_OOM;
+ r = calcfilekeys(component, sourcename, basefilename, filekeys);
+ if (RET_WAS_ERROR(r)) {
+ free(n);
+ return r;
+ }
+
+ assert (filekeys->count == 1);
+ *newchunk = chunk_replacefield(n, "Filename",
+ filekeys->values[0], false);
+ free(n);
+ if (FAILEDTOALLOC(*newchunk)) {
+ strlist_done(filekeys);
+ return RET_ERROR_OOM;
+ }
+ return RET_OK;
+}
+
+retvalue binaries_getversion(const char *control, char **version) {
+ retvalue r;
+
+ r = chunk_getvalue(control, "Version", version);
+ if (RET_WAS_ERROR(r))
+ return r;
+ if (r == RET_NOTHING) {
+ fprintf(stderr,
+"Missing 'Version' field in chunk:'%s'\n",
+ control);
+ return RET_ERROR;
+ }
+ return r;
+}
+
+retvalue binaries_getinstalldata(const struct target *t, const char *packagename, const char *version, architecture_t package_architecture, const char *chunk, char **control, struct strlist *filekeys, struct checksumsarray *origfiles) {
+ char *sourcename, *basefilename;
+ struct checksumsarray origfilekeys;
+ retvalue r;
+
+ r = binaries_parse_chunk(chunk, packagename,
+ t->packagetype, package_architecture,
+ version, &sourcename, &basefilename);
+ if (RET_WAS_ERROR(r)) {
+ return r;
+ } else if (r == RET_NOTHING) {
+ fprintf(stderr, "Does not look like a binary package: '%s'!\n",
+ chunk);
+ return RET_ERROR;
+ }
+ r = binaries_getchecksums(chunk, &origfilekeys);
+ if (RET_WAS_ERROR(r)) {
+ free(sourcename); free(basefilename);
+ return r;
+ }
+
+ r = calcnewcontrol(chunk, packagename, sourcename, basefilename,
+ t->component, filekeys, control);
+ if (RET_WAS_ERROR(r)) {
+ checksumsarray_done(&origfilekeys);
+ } else {
+ assert (r != RET_NOTHING);
+ checksumsarray_move(origfiles, &origfilekeys);
+ }
+ free(sourcename); free(basefilename);
+ return r;
+}
+
+retvalue binaries_getchecksums(const char *chunk, struct checksumsarray *filekeys) {
+ retvalue r;
+ struct checksumsarray a;
+
+ r = binaries_getfilekeys(chunk, &a.names);
+ if (RET_WAS_ERROR(r))
+ return r;
+ assert (a.names.count == 1);
+ a.checksums = NEW(struct checksums *);
+ if (FAILEDTOALLOC(a.checksums)) {
+ strlist_done(&a.names);
+ return RET_ERROR_OOM;
+ }
+ r = binaries_parse_checksums(chunk, a.checksums);
+ assert (r != RET_NOTHING);
+ if (RET_WAS_ERROR(r)) {
+ free(a.checksums);
+ strlist_done(&a.names);
+ return r;
+ }
+ checksumsarray_move(filekeys, &a);
+ return RET_OK;
+}
+
+retvalue binaries_doreoverride(const struct target *target, const char *packagename, const char *controlchunk, /*@out@*/char **newcontrolchunk) {
+ const struct overridedata *o;
+ struct fieldtoadd *fields;
+ char *newchunk;
+ retvalue r;
+
+ if (interrupted())
+ return RET_ERROR_INTERRUPTED;
+
+ o = override_search(target->distribution->overrides.deb, packagename);
+ if (o == NULL)
+ return RET_NOTHING;
+
+ r = override_allreplacefields(o, &fields);
+ if (!RET_IS_OK(r))
+ return r;
+ newchunk = chunk_replacefields(controlchunk, fields, "Filename", false);
+ addfield_free(fields);
+ if (FAILEDTOALLOC(newchunk))
+ return RET_ERROR_OOM;
+ *newcontrolchunk = newchunk;
+ return RET_OK;
+}
+
+retvalue ubinaries_doreoverride(const struct target *target, const char *packagename, const char *controlchunk, /*@out@*/char **newcontrolchunk) {
+ const struct overridedata *o;
+ struct fieldtoadd *fields;
+ char *newchunk;
+ retvalue r;
+
+ if (interrupted())
+ return RET_ERROR_INTERRUPTED;
+
+ o = override_search(target->distribution->overrides.udeb, packagename);
+ if (o == NULL)
+ return RET_NOTHING;
+
+ r = override_allreplacefields(o, &fields);
+ if (!RET_IS_OK(r))
+ return r;
+ newchunk = chunk_replacefields(controlchunk, fields, "Filename", true);
+ addfield_free(fields);
+ if (FAILEDTOALLOC(newchunk))
+ return RET_ERROR_OOM;
+ *newcontrolchunk = newchunk;
+ return RET_OK;
+}
+
+retvalue binaries_retrack(const char *packagename, const char *chunk, trackingdb tracks) {
+ retvalue r;
+ const char *sourcename;
+ char *fsourcename, *sourceversion, *arch, *filekey;
+ enum filetype filetype;
+ struct trackedpackage *pkg;
+
+ //TODO: eliminate duplicate code!
+ assert(packagename!=NULL);
+
+ if (interrupted())
+ return RET_ERROR_INTERRUPTED;
+
+ /* is there a sourcename */
+ r = chunk_getnameandversion(chunk, "Source",
+ &fsourcename, &sourceversion);
+ if (RET_WAS_ERROR(r))
+ return r;
+ if (r == RET_NOTHING) {
+ sourceversion = NULL;
+ sourcename = packagename;
+ fsourcename = NULL;
+ } else {
+ sourcename = fsourcename;
+ }
+ if (sourceversion == NULL) {
+ // Think about binNMUs, can something be done here?
+ r = chunk_getvalue(chunk, "Version", &sourceversion);
+ if (RET_WAS_ERROR(r)) {
+ free(fsourcename);
+ return r;
+ }
+ if (r == RET_NOTHING) {
+ free(fsourcename);
+ fprintf(stderr,
+"Missing 'Version' field in chunk:'%s'\n",
+ chunk);
+ return RET_ERROR;
+ }
+ }
+
+ r = chunk_getvalue(chunk, "Architecture", &arch);
+ if (r == RET_NOTHING) {
+ fprintf(stderr, "No Architecture field in chunk:'%s'\n",
+ chunk);
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r)) {
+ free(sourceversion);
+ free(fsourcename);
+ return r;
+ }
+ if (strcmp(arch, "all") == 0) {
+ filetype = ft_ALL_BINARY;
+ } else {
+ filetype = ft_ARCH_BINARY;
+ }
+ free(arch);
+
+ r = chunk_getvalue(chunk, "Filename", &filekey);
+ if (!RET_IS_OK(r)) {
+ if (r == RET_NOTHING) {
+ fprintf(stderr, "No Filename field in chunk: '%s'\n",
+ chunk);
+ r = RET_ERROR;
+ }
+ free(sourceversion);
+ free(fsourcename);
+ return r;
+ }
+ r = tracking_getornew(tracks, sourcename, sourceversion, &pkg);
+ free(fsourcename);
+ free(sourceversion);
+ if (RET_WAS_ERROR(r)) {
+ free(filekey);
+ return r;
+ }
+ assert (r != RET_NOTHING);
+ r = trackedpackage_addfilekey(tracks, pkg, filetype, filekey, true);
+ if (RET_WAS_ERROR(r)) {
+ trackedpackage_free(pkg);
+ return r;
+ }
+ return tracking_save(tracks, pkg);
+}
+
+retvalue binaries_getsourceandversion(const char *chunk, const char *packagename, char **source, char **version) {
+ retvalue r;
+ char *sourcename, *sourceversion;
+
+ //TODO: eliminate duplicate code!
+ assert(packagename!=NULL);
+
+ /* is there a sourcename */
+ r = chunk_getnameandversion(chunk, "Source",
+ &sourcename, &sourceversion);
+ if (RET_WAS_ERROR(r))
+ return r;
+ if (r == RET_NOTHING) {
+ sourceversion = NULL;
+ sourcename = strdup(packagename);
+ if (FAILEDTOALLOC(sourcename))
+ return RET_ERROR_OOM;
+ }
+ if (sourceversion == NULL) {
+ r = chunk_getvalue(chunk, "Version", &sourceversion);
+ if (RET_WAS_ERROR(r)) {
+ free(sourcename);
+ return r;
+ }
+ if (r == RET_NOTHING) {
+ free(sourcename);
+ fprintf(stderr, "No Version field in chunk:'%s'\n",
+ chunk);
+ return RET_ERROR;
+ }
+ }
+ *source = sourcename;
+ *version = sourceversion;
+ return RET_OK;
+}
+
+static inline retvalue getvalue(const char *filename, const char *chunk, const char *field, char **value) {
+ retvalue r;
+
+ r = chunk_getvalue(chunk, field, value);
+ if (r == RET_NOTHING) {
+ fprintf(stderr, "No %s field in %s's control file!\n",
+ field, filename);
+ r = RET_ERROR;
+ }
+ return r;
+}
+
+static inline retvalue checkvalue(const char *filename, const char *chunk, const char *field) {
+ retvalue r;
+
+ r = chunk_checkfield(chunk, field);
+ if (r == RET_NOTHING) {
+ fprintf(stderr, "No %s field in %s's control file!\n",
+ field, filename);
+ r = RET_ERROR;
+ }
+ return r;
+}
+
+static inline retvalue getvalue_n(const char *chunk, const char *field, char **value) {
+ retvalue r;
+
+ r = chunk_getvalue(chunk, field, value);
+ if (r == RET_NOTHING) {
+ *value = NULL;
+ }
+ return r;
+}
+
+void binaries_debdone(struct deb_headers *pkg) {
+ free(pkg->name);free(pkg->version);
+ free(pkg->source);free(pkg->sourceversion);
+ free(pkg->control);
+ free(pkg->section);
+ free(pkg->priority);
+}
+
+retvalue binaries_readdeb(struct deb_headers *deb, const char *filename, bool needssourceversion) {
+ retvalue r;
+ char *architecture;
+
+ r = extractcontrol(&deb->control, filename);
+ if (RET_WAS_ERROR(r))
+ return r;
+ /* first look for fields that should be there */
+
+ r = chunk_getname(deb->control, "Package", &deb->name, false);
+ if (r == RET_NOTHING) {
+ fprintf(stderr, "Missing 'Package' field in %s!\n", filename);
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r))
+ return r;
+ r = checkvalue(filename, deb->control, "Maintainer");
+ if (RET_WAS_ERROR(r))
+ return r;
+ r = checkvalue(filename, deb->control, "Description");
+ if (RET_WAS_ERROR(r))
+ return r;
+ r = getvalue(filename, deb->control, "Version", &deb->version);
+ if (RET_WAS_ERROR(r))
+ return r;
+ r = getvalue(filename, deb->control, "Architecture", &architecture);
+ if (RET_WAS_ERROR(r))
+ return r;
+ r = properfilenamepart(architecture);
+ if (RET_WAS_ERROR(r)) {
+ free(architecture);
+ return r;
+ }
+ r = architecture_intern(architecture, &deb->architecture);
+ free(architecture);
+ if (RET_WAS_ERROR(r))
+ return r;
+ /* can be there, otherwise we also know what it is */
+ if (needssourceversion)
+ r = chunk_getnameandversion(deb->control, "Source",
+ &deb->source, &deb->sourceversion);
+ else
+ r = chunk_getname(deb->control, "Source", &deb->source, true);
+ if (r == RET_NOTHING) {
+ deb->source = strdup(deb->name);
+ if (FAILEDTOALLOC(deb->source))
+ r = RET_ERROR_OOM;
+ }
+ if (RET_WAS_ERROR(r))
+ return r;
+ if (needssourceversion && deb->sourceversion == NULL) {
+ deb->sourceversion = strdup(deb->version);
+ if (FAILEDTOALLOC(deb->sourceversion))
+ return RET_ERROR_OOM;
+ }
+
+ /* normally there, but optional: */
+
+ r = getvalue_n(deb->control, PRIORITY_FIELDNAME, &deb->priority);
+ if (RET_WAS_ERROR(r))
+ return r;
+ r = getvalue_n(deb->control, SECTION_FIELDNAME, &deb->section);
+ if (RET_WAS_ERROR(r))
+ return r;
+ return RET_OK;
+}
+
+/* do overwrites, add Filename and Checksums to the control-item */
+retvalue binaries_complete(const struct deb_headers *pkg, const char *filekey, const struct checksums *checksums, const struct overridedata *override, const char *section, const char *priority, char **newcontrol) {
+ struct fieldtoadd *replace;
+ char *normalchunk, *newchunk;
+ enum checksumtype type;
+
+ assert (section != NULL && priority != NULL);
+ assert (filekey != NULL && checksums != NULL);
+
+ replace = NULL;
+ for (type = 0 ; type < cs_COUNT ; type++) {
+ const char *start;
+ size_t len;
+ if (checksums_getpart(checksums, type, &start, &len)) {
+ replace = addfield_newn(deb_checksum_headers[type],
+ start, len, replace);
+ if (FAILEDTOALLOC(replace))
+ return RET_ERROR_OOM;
+ }
+ }
+ replace = addfield_new("Filename", filekey, replace);
+ if (FAILEDTOALLOC(replace))
+ return RET_ERROR_OOM;
+ replace = addfield_new(SECTION_FIELDNAME, section, replace);
+ if (FAILEDTOALLOC(replace))
+ return RET_ERROR_OOM;
+ replace = addfield_new(PRIORITY_FIELDNAME, priority, replace);
+ if (FAILEDTOALLOC(replace))
+ return RET_ERROR_OOM;
+
+ replace = override_addreplacefields(override, replace);
+ if (FAILEDTOALLOC(replace))
+ return RET_ERROR_OOM;
+
+ normalchunk = chunk_normalize(pkg->control,
+ "Package", pkg->name);
+ if (FAILEDTOALLOC(normalchunk))
+ newchunk = NULL;
+ else
+ newchunk = chunk_replacefields(normalchunk, replace,
+ "Description", true);
+ free(normalchunk);
+ addfield_free(replace);
+ if (FAILEDTOALLOC(newchunk)) {
+ return RET_ERROR_OOM;
+ }
+
+ *newcontrol = newchunk;
+
+ return RET_OK;
+}
+
+/* update Checksums */
+retvalue binaries_complete_checksums(const char *chunk, const struct strlist *filekeys, struct checksums **c, char **out) {
+ struct fieldtoadd *replace;
+ char *newchunk;
+ enum checksumtype type;
+ const struct checksums *checksums;
+
+ assert (filekeys->count == 1);
+ checksums = c[0];
+
+ replace = NULL;
+ for (type = 0 ; type < cs_COUNT ; type++) {
+ const char *start;
+ size_t len;
+ if (checksums_getpart(checksums, type, &start, &len)) {
+ replace = addfield_newn(deb_checksum_headers[type],
+ start, len, replace);
+ if (FAILEDTOALLOC(replace))
+ return RET_ERROR_OOM;
+ }
+ }
+ newchunk = chunk_replacefields(chunk, replace,
+ "Description", true);
+ addfield_free(replace);
+ if (FAILEDTOALLOC(newchunk))
+ return RET_ERROR_OOM;
+ *out = newchunk;
+ return RET_OK;
+}
+
+retvalue binaries_adddeb(const struct deb_headers *deb, const struct atomlist *forcearchitectures, packagetype_t packagetype, struct distribution *distribution, struct trackingdata *trackingdata, component_t component, const struct strlist *filekeys, const char *control) {
+ retvalue r, result;
+ int i;
+
+ assert (logger_isprepared(distribution->logger));
+
+ /* finally put it into one or more architectures of the distribution */
+
+ result = RET_NOTHING;
+
+ if (deb->architecture != architecture_all) {
+ struct target *t = distribution_getpart(distribution,
+ component, deb->architecture,
+ packagetype);
+ r = target_initpackagesdb(t, READWRITE);
+ if (!RET_WAS_ERROR(r)) {
+ retvalue r2;
+ if (interrupted())
+ r = RET_ERROR_INTERRUPTED;
+ else
+ r = target_addpackage(t, distribution->logger,
+ deb->name, deb->version,
+ control,
+ filekeys,
+ false,
+ trackingdata,
+ deb->architecture,
+ NULL, NULL, NULL);
+ r2 = target_closepackagesdb(t);
+ RET_ENDUPDATE(r, r2);
+ }
+ RET_UPDATE(result, r);
+ RET_UPDATE(distribution->status, result);
+ return result;
+ }
+ /* It's an architecture all package */
+
+ /* if -A includes all, it is added everywhere, as if no -A was
+ * given. (as it behaved this way when there was only one -A possible,
+ * and to allow incoming to force it into architecture 'all' )
+ * */
+ if (forcearchitectures != NULL &&
+ atomlist_in(forcearchitectures, architecture_all))
+ forcearchitectures = NULL;
+
+ for (i = 0 ; i < distribution->architectures.count ; i++) {
+ /*@dependent@*/struct target *t;
+ architecture_t a = distribution->architectures.atoms[i];
+
+ if (a == architecture_source)
+ continue;
+ if (forcearchitectures != NULL &&
+ !atomlist_in(forcearchitectures, a))
+ continue;
+ t = distribution_getpart(distribution,
+ component, a, packagetype);
+ r = target_initpackagesdb(t, READWRITE);
+ if (!RET_WAS_ERROR(r)) {
+ retvalue r2;
+ if (interrupted())
+ r = RET_ERROR_INTERRUPTED;
+ else
+ r = target_addpackage(t, distribution->logger,
+ deb->name, deb->version,
+ control,
+ filekeys,
+ false,
+ trackingdata,
+ deb->architecture,
+ NULL, NULL, NULL);
+ r2 = target_closepackagesdb(t);
+ RET_ENDUPDATE(r, r2);
+ }
+ RET_UPDATE(result, r);
+ }
+ RET_UPDATE(distribution->status, result);
+ return result;
+}
+
+static inline retvalue checkadddeb(struct distribution *distribution, component_t component, architecture_t architecture, packagetype_t packagetype, bool tracking, const struct deb_headers *deb, bool permitnewerold) {
+ retvalue r;
+ struct target *t;
+
+ t = distribution_getpart(distribution,
+ component, architecture, packagetype);
+ assert (t != NULL);
+ r = target_initpackagesdb(t, READONLY);
+ if (!RET_WAS_ERROR(r)) {
+ retvalue r2;
+ if (interrupted())
+ r = RET_ERROR_INTERRUPTED;
+ else
+ r = target_checkaddpackage(t,
+ deb->name, deb->version,
+ tracking,
+ permitnewerold);
+ r2 = target_closepackagesdb(t);
+ RET_ENDUPDATE(r, r2);
+ }
+ return r;
+}
+
+retvalue binaries_checkadddeb(const struct deb_headers *deb, architecture_t forcearchitecture, packagetype_t packagetype, struct distribution *distribution, bool tracking, component_t component, bool permitnewerold) {
+ retvalue r, result;
+ int i;
+
+ /* finally put it into one or more architectures of the distribution */
+ result = RET_NOTHING;
+
+ if (deb->architecture != architecture_all) {
+ r = checkadddeb(distribution,
+ component, deb->architecture, packagetype,
+ tracking, deb, permitnewerold);
+ RET_UPDATE(result, r);
+ } else if (atom_defined(forcearchitecture)
+ && forcearchitecture != architecture_all) {
+ r = checkadddeb(distribution,
+ component, forcearchitecture, packagetype,
+ tracking, deb, permitnewerold);
+ RET_UPDATE(result, r);
+ } else for (i = 0 ; i < distribution->architectures.count ; i++) {
+ architecture_t a = distribution->architectures.atoms[i];
+ if (a == architecture_source)
+ continue;
+ r = checkadddeb(distribution,
+ component, a, packagetype,
+ tracking, deb, permitnewerold);
+ RET_UPDATE(result, r);
+ }
+ return result;
+}
+
+retvalue binaries_calcfilekeys(component_t component, const struct deb_headers *deb, packagetype_t packagetype, struct strlist *filekeys) {
+ retvalue r;
+ char *basefilename;
+
+ basefilename = calc_binary_basename(deb->name, deb->version,
+ deb->architecture, packagetype);
+ if (FAILEDTOALLOC(basefilename))
+ return RET_ERROR_OOM;
+
+ r = calcfilekeys(component, deb->source, basefilename, filekeys);
+ free(basefilename);
+ return r;
+}
+
diff --git a/binaries.h b/binaries.h
new file mode 100644
index 0000000..ff1a9e6
--- /dev/null
+++ b/binaries.h
@@ -0,0 +1,57 @@
+#ifndef REPREPRO_BINARIES_H
+#define REPREPRO_BINARIES_H
+
+#ifndef REPREPRO_ERROR_H
+#include "error.h"
+#warning "What's hapening here?"
+#endif
+#ifndef REPREPRO_TARGET_H
+#include "target.h"
+#endif
+#ifndef REPREPRO_CHECKSUMS_H
+#include "checksums.h"
+#endif
+
+
+/* Functions for the target.h-stuff: */
+get_version binaries_getversion;
+get_installdata binaries_getinstalldata;
+get_architecture binaries_getarchitecture;
+get_filekeys binaries_getfilekeys;
+get_checksums binaries_getchecksums;
+do_reoverride binaries_doreoverride;
+do_reoverride ubinaries_doreoverride;
+do_retrack binaries_retrack;
+get_sourceandversion binaries_getsourceandversion;
+complete_checksums binaries_complete_checksums;
+
+/* Functions for checkindeb.c and incoming.c: */
+
+struct deb_headers {
+ char *name, *version;
+ char *source;
+ architecture_t architecture;
+ char *control;
+ /* only extracted when requested: */
+ /*@null@*/char *sourceversion;
+ /* optional fields: */
+ /*@null@*/char *section;
+ /*@null@*/char *priority;
+};
+
+/* read contents of filename into deb_headers.
+ * - does not follow retvalue conventions, some fields may be set even when
+ * error returned
+ * - no checks for sanity of values, left to the caller */
+
+retvalue binaries_readdeb(struct deb_headers *, const char *filename, bool /*needssourceversion*/);
+void binaries_debdone(struct deb_headers *);
+
+retvalue binaries_calcfilekeys(component_t, const struct deb_headers *, packagetype_t, /*@out@*/struct strlist *);
+
+struct overridedata;
+retvalue binaries_complete(const struct deb_headers *, const char * /*filekey*/, const struct checksums *, const struct overridedata *, const char * /*section*/, const char * /*priority*/, char **/*newcontrol_p*/);
+
+retvalue binaries_adddeb(const struct deb_headers *, const struct atomlist */*forcedarchitectures*/, packagetype_t, struct distribution *, /*@null@*/struct trackingdata *, component_t, const struct strlist */*filekeys*/, const char */*control*/);
+retvalue binaries_checkadddeb(const struct deb_headers *, architecture_t /*forcearchitecture*/, packagetype_t, struct distribution *, bool tracking, component_t, bool /*permitnewerold*/);
+#endif
diff --git a/byhandhook.c b/byhandhook.c
new file mode 100644
index 0000000..c4f18fd
--- /dev/null
+++ b/byhandhook.c
@@ -0,0 +1,241 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2010 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "error.h"
+#include "filecntl.h"
+#include "names.h"
+#include "configparser.h"
+#include "globmatch.h"
+#include "hooks.h"
+#include "byhandhook.h"
+
+struct byhandhook {
+ /*@null@*/struct byhandhook *next;
+ char *sectionglob;
+ char *priorityglob;
+ char *filenameglob;
+ char *script;
+};
+
+void byhandhooks_free(struct byhandhook *l) {
+ while (l != NULL) {
+ /*@null@*/struct byhandhook *n = l->next;
+
+ free(l->sectionglob);
+ free(l->priorityglob);
+ free(l->filenameglob);
+ free(l->script);
+ free(l);
+ l = n;
+ }
+}
+
+retvalue byhandhooks_parse(struct configiterator *iter, struct byhandhook **hooks_p) {
+ retvalue r;
+ char *v;
+ struct byhandhook *h, *hooks = NULL, **nexthook_p = &hooks;
+
+ r = config_getwordinline(iter, &v);
+ if (RET_IS_OK(r)) {
+ fprintf(stderr,
+"Error parsing %s, line %u, column %u: unexpected input '%s'"
+" (each hook must be in its own line)!\n",
+ config_filename(iter),
+ config_markerline(iter),
+ config_markercolumn(iter),
+ v);
+ free(v);
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r))
+ return r;
+ while (config_nextline(iter)) {
+ r = config_getwordinline(iter, &v);
+ if (r == RET_NOTHING)
+ continue;
+ if (RET_WAS_ERROR(r))
+ break;
+ h = zNEW(struct byhandhook);
+ if (FAILEDTOALLOC(h)) {
+ r = RET_ERROR_OOM;
+ break;
+ }
+ *nexthook_p = h;
+ nexthook_p = &h->next;
+ h->sectionglob = v;
+ r = config_getwordinline(iter, &v);
+ if (r == RET_NOTHING) {
+ fprintf(stderr,
+"Error parsing %s, line %u, column %u: each byhand hooks needs 4 arguments, found only 1!\n",
+ config_filename(iter),
+ config_markerline(iter),
+ config_markercolumn(iter));
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r))
+ break;
+ h->priorityglob = v;
+ r = config_getwordinline(iter, &v);
+ if (r == RET_NOTHING) {
+ fprintf(stderr,
+"Error parsing %s, line %u, column %u: each byhand hooks needs 4 arguments, found only 2!\n",
+ config_filename(iter),
+ config_markerline(iter),
+ config_markercolumn(iter));
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r))
+ break;
+ h->filenameglob = v;
+ r = config_getwordinline(iter, &v);
+ if (r == RET_NOTHING) {
+ fprintf(stderr,
+"Error parsing %s, line %u, column %u: each byhand hooks needs 4 arguments, found only 2!\n",
+ config_filename(iter),
+ config_markerline(iter),
+ config_markercolumn(iter));
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r))
+ break;
+ assert (v != NULL && v[0] != '\0'); \
+ h->script = configfile_expandname(v, v);
+ if (FAILEDTOALLOC(h->script)) {
+ r = RET_ERROR_OOM;
+ break;
+ }
+ r = config_getwordinline(iter, &v);
+ if (RET_IS_OK(r)) {
+ fprintf(stderr,
+"Error parsing %s, line %u, column %u: each byhand hooks needs exactly 4 arguments, but there are more (first unexpected: '%s'!\n",
+ config_filename(iter),
+ config_markerline(iter),
+ config_markercolumn(iter), v);
+ free(v);
+ r = RET_ERROR;
+ }
+ if (RET_WAS_ERROR(r))
+ break;
+ }
+ if (RET_WAS_ERROR(r)) {
+ byhandhooks_free(hooks);
+ return r;
+ }
+ *hooks_p = hooks;
+ return RET_OK;
+}
+
+bool byhandhooks_matched(const struct byhandhook *list, const struct byhandhook **touse, const char *section, const char *priority, const char *filename) {
+ const struct byhandhook *h;
+
+ /* for each file the first matching hook is called
+ * it might later be extended to allow multiple with some keywords */
+ if (*touse != NULL)
+ /* if ((*touse)->nonexclusive) list = (*touse)->next ; else */
+ return false;
+ for (h = list ; h != NULL ; h = h->next) {
+ if (!globmatch(section, h->sectionglob))
+ continue;
+ if (!globmatch(priority, h->priorityglob))
+ continue;
+ if (!globmatch(filename, h->filenameglob))
+ continue;
+ *touse = h;
+ return true;
+ }
+ return false;
+}
+
+retvalue byhandhook_call(const struct byhandhook *h, const char *codename, const char *section, const char *priority, const char *name, const char *fullfilename) {
+ pid_t child;
+
+ child = fork();
+ if (child == 0) {
+ /* Try to close all open fd but 0,1,2 */
+ closefrom(3);
+ sethookenvironment(causingfile, NULL, NULL, NULL);
+ (void)execl(h->script, h->script, codename,
+ section, priority, name,
+ fullfilename, (char*)NULL);
+ {
+ int e = errno;
+ fprintf(stderr, "Error %d executing '%s': %s\n",
+ e, h->script,
+ strerror(e));
+ }
+ _exit(255);
+ }
+ if (child < 0) {
+ int e = errno;
+ fprintf(stderr, "Error %d forking: %s!\n", e, strerror(e));
+ return RET_ERRNO(e);
+ }
+ while (true) {
+ int status;
+ pid_t pid;
+
+ pid = waitpid(child, &status, 0);
+ if (pid == child) {
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 0) {
+ return RET_OK;
+ }
+ fprintf(stderr,
+"Byhandhook '%s' '%s' '%s' '%s' '%s' '%s' failed with exit code %d!\n",
+ h->script, codename,
+ section, priority, name,
+ fullfilename,
+ (int)(WEXITSTATUS(status)));
+ } else if (WIFSIGNALED(status)) {
+ fprintf(stderr,
+"Byhandhook '%s' '%s' '%s' '%s' '%s' '%s' killed by signal %d!\n",
+ h->script, codename,
+ section, priority, name,
+ fullfilename,
+ (int)(WTERMSIG(status)));
+ } else {
+ fprintf(stderr,
+"Byhandhook '%s' '%s' '%s' '%s' '%s' '%s' failed!\n",
+ h->script, codename,
+ section, priority, name,
+ fullfilename);
+ }
+ return RET_ERROR;
+ } else if (pid == (pid_t)-1) {
+ int e = errno;
+
+ if (e == EINTR)
+ continue;
+ fprintf(stderr,
+"Error %d calling waitpid on byhandhook child: %s\n",
+ e, strerror(e));
+ return RET_ERRNO(e);
+ }
+ }
+ /* NOT REACHED */
+}
+
diff --git a/byhandhook.h b/byhandhook.h
new file mode 100644
index 0000000..dd72e02
--- /dev/null
+++ b/byhandhook.h
@@ -0,0 +1,26 @@
+#ifndef REPREPRO_BYHANDHOOK_H
+#define REPREPRO_BYHANDHOOK_H
+
+#ifndef REPREPRO_ERROR_H
+#include "error.h"
+#warning "What's hapening here?"
+#endif
+
+#ifndef REPREPRO_ERROR_H
+#include "error.h"
+#warning "What's hapening here?"
+#endif
+
+struct byhandhook;
+
+retvalue byhandhooks_parse(struct configiterator *, /*@out@*/struct byhandhook **);
+
+/* 2nd argument starts as NULL, returns true as long as there are hooks */
+bool byhandhooks_matched(const struct byhandhook *, const struct byhandhook **, const char * /*section*/, const char * /*priority*/, const char * /*name*/);
+
+retvalue byhandhook_call(const struct byhandhook *, const char * /*codename*/, const char * /*section*/, const char * /*priority*/, const char * /*basename*/, const char * /*fullfilename*/);
+
+void byhandhooks_free(/*@null@*//*@only@*/struct byhandhook *);
+
+#endif
+
diff --git a/changes.c b/changes.c
new file mode 100644
index 0000000..2cfb33d
--- /dev/null
+++ b/changes.c
@@ -0,0 +1,333 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2003,2004,2005,2006,2008 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "error.h"
+#include "names.h"
+#include "uncompression.h"
+#include "checksums.h"
+#include "changes.h"
+
+retvalue changes_parsefileline(const char *fileline, /*@out@*/filetype *result_type, /*@out@*/char **result_basename, /*@out@*/struct hash_data *hash_p, /*@out@*/struct hash_data *size_p, /*@out@*/char **result_section, /*@out@*/char **result_priority, /*@out@*/architecture_t *result_architecture, /*@out@*/char **result_name) {
+
+ const char *p, *md5start, *md5end;
+ const char *sizestart, *sizeend;
+ const char *sectionstart, *sectionend;
+ const char *priostart, *prioend;
+ const char *filestart, *nameend, *fileend;
+ const char *archstart, *archend;
+ const char *versionstart;
+ filetype type;
+ char *section, *priority, *basefilename, *name;
+ architecture_t architecture;
+ size_t l;
+ bool checkfilename = false;
+
+ p = fileline;
+ while (*p !='\0' && xisspace(*p))
+ p++;
+ md5start = p;
+ while ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f'))
+ p++;
+ if (*p == '\0') {
+ fprintf(stderr, "Missing md5sum in '%s'!\n", fileline);
+ return RET_ERROR;
+ }
+ if (!xisspace(*p)) {
+ fprintf(stderr, "Malformed md5 hash in '%s'!\n", fileline);
+ return RET_ERROR;
+ }
+ md5end = p;
+ while (*p !='\0' && xisspace(*p))
+ p++;
+ while (*p == '0' && p[1] >= '0' && p[1] <= '9')
+ p++;
+ sizestart = p;
+ while (*p >= '0' && *p <= '9')
+ p++;
+ if (*p == '\0') {
+ fprintf(stderr,
+"Missing size (second argument) in '%s'!\n", fileline);
+ return RET_ERROR;
+ }
+ if (!xisspace(*p)) {
+ fprintf(stderr,
+"Malformed size (second argument) in '%s'!\n", fileline);
+ return RET_ERROR;
+ }
+ sizeend = p;
+ while (*p !='\0' && xisspace(*p))
+ p++;
+ sectionstart = p;
+ while (*p !='\0' && !xisspace(*p))
+ p++;
+ sectionend = p;
+ while (*p !='\0' && xisspace(*p))
+ p++;
+ priostart = p;
+ while (*p !='\0' && !xisspace(*p))
+ p++;
+ prioend = p;
+ while (*p !='\0' && xisspace(*p))
+ p++;
+ filestart = p;
+ while (*p !='\0' && !xisspace(*p))
+ p++;
+ fileend = p;
+ while (*p !='\0' && xisspace(*p))
+ p++;
+ if (*p != '\0') {
+ fprintf(stderr,
+"Unexpected sixth argument in '%s'!\n", fileline);
+ return RET_ERROR;
+ }
+ if (*md5start == '\0' || *sizestart == '\0' || *sectionstart == '\0'
+ || *priostart == '\0' || *filestart == '\0') {
+ fprintf(stderr,
+"Wrong number of arguments in '%s' (5 expected)!\n",
+ fileline);
+ return RET_ERROR;
+ }
+ if ((sectionend - sectionstart == 6 &&
+ strncmp(sectionstart, "byhand", 6) == 0) ||
+ (sectionend - sectionstart > 4 &&
+ strncmp(sectionstart, "raw-", 4) == 0)) {
+ section = strndup(sectionstart, sectionend - sectionstart);
+ priority = strndup(priostart, prioend - priostart);
+ basefilename = strndup(filestart, fileend - filestart);
+ if (FAILEDTOALLOC(section) || FAILEDTOALLOC(priority) ||
+ FAILEDTOALLOC(basefilename)) {
+ free(section); free(priority);
+ free(basefilename);
+ return RET_ERROR_OOM;
+ }
+ hash_p->start = md5start;
+ hash_p->len = md5end - md5start;
+ size_p->start = sizestart;
+ size_p->len = sizeend - sizestart;
+ *result_section = section;
+ *result_priority = priority;
+ *result_basename = basefilename;
+ *result_architecture = atom_unknown;
+ *result_name = NULL;
+ *result_type = fe_BYHAND;
+ return RET_OK;
+ }
+
+ p = filestart;
+ while (*p != '\0' && *p != '_' && !xisspace(*p))
+ p++;
+ if (*p != '_') {
+ if (*p == '\0')
+ fprintf(stderr,
+"No underscore found in file name in '%s'!\n",
+ fileline);
+ else
+ fprintf(stderr,
+"Unexpected character '%c' in file name in '%s'!\n",
+ *p, fileline);
+ return RET_ERROR;
+ }
+ nameend = p;
+ p++;
+ versionstart = p;
+
+ /* changing 3.0 format to now also allow _ in source files
+ * makes this parsing quite more ugly... */
+
+ while (*p !='\0' && !xisspace(*p))
+ p++;
+ l = p - versionstart;
+
+ /* identify the binary types (they have no compression
+ * and will need a _ */
+
+ if (l >= 4 && memcmp(p-4, ".deb", 4) == 0)
+ type = fe_DEB;
+ else if (l >= 5 && memcmp(p-5, ".udeb", 5) == 0)
+ type = fe_UDEB;
+ else
+ type = fe_UNKNOWN;
+
+ if (type != fe_UNKNOWN) {
+ /* a _ should separate the version from the rest */
+ p = versionstart;
+ names_overversion(&p, true);
+ if (*p != '\0' && *p != '_') {
+ fprintf(stderr,
+"Unexpected character '%c' in file name within '%s'!\n", *p, fileline);
+ return RET_ERROR;
+ }
+ if (*p != '_') {
+ fprintf(stderr,
+"Cannot cope with .[u]deb filename not containing an underscore (in '%s')!",
+ fileline);
+ return RET_ERROR;
+ }
+ p++;
+ archstart = p;
+ if (type == fe_DEB)
+ archend = versionstart + l - 4;
+ else {
+ assert (type == fe_UDEB);
+ archend = versionstart + l - 5;
+ }
+ if (archend - archstart == 6 &&
+ strncmp(archstart, "source", 6) == 0) {
+ fprintf(stderr,
+"Architecture 'source' not allowed for .[u]debs ('%s')!\n", filestart);
+ return RET_ERROR;
+ }
+ } else {
+ enum compression c;
+ const char *eoi;
+ bool issignature = false;
+
+ /* without those, it gets more complicated.
+ * It's not .deb or .udeb, so most likely a
+ * source file (or perhaps a log (reprepro extension)) */
+
+ /* if it uses a known compression, things are easy,
+ * so try this first: */
+
+ if (l > 4 && memcmp(versionstart + l - 4, ".asc", 4) == 0 ) {
+ issignature = true;
+ l -= 4;
+ }
+ c = compression_by_suffix(versionstart, &l);
+ p = versionstart + l;
+
+ archstart = "source";
+ archend = archstart + 6;
+ if (l > 9 && strncmp(p-9, ".orig.tar", 9) == 0) {
+ type = fe_ORIG;
+ eoi = p - 9;
+ } else if (l > 4 && strncmp(p-4, ".tar", 4) == 0) {
+ type = fe_TAR;
+ eoi = p - 4;
+ } else if (issignature) {
+ /* only .tar.* files are allowed to have .asc files: */
+ issignature = false;
+ } else if (l > 5 && strncmp(p-5, ".diff", 5) == 0) {
+ type = fe_DIFF;
+ eoi = p - 5;
+ } else if (l > 4 && strncmp(p-4, ".dsc", 4) == 0
+ && c == c_none) {
+ type = fe_DSC;
+ eoi = p - 4;
+ } else if (l > 4 && strncmp(p-4, ".git", 4) == 0
+ && c == c_none) {
+ type = fe_ALTSRC;
+ eoi = p - 4;
+ } else if (l > 4 && strncmp(p-4, ".log", 4) == 0) {
+ type = fe_LOG;
+ eoi = p - 4;
+ } else if (l > 6 && strncmp(p-6, ".build", 6) == 0) {
+ type = fe_LOG;
+ eoi = p - 6;
+ } else if (l > 10 && strncmp(p-10, ".buildinfo", 10) == 0) {
+ type = fe_BUILDINFO;
+ eoi = p - 10;
+ }
+ if (type != fe_UNKNOWN) {
+ /* check for a proper version */
+ p = versionstart;
+ names_overversion(&p, true);
+ if (p >= eoi) {
+ /* all well */
+ } else if (type == fe_TAR) {
+ /* a tar might be a component with ugly
+ * data between .orig- and the .tar.c */
+ const char *o = strstr(versionstart, ".orig-");
+ if (o == NULL || o > eoi) {
+ fprintf(stderr,
+"Unexpected character '%c' in file name within '%s'!\n",
+ *p, fileline);
+ return RET_ERROR;
+ }
+ checkfilename = true;
+ } else if (type == fe_LOG || type == fe_BUILDINFO) {
+ if (*p == '_') {
+ archstart = p + 1;
+ archend = eoi;
+ checkfilename = true;
+ } else {
+ fprintf(stderr,
+"Unexpected character '%c' in file name within '%s'!\n",
+ *p, fileline);
+ }
+ } else {
+ fprintf(stderr,
+"Unexpected character '%c' in file name within '%s'!\n",
+ *p, fileline);
+ return RET_ERROR;
+
+ }
+ if (issignature)
+ type = fe_SIG;
+ } else {
+ /* everything else is assumed to be source */
+ checkfilename = true;
+ fprintf(stderr,
+"Unknown file type: '%s', assuming source format...\n", fileline);
+ }
+ }
+ section = strndup(sectionstart, sectionend - sectionstart);
+ priority = strndup(priostart, prioend - priostart);
+ basefilename = strndup(filestart, fileend - filestart);
+ // TODO: this does not make much sense for log files, as they might
+ // list multiple..
+ architecture = architecture_find_l(archstart, archend - archstart);
+ name = strndup(filestart, nameend - filestart);
+ if (FAILEDTOALLOC(section) || FAILEDTOALLOC(priority) ||
+ FAILEDTOALLOC(basefilename) || FAILEDTOALLOC(name)) {
+ free(section); free(priority);
+ free(basefilename); free(name);
+ return RET_ERROR_OOM;
+ }
+ if (checkfilename || !atom_defined(architecture)) {
+ retvalue r;
+
+ /* as we no longer run properversion over the whole
+ * rest of the string, at least make sure nothing evil
+ * is in this name */
+ r = properfilename(basefilename);
+ if (!RET_IS_OK(r)) {
+ assert (r != RET_NOTHING);
+ free(section); free(priority);
+ free(basefilename); free(name);
+ return r;
+ }
+ }
+ hash_p->start = md5start;
+ hash_p->len = md5end - md5start;
+ size_p->start = sizestart;
+ size_p->len = sizeend - sizestart;
+ *result_section = section;
+ *result_priority = priority;
+ *result_basename = basefilename;
+ *result_architecture = architecture;
+ *result_name = name;
+ *result_type = type;
+ return RET_OK;
+}
diff --git a/changes.h b/changes.h
new file mode 100644
index 0000000..b4206d9
--- /dev/null
+++ b/changes.h
@@ -0,0 +1,24 @@
+#ifndef REPREPRO_CHANGES_H
+#define REPREPRO_CHANGES_H
+
+#ifndef REPREPRO_ATOMS_H
+#include "atoms.h"
+#endif
+
+typedef enum {
+ fe_UNKNOWN=0,
+ fe_DEB, fe_UDEB,
+ fe_DSC, fe_DIFF, fe_ORIG, fe_TAR,
+ fe_SIG,
+ fe_ALTSRC,
+ fe_BYHAND, fe_LOG, fe_CHANGES,
+ fe_BUILDINFO
+} filetype;
+
+#define FE_PACKAGE(ft) ((ft) == fe_DEB || (ft) == fe_UDEB || (ft) == fe_DSC)
+#define FE_BINARY(ft) ((ft) == fe_DEB || (ft) == fe_UDEB)
+#define FE_SOURCE(ft) ((ft) == fe_DIFF || (ft) == fe_ORIG || (ft) == fe_TAR || (ft) == fe_DSC || (ft) == fe_UNKNOWN || (ft) == fe_ALTSRC || (ft) == fe_SIG)
+
+struct hash_data;
+retvalue changes_parsefileline(const char * /*fileline*/, /*@out@*/filetype *, /*@out@*/char ** /*result_basename*/, /*@out@*/struct hash_data *, /*@out@*/struct hash_data *, /*@out@*/char ** /*result_section*/, /*@out@*/char ** /*result_priority*/, /*@out@*/architecture_t *, /*@out@*/char ** /*result_name*/);
+#endif
diff --git a/checkin.c b/checkin.c
new file mode 100644
index 0000000..5b1d15d
--- /dev/null
+++ b/checkin.c
@@ -0,0 +1,1612 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2003,2004,2005,2006,2007,2009,2012 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <ctype.h>
+#include "error.h"
+#include "ignore.h"
+#include "strlist.h"
+#include "mprintf.h"
+#include "atoms.h"
+#include "checksums.h"
+#include "names.h"
+#include "filecntl.h"
+#include "dirs.h"
+#include "chunks.h"
+#include "reference.h"
+#include "signature.h"
+#include "sources.h"
+#include "files.h"
+#include "tracking.h"
+#include "guesscomponent.h"
+#include "override.h"
+#include "checkindsc.h"
+#include "checkindeb.h"
+#include "checkin.h"
+#include "uploaderslist.h"
+#include "log.h"
+#include "dpkgversions.h"
+#include "changes.h"
+
+/* Things to do when including a .changes-file:
+ * - Read in the chunk of the possible signed file.
+ * (In later versions possibly checking the signature)
+ * - Parse it, extracting:
+ * + Distribution
+ * + Source
+ * + Architecture
+ * + Binary
+ * + Version
+ * + ...
+ * + Files
+ * - Calculate what files are expectable...
+ * - Compare supplied filed with files expected.
+ * - (perhaps: write what was done and changes to some logfile)
+ * - add supplied files to the pool and register them in files.db
+ * - add the .dsc-files via checkindsc.c
+ * - add the .deb-filed via checkindeb.c
+ *
+ */
+
+struct fileentry {
+ struct fileentry *next;
+ char *basename;
+ filetype type;
+ struct checksums *checksums;
+ char *section;
+ char *priority;
+ architecture_t architecture_into;
+ char *name;
+ /* this might be different for different files,
+ * (though this is only allowed in rare cases),
+ * will be set by _fixfields */
+ component_t component;
+ /* only set after changes_includefiles */
+ char *filekey;
+ /* was already found in the pool before */
+ bool wasalreadythere;
+ /* set between checkpkg and includepkg */
+ struct strlist needed_filekeys;
+ union { struct dsc_headers dsc;
+ struct debpackage *deb;} pkg;
+ /* only valid while parsing: */
+ struct hashes hashes;
+};
+
+struct changes {
+ /* Things read by changes_read: */
+ char *source, *sourceversion, *changesversion;
+ struct strlist distributions,
+ architectures,
+ binaries;
+ struct fileentry *files;
+ char *control;
+ struct signatures *signatures;
+ /* Things to be set by changes_fixfields: */
+ /* the component source files are put into */
+ component_t srccomponent;
+ /* != NULL if changesfile was put into pool/ */
+ /*@null@*/ char *changesfilekey;
+ /* the directory where source files are put into */
+ char *srcdirectory;
+ /* (only to warn if multiple are used) */
+ component_t firstcomponent;
+ /* the directory the .changes file resides in */
+ char *incomingdirectory;
+ /* the Version: and the version in Source: differ */
+ bool isbinnmu;
+};
+
+static void freeentries(/*@only@*/struct fileentry *entry) {
+ struct fileentry *h;
+
+ while (entry != NULL) {
+ h = entry->next;
+ free(entry->filekey);
+ free(entry->basename);
+ checksums_free(entry->checksums);
+ free(entry->section);
+ free(entry->priority);
+ free(entry->name);
+ if (FE_BINARY(entry->type))
+ deb_free(entry->pkg.deb);
+ else if (entry->type == fe_DSC) {
+ strlist_done(&entry->needed_filekeys);
+ sources_done(&entry->pkg.dsc);
+ }
+ free(entry);
+ entry = h;
+ }
+}
+
+static void changes_free(/*@only@*/struct changes *changes) {
+ if (changes != NULL) {
+ free(changes->source);
+ free(changes->sourceversion);
+ free(changes->changesversion);
+ strlist_done(&changes->architectures);
+ strlist_done(&changes->binaries);
+ freeentries(changes->files);
+ strlist_done(&changes->distributions);
+ free(changes->control);
+ free(changes->srcdirectory);
+ free(changes->changesfilekey);
+// trackedpackage_free(changes->trackedpkg);
+ free(changes->incomingdirectory);
+ signatures_free(changes->signatures);
+ }
+ free(changes);
+}
+
+
+static retvalue newentry(struct fileentry **entry, const char *fileline, const struct atomlist *packagetypes, const struct atomlist *forcearchitectures, const char *sourcename, bool includebyhand, bool includelogs, bool includebuildinfos, bool *ignoredlines_p, bool skip_binaries) {
+ struct fileentry *e;
+ retvalue r;
+
+ e = zNEW(struct fileentry);
+ if (FAILEDTOALLOC(e))
+ return RET_ERROR_OOM;
+
+ r = changes_parsefileline(fileline, &e->type, &e->basename,
+ &e->hashes.hashes[cs_md5sum],
+ &e->hashes.hashes[cs_length],
+ &e->section, &e->priority, &e->architecture_into,
+ &e->name);
+ if (RET_WAS_ERROR(r)) {
+ free(e);
+ return r;
+ }
+ assert (RET_IS_OK(r));
+ if (e->type == fe_BYHAND) {
+ if (!includebyhand) {
+ // TODO: at least check them and fail if wrong?
+ fprintf(stderr, "Ignoring byhand file: '%s'!\n",
+ e->basename);
+ freeentries(e);
+ *ignoredlines_p = true;
+ return RET_NOTHING;
+ }
+ e->next = *entry;
+ *entry = e;
+ return RET_OK;
+ }
+ if (FE_SOURCE(e->type) && limitations_missed(packagetypes, pt_dsc)) {
+ freeentries(e);
+ *ignoredlines_p = true;
+ return RET_NOTHING;
+ }
+ if (e->type == fe_DEB && limitations_missed(packagetypes, pt_deb)) {
+ freeentries(e);
+ *ignoredlines_p = true;
+ return RET_NOTHING;
+ }
+ if (e->type == fe_UDEB && limitations_missed(packagetypes, pt_udeb)) {
+ freeentries(e);
+ *ignoredlines_p = true;
+ return RET_NOTHING;
+ }
+ if (e->type != fe_LOG && e->type != fe_BUILDINFO &&
+ e->architecture_into == architecture_source &&
+ strcmp(e->name, sourcename) != 0) {
+ fprintf(stderr,
+"Warning: File '%s' looks like source but does not start with '%s_'!\n",
+ e->basename, sourcename);
+ } else if (e->type == fe_BUILDINFO) {
+ if (strcmp(e->name, sourcename) != 0) {
+ fprintf(stderr,
+"Warning: File '%s' looks like buildinfo but does not start with '%s_'!\n",
+ e->basename, sourcename);
+ }
+ if (!includebuildinfos) {
+ if (verbose > 2)
+ fprintf(stderr,
+"Ignoring buildinfo file: '%s'!\n", e->basename);
+ freeentries(e);
+ *ignoredlines_p = true;
+ return RET_NOTHING;
+ }
+ /* otherwise the normal rules like for .deb, see below */
+ }
+ if (e->type == fe_LOG) {
+ if (strcmp(e->name, sourcename) != 0) {
+ fprintf(stderr,
+"Warning: File '%s' looks like log but does not start with '%s_'!\n",
+ e->basename, sourcename);
+ }
+ if (!includelogs) {
+ // TODO: at least check them and fail if wrong?
+ fprintf(stderr, "Ignoring log file: '%s'!\n",
+ e->basename);
+ freeentries(e);
+ *ignoredlines_p = true;
+ return RET_NOTHING;
+ }
+ /* a log file without parseable architecture (atom undefined)
+ * might still belong to an forced architecture (as it might
+ * list multiples), so cannot be excluded here: */
+ if (atom_defined(e->architecture_into) &&
+ limitations_missed(forcearchitectures,
+ e->architecture_into)) {
+ if (verbose > 1)
+ fprintf(stderr,
+"Skipping '%s' as not for architecture ",
+ e->basename);
+ atomlist_fprint(stderr, at_architecture,
+ forcearchitectures);
+ fputs(".\n", stderr);
+ freeentries(e);
+ *ignoredlines_p = true;
+ return RET_NOTHING;
+ }
+ } else if (forcearchitectures != NULL) {
+ if (e->architecture_into == architecture_all &&
+ !skip_binaries) {
+ if (verbose > 2) {
+ fprintf(stderr,
+"Limiting '%s' to architectures ",
+ e->basename);
+ atomlist_fprint(stderr, at_architecture,
+ forcearchitectures);
+ fputs(" as requested.\n", stderr);
+ }
+ /* keep e->architecture_into to all, this wil
+ * be restricted to forcearchitectures when added */
+ } else if (!atomlist_in(forcearchitectures,
+ e->architecture_into)) {
+ if (verbose > 1) {
+ if (atom_defined(e->architecture_into))
+ fprintf(stderr,
+"Skipping '%s' as architecture '%s' is not in the requested set.\n",
+ e->basename,
+ atoms_architectures[
+ e->architecture_into]);
+ else
+ fprintf(stderr,
+"Skipping '%s' as architecture is not in the requested set.\n",
+ e->basename);
+ }
+ freeentries(e);
+ *ignoredlines_p = true;
+ return RET_NOTHING;
+ }
+ }
+
+ e->next = *entry;
+ *entry = e;
+ return RET_OK;
+}
+
+/* Parse the Files-header to see what kind of files we carry around */
+static retvalue changes_parsefilelines(const char *filename, struct changes *changes, const struct strlist *filelines, const struct atomlist *packagetypes, const struct atomlist *forcearchitectures, bool includebyhand, bool includelogs, bool includebuildinfos, bool *ignoredlines_p, bool skip_binaries) {
+ retvalue result, r;
+ int i;
+
+ assert (changes->files == NULL);
+ result = RET_NOTHING;
+
+ for (i = 0 ; i < filelines->count ; i++) {
+ const char *fileline = filelines->values[i];
+
+ r = newentry(&changes->files, fileline,
+ packagetypes, forcearchitectures,
+ changes->source,
+ includebyhand, includelogs, includebuildinfos,
+ ignoredlines_p, skip_binaries);
+ RET_UPDATE(result, r);
+ if (r == RET_ERROR)
+ return r;
+ }
+ if (result == RET_NOTHING) {
+ fprintf(stderr,
+"%s: Not enough files in .changes!\n", filename);
+ return RET_ERROR;
+ }
+ return result;
+}
+
+static retvalue changes_addhashes(const char *filename, struct changes *changes, enum checksumtype cs, struct strlist *filelines, bool ignoresomefiles) {
+ int i;
+ retvalue r;
+
+ for (i = 0 ; i < filelines->count ; i++) {
+ struct hash_data data, size;
+ const char *fileline = filelines->values[i];
+ struct fileentry *e;
+ const char *basefilename;
+
+ r = hashline_parse(filename, fileline, cs, &basefilename,
+ &data, &size);
+ if (r == RET_NOTHING)
+ continue;
+ if (RET_WAS_ERROR(r))
+ return r;
+ e = changes->files;
+ while (e != NULL && strcmp(e->basename, basefilename) != 0)
+ e = e->next;
+ if (e == NULL) {
+ if (ignoresomefiles)
+ /* we might already have ignored files when
+ * creating changes->files, so we cannot say
+ * if this is an error. */
+ continue;
+ fprintf(stderr,
+"In '%s': file '%s' listed in '%s' but not in 'Files'\n",
+ filename, basefilename,
+ changes_checksum_names[cs]);
+ return RET_ERROR;
+ }
+ if (e->hashes.hashes[cs_length].len != size.len ||
+ memcmp(e->hashes.hashes[cs_length].start,
+ size.start, size.len) != 0) {
+ fprintf(stderr,
+"In '%s': file '%s' listed in '%s' with different size than in 'Files'\n",
+ filename, basefilename,
+ changes_checksum_names[cs]);
+ return RET_ERROR;
+ }
+ e->hashes.hashes[cs] = data;
+ }
+ return RET_OK;
+}
+
+static retvalue changes_finishhashes(struct changes *changes) {
+ struct fileentry *e;
+ retvalue r;
+
+ for (e = changes->files ; e != NULL ; e = e->next) {
+ r = checksums_initialize(&e->checksums, e->hashes.hashes);
+ if (RET_WAS_ERROR(r))
+ return r;
+ }
+ return RET_OK;
+}
+
+
+static retvalue check(const char *filename, struct changes *changes, const char *field) {
+ retvalue r;
+
+ r = chunk_checkfield(changes->control, field);
+ if (r == RET_NOTHING) {
+ if (IGNORING(missingfield,
+"In '%s': Missing '%s' field!\n", filename, field)) {
+ return RET_OK;
+ } else {
+ return RET_ERROR;
+ }
+ }
+ return r;
+}
+
+static retvalue changes_read(const char *filename, /*@out@*/struct changes **changes, const struct atomlist *packagetypes, const struct atomlist *forcearchitectures, bool includebyhand, bool includelogs, bool includebuildinfos) {
+ retvalue r;
+ struct changes *c;
+ struct strlist filelines[cs_hashCOUNT];
+ enum checksumtype cs;
+ bool broken, ignoredlines;
+ int versioncmp;
+ bool skip_binaries;
+
+#define E(err) { \
+ if (r == RET_NOTHING) { \
+ fprintf(stderr, "In '%s': " err "\n", filename); \
+ r = RET_ERROR; \
+ } \
+ if (RET_WAS_ERROR(r)) { \
+ changes_free(c); \
+ return r; \
+ } \
+ }
+#define R { \
+ if (RET_WAS_ERROR(r)) { \
+ changes_free(c); \
+ return r; \
+ } \
+ }
+
+
+ c = zNEW(struct changes);
+ if (FAILEDTOALLOC(c))
+ return RET_ERROR_OOM;
+ r = signature_readsignedchunk(filename, filename,
+ &c->control, &c->signatures, &broken);
+ R;
+ if (broken && !IGNORING(brokensignatures,
+"'%s' contains only broken signatures.\n"
+"This most likely means the file was damaged or edited improperly.\n",
+ filename)) {
+ r = RET_ERROR;
+ R;
+ }
+ r = check(filename, c, "Format");
+ R;
+ r = check(filename, c, "Date");
+ R;
+ r = chunk_getnameandversion(c->control, "Source",
+ &c->source, &c->sourceversion);
+ E("Missing 'Source' field");
+ r = propersourcename(c->source);
+ R;
+ if (c->sourceversion != NULL) {
+ r = properversion(c->sourceversion);
+ R;
+ }
+ r = chunk_getwordlist(c->control, "Binary", &c->binaries);
+ E("Missing 'Binary' field");
+ r = chunk_getwordlist(c->control, "Architecture", &c->architectures);
+ E("Missing 'Architecture' field");
+ r = chunk_getvalue(c->control, "Version", &c->changesversion);
+ E("Missing 'Version' field");
+ r = properversion(c->changesversion);
+ E("Malforce Version number");
+ if (c->sourceversion == NULL) {
+ c->sourceversion = strdup(c->changesversion);
+ if (FAILEDTOALLOC(c->sourceversion)) {
+ changes_free(c);
+ return RET_ERROR_OOM;
+ }
+ c->isbinnmu = false;
+ } else {
+ r = dpkgversions_cmp(c->sourceversion, c->changesversion,
+ &versioncmp);
+ E("Error comparing versions. (That should have been caught earlier, why now?)");
+ c->isbinnmu = versioncmp != 0;
+ }
+ r = chunk_getwordlist(c->control, "Distribution", &c->distributions);
+ E("Missing 'Distribution' field");
+ r = check(filename, c, "Maintainer");
+ R;
+ r = chunk_getextralinelist(c->control,
+ changes_checksum_names[cs_md5sum],
+ &filelines[cs_md5sum]);
+ E("Missing 'Files' field!");
+ ignoredlines = false;
+ /* check if forcearchitectures allows non-source binaries,
+ * (used to check if Architecture all are skipped) */
+ if (forcearchitectures == NULL) {
+ skip_binaries = false;
+ } else {
+ skip_binaries = !atomlist_hasexcept(forcearchitectures,
+ architecture_source);
+ }
+ r = changes_parsefilelines(filename, c, &filelines[cs_md5sum],
+ packagetypes, forcearchitectures,
+ includebyhand, includelogs, includebuildinfos,
+ &ignoredlines, skip_binaries);
+ if (RET_WAS_ERROR(r)) {
+ strlist_done(&filelines[cs_md5sum]);
+ changes_free(c);
+ return r;
+ }
+ for (cs = cs_firstEXTENDED ; cs < cs_hashCOUNT ; cs++) {
+ r = chunk_getextralinelist(c->control,
+ changes_checksum_names[cs], &filelines[cs]);
+ if (RET_IS_OK(r))
+ r = changes_addhashes(filename, c, cs, &filelines[cs],
+ ignoredlines);
+ else
+ strlist_init(&filelines[cs]);
+ if (RET_WAS_ERROR(r)) {
+ while (cs-- > cs_md5sum)
+ strlist_done(&filelines[cs]);
+ changes_free(c);
+ return r;
+ }
+ }
+ r = changes_finishhashes(c);
+ for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++)
+ strlist_done(&filelines[cs]);
+ R;
+ r = dirs_getdirectory(filename, &c->incomingdirectory);
+ R;
+
+ *changes = c;
+ return RET_OK;
+#undef E
+#undef R
+}
+
+static retvalue changes_fixfields(const struct distribution *distribution, const char *filename, struct changes *changes, component_t forcecomponent, /*@null@*/const char *forcesection, /*@null@*/const char *forcepriority) {
+ struct fileentry *e;
+ retvalue r;
+ bool needsourcedir = false;
+ struct fileentry *needs_source_package = NULL;
+ bool has_source_package = false;
+
+ r = propersourcename(changes->source);
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ e = changes->files;
+ if (e == NULL) {
+ fprintf(stderr, "No files given in '%s'!\n", filename);
+ return RET_ERROR;
+ }
+
+ for (; e != NULL ; e = e->next) {
+ const struct overridedata *oinfo = NULL;
+ const char *force = NULL;
+
+ if (e->type == fe_BYHAND ||
+ e->type == fe_BUILDINFO ||
+ e->type == fe_LOG) {
+ needsourcedir = true;
+ continue;
+ }
+
+ /* section and priority are only needed for the dsc,
+ * not for the other source files */
+ if (FE_SOURCE(e->type) && !FE_PACKAGE(e->type)) {
+ needs_source_package = e;
+ continue;
+ }
+
+ if (forcesection == NULL || forcepriority == NULL) {
+ oinfo = override_search(
+ FE_BINARY(e->type)?(e->type==fe_UDEB?
+ distribution->overrides.udeb
+ :distribution->overrides.deb)
+ :distribution->overrides.dsc,
+ e->name);
+ }
+
+ if (forcesection != NULL)
+ force = forcesection;
+ else
+ force = override_get(oinfo, SECTION_FIELDNAME);
+ if (force != NULL) {
+ free(e->section);
+ e->section = strdup(force);
+ if (FAILEDTOALLOC(e->section))
+ return RET_ERROR_OOM;
+ }
+ if (strcmp(e->section, "unknown") == 0 && verbose >= 0) {
+ fprintf(stderr, "Warning: '%s' contains strange section '%s'!\n",
+ filename, e->section);
+ }
+ if (strcmp(e->section, "-") == 0) {
+ fprintf(stderr,
+"No section specified for '%s' in '%s'!\n", e->basename, filename);
+ return RET_ERROR;
+ }
+ if (forcepriority != NULL)
+ force = forcepriority;
+ else
+ force = override_get(oinfo, PRIORITY_FIELDNAME);
+ if (force != NULL) {
+ free(e->priority);
+ e->priority = strdup(force);
+ if (FAILEDTOALLOC(e->priority))
+ return RET_ERROR_OOM;
+ }
+ if (strcmp(e->priority, "-") == 0) {
+ fprintf(stderr,
+"No priority specified for '%s'!\n", filename);
+ return RET_ERROR;
+ }
+ if (!atom_defined(forcecomponent)) {
+ const char *fc;
+
+ fc = override_get(oinfo, "$Component");
+ if (fc != NULL) {
+ forcecomponent = component_find(fc);
+ if (!atom_defined(forcecomponent)) {
+ fprintf(stderr,
+"Unparseable component '%s' in $Component override of '%s'\n",
+ fc, e->name);
+ return RET_ERROR;
+ }
+ }
+ }
+
+ // I'm undecided here. If this is a udeb, one could also use
+ // distribution->udebcomponents. Though this might result
+ // in not really predictable guesses for the section.
+ r = guess_component(distribution->codename,
+ &distribution->components, changes->source,
+ e->section, forcecomponent,
+ &e->component);
+ if (RET_WAS_ERROR(r))
+ return r;
+ assert(atom_defined(e->component));
+
+ if (!atom_defined(changes->firstcomponent)) {
+ changes->firstcomponent = e->component;
+ } else if (changes->firstcomponent != e->component) {
+ fprintf(stderr,
+"Warning: %s contains files guessed to be in different components ('%s' vs '%s)!\n",
+ filename,
+ atoms_components[e->component],
+ atoms_components[changes->firstcomponent]);
+ }
+
+ if (FE_SOURCE(e->type)) {
+ assert (FE_PACKAGE(e->type));
+ has_source_package = true;
+ if (strcmp(changes->source, e->name) != 0) {
+ r = propersourcename(e->name);
+ if (RET_WAS_ERROR(r))
+ return r;
+ }
+ if (!atom_defined(changes->srccomponent)) {
+ changes->srccomponent = e->component;
+ } else if (changes->srccomponent != e->component) {
+ fprintf(stderr,
+"%s contains source files guessed to be in different components ('%s' vs '%s)!\n",
+ filename,
+ atoms_components[e->component],
+ atoms_components[changes->srccomponent]);
+ return RET_ERROR;
+ }
+ } else if (FE_BINARY(e->type)) {
+ r = properpackagename(e->name);
+ if (RET_WAS_ERROR(r))
+ return r;
+ // Let's just check here, perhaps
+ if (e->type == fe_UDEB &&
+ !atomlist_in(
+ &distribution->udebcomponents,
+ e->component)) {
+ fprintf(stderr,
+"Cannot put file '%s' into component '%s', as it is not listed in UDebComponents!\n",
+ e->basename,
+ atoms_components[e->component]);
+ return RET_ERROR;
+ }
+ } else {
+ assert (FE_SOURCE(e->type) || FE_BINARY(e->type));
+ fprintf(stderr, "Internal Error!\n");
+ return RET_ERROR;
+ }
+ }
+
+ if (needs_source_package != NULL && !has_source_package) {
+ fprintf(stderr,
+"'%s' looks like part of an source package, but no dsc file listed in the .changes file!\n",
+ needs_source_package->basename);
+ return RET_ERROR;
+ }
+ if (atom_defined(changes->srccomponent)) {
+ changes->srcdirectory = calc_sourcedir(changes->srccomponent,
+ changes->source);
+ if (FAILEDTOALLOC(changes->srcdirectory))
+ return RET_ERROR_OOM;
+ } else if (distribution->trackingoptions.includechanges ||
+ needsourcedir) {
+ component_t component = forcecomponent;
+ if (!atom_defined(forcecomponent)) {
+ for (e = changes->files ; e != NULL ; e = e->next) {
+ if (FE_PACKAGE(e->type)){
+ component = e->component;
+ break;
+ }
+ }
+ }
+ if (!atom_defined(component)) {
+ fprintf(stderr,
+"No component found to place .changes or byhand files in. Aborting.\n");
+ return RET_ERROR;
+ }
+ changes->srcdirectory = calc_sourcedir(component,
+ changes->source);
+ if (FAILEDTOALLOC(changes->srcdirectory))
+ return RET_ERROR_OOM;
+ }
+
+ return RET_OK;
+}
+
+static inline retvalue checkforarchitecture(const struct fileentry *e, architecture_t architecture) {
+ if (!atom_defined(architecture))
+ return RET_NOTHING;
+ while (e != NULL && e->architecture_into != architecture)
+ e = e->next;
+ if (e == NULL) {
+ if (!IGNORING(unusedarch,
+"Architecture header lists architecture '%s', but no files for it!\n",
+ atoms_architectures[architecture]))
+ return RET_ERROR;
+ }
+ return RET_OK;
+}
+
+static bool can_add_all(const struct atomlist *forcearchitectures, const struct distribution *d) {
+ const struct atomlist *da = &d->architectures;
+ int i;
+
+ if (forcearchitectures == NULL) {
+ return atomlist_hasexcept(da, architecture_source);
+ }
+ for (i = 0 ; i < forcearchitectures->count ; i++) {
+ architecture_t a = forcearchitectures->atoms[i];
+
+ if (a == architecture_source)
+ continue;
+ if (a == architecture_all)
+ return atomlist_hasexcept(da, architecture_source);
+ if (atomlist_in(da, a))
+ return true;
+ }
+ return false;
+}
+
+static retvalue changes_check(const struct distribution *distribution, const char *filename, struct changes *changes, const struct atomlist *forcearchitectures, const struct atomlist *packagetypes) {
+ int i;
+ struct fileentry *e;
+ retvalue r = RET_OK;
+ bool havedsc = false,
+ haveorig = false,
+ havetar = false,
+ havediff = false,
+ havealtsrc = false;
+
+ /* First check for each given architecture, if it has files: */
+ if (forcearchitectures != NULL) {
+ for (i = 0 ; i < forcearchitectures->count ; i++) {
+ architecture_t a = forcearchitectures->atoms[i];
+
+ if (!strlist_in(&changes->architectures,
+ atoms_architectures[a])) {
+ // TODO: check if this is sensible
+ if (!IGNORING(surprisingarch,
+"Architecture header does not list the"
+" architecture '%s' to be forced in!\n",
+ atoms_architectures[a]))
+ return RET_ERROR_MISSING;
+ }
+ r = checkforarchitecture(changes->files, a);
+ if (RET_WAS_ERROR(r))
+ return r;
+ }
+ } else {
+ bool limitedtosource = false;
+ bool limitedtononsource = false;
+
+ if (packagetypes != NULL) {
+ limitedtosource = true;
+ limitedtononsource = true;
+ for (i = 0 ; i < packagetypes->count ; i++) {
+ if (packagetypes->atoms[i] == pt_dsc)
+ limitedtononsource = false;
+ else
+ limitedtosource = false;
+ }
+ }
+
+ for (i = 0 ; i < changes->architectures.count ; i++) {
+ const char *architecture = changes->architectures.values[i];
+ if (strcmp(architecture, "source") == 0) {
+ if (limitedtononsource)
+ continue;
+ } else {
+ if (limitedtosource)
+ continue;
+ }
+ r = checkforarchitecture(changes->files,
+ architecture_find(architecture));
+ if (RET_WAS_ERROR(r))
+ return r;
+ }
+ }
+ /* Then check for each file, if its architecture is sensible
+ * and listed. */
+ for (e = changes->files ; e != NULL ; e = e->next) {
+ if (e->type == fe_BYHAND || e->type == fe_LOG) {
+ /* don't insist on a single architecture for those */
+ continue;
+ }
+ if (atom_defined(e->architecture_into)) {
+ if (e->architecture_into == architecture_all) {
+ /* "all" can be added if at least one binary
+ * architecture */
+ if (!can_add_all(forcearchitectures,
+ distribution))
+ e->architecture_into = atom_unknown;
+ } else if (!atomlist_in(&distribution->architectures,
+ e->architecture_into))
+ e->architecture_into = atom_unknown;
+ }
+ if (!atom_defined(e->architecture_into)) {
+ fprintf(stderr,
+"Error: '%s' has the wrong architecture to add it to %s!\n",
+ e->basename, distribution->codename);
+ return RET_ERROR;
+
+ }
+ if (!strlist_in(&changes->architectures,
+ atoms_architectures[e->architecture_into])) {
+ if (!IGNORING(surprisingarch,
+"'%s' looks like architecture '%s', but this is not listed in the Architecture-Header!\n",
+ e->basename,
+ atoms_architectures[e->architecture_into]))
+ return RET_ERROR;
+ }
+
+ if (e->type == fe_DSC) {
+ char *calculatedname;
+ if (havedsc) {
+ fprintf(stderr,
+"I don't know what to do with multiple .dsc files in '%s'!\n", filename);
+ return RET_ERROR;
+ }
+ havedsc = true;
+ calculatedname = calc_source_basename(changes->source,
+ changes->sourceversion);
+ if (FAILEDTOALLOC(calculatedname))
+ return RET_ERROR_OOM;
+ if (strcmp(calculatedname, e->basename) != 0) {
+ fprintf(stderr,
+"dsc file name is '%s' instead of the expected '%s'!\n",
+ e->basename, calculatedname);
+ free(calculatedname);
+ return RET_ERROR;
+ }
+ free(calculatedname);
+ } else if (e->type == fe_DIFF) {
+ if (havediff) {
+ fprintf(stderr,
+"I don't know what to do with multiple .diff files in '%s'!\n", filename);
+ return RET_ERROR;
+ }
+ havediff = true;
+ } else if (e->type == fe_ORIG) {
+ if (haveorig) {
+ fprintf(stderr,
+"I don't know what to do with multiple .orig.tar.gz files in '%s'!\n", filename);
+ return RET_ERROR;
+ }
+ haveorig = true;
+ } else if (e->type == fe_TAR) {
+ havetar = true;
+ } else if (e->type == fe_ALTSRC) {
+ havealtsrc = true;
+ }
+ }
+ if (havetar && !haveorig && havediff) {
+ fprintf(stderr,
+"I don't know what to do having a .tar.gz not being a .orig.tar.gz and a .diff.gz in '%s'!\n",
+ filename);
+ return RET_ERROR;
+ }
+ if (strlist_in(&changes->architectures, "source") && !havedsc &&
+ !limitations_missed(forcearchitectures, architecture_source) &&
+ !limitations_missed(packagetypes, pt_dsc)) {
+ fprintf(stderr,
+"I don't know what to do with a source-upload not containing a .dsc in '%s'!\n",
+ filename);
+ return RET_ERROR;
+ }
+ if (havedsc && !havediff && !haveorig && !havetar && !havealtsrc) {
+ fprintf(stderr,
+"I don't know what to do having a .dsc without a .diff.gz or .tar.gz in '%s'!\n",
+ filename);
+ return RET_ERROR;
+ }
+
+ /* check if signatures match files signed: */
+ for (e = changes->files ; e != NULL ; e = e->next) {
+ size_t el;
+ struct fileentry *f;
+
+ if (e->type != fe_SIG)
+ continue;
+
+ el = strlen(e->basename);
+
+ if (el <= 4 || memcmp(e->basename + el - 4, ".asc", 4) != 0)
+ continue;
+
+ for (f = changes->files ; f != NULL ; f = f->next) {
+ size_t fl = strlen(f->basename);
+
+ if (el != fl + 4)
+ continue;
+ if (memcmp(e->basename, f->basename, fl) != 0)
+ continue;
+ break;
+ }
+ if (f == NULL) {
+ fprintf(stderr,
+"Signature file without file to be signed: '%s'!\n",
+ e->basename);
+ return RET_ERROR;
+ }
+ }
+
+ return r;
+}
+
+static retvalue changes_checkfiles(const char *filename, struct changes *changes) {
+ struct fileentry *e;
+ retvalue r;
+
+ r = RET_NOTHING;
+
+ for (e = changes->files; e != NULL ; e = e->next) {
+ //TODO: decide earlier which files to include
+ if (e->type == fe_BYHAND) {
+ /* byhand files might have the same name and not
+ * contain the version, so store separately */
+ assert(changes->srcdirectory!=NULL);
+ e->filekey = mprintf("%s/%s_%s_byhand/%s",
+ changes->srcdirectory,
+ changes->source,
+ changes->changesversion,
+ e->basename);
+ } else if (FE_SOURCE(e->type) || e->type == fe_LOG
+ || e->type == fe_BUILDINFO) {
+ assert(changes->srcdirectory!=NULL);
+ e->filekey = calc_dirconcat(changes->srcdirectory,
+ e->basename);
+ } else {
+ char *directory;
+
+ // TODO: make this in-situ?
+ /* as the directory depends on the sourcename, it can be
+ * different for every file... */
+ directory = calc_sourcedir(e->component,
+ changes->source);
+ if (FAILEDTOALLOC(directory))
+ return RET_ERROR_OOM;
+ e->filekey = calc_dirconcat(directory, e->basename);
+ free(directory);
+ }
+
+ if (FAILEDTOALLOC(e->filekey))
+ return RET_ERROR_OOM;
+ /* do not copy yet, but only check if it could be included */
+ r = files_canadd(e->filekey, e->checksums);
+ if (RET_WAS_ERROR(r))
+ return r;
+ /* If is was already there, remember that */
+ if (r == RET_NOTHING) {
+ e->wasalreadythere = true;
+ } else {
+ /* and if it needs inclusion check if there is a file */
+ char *fullfilename;
+
+ assert(RET_IS_OK(r));
+ // TODO: add a --paranoid to also check md5sums before copying?
+
+ fullfilename = calc_dirconcat(
+ changes->incomingdirectory,
+ e->basename);
+ if (FAILEDTOALLOC(fullfilename))
+ return RET_ERROR_OOM;
+ if (!isregularfile(fullfilename)) {
+ fprintf(stderr,
+"Cannot find file '%s' needed by '%s'!\n", fullfilename, filename);
+ free(fullfilename);
+ return RET_ERROR_MISSING;
+ }
+ free(fullfilename);
+ }
+ }
+
+ return RET_OK;
+}
+
+static retvalue changes_includefiles(struct changes *changes) {
+ struct fileentry *e;
+ retvalue r;
+
+ r = RET_NOTHING;
+
+ for (e = changes->files; e != NULL ; e = e->next) {
+ assert (e->filekey != NULL);
+
+ if (e->wasalreadythere && checksums_iscomplete(e->checksums))
+ continue;
+
+ r = files_checkincludefile(changes->incomingdirectory,
+ e->basename, e->filekey, &e->checksums);
+ if (RET_WAS_ERROR(r))
+ return r;
+ }
+
+ return r;
+}
+
+/* delete the files included */
+static retvalue changes_deleteleftoverfiles(struct changes *changes, int delete) {
+ struct fileentry *e;
+ retvalue result, r;
+
+ if (delete < D_MOVE)
+ return RET_OK;
+
+ result = RET_OK;
+ // TODO: we currently only see files included here, so D_DELETE
+ // only affacts the .changes file.
+
+ for (e = changes->files; e != NULL ; e = e->next) {
+ char *fullorigfilename;
+
+ if (delete < D_DELETE && e->filekey == NULL)
+ continue;
+
+ fullorigfilename = calc_dirconcat(changes->incomingdirectory,
+ e->basename);
+
+ if (unlink(fullorigfilename) != 0) {
+ int err = errno;
+ fprintf(stderr, "Error deleting '%s': %d=%s\n",
+ fullorigfilename, err, strerror(err));
+ r = RET_ERRNO(err);
+ RET_UPDATE(result, r);
+ }
+ free(fullorigfilename);
+ }
+
+ return result;
+}
+
+static retvalue changes_check_sourcefile(struct changes *changes, struct fileentry *dsc, const char *basefilename, const char *filekey, struct checksums **checksums_p) {
+ retvalue r;
+
+ r = files_expect(filekey, *checksums_p, false);
+ if (RET_WAS_ERROR(r))
+ return r;
+ // TODO: get additionals checksum out of database, as future
+ // source file completion code might need them...
+ if (RET_IS_OK(r))
+ return RET_OK;
+ if (!IGNORABLE(missingfile)) {
+ fprintf(stderr,
+"Unable to find %s needed by %s!\n"
+"Perhaps you forgot to give dpkg-buildpackage the -sa option,\n"
+" or you could try --ignore=missingfile to guess possible files to use.\n",
+ filekey, dsc->basename);
+ return RET_ERROR_MISSING;
+ }
+ fprintf(stderr,
+"Unable to find %s!\n"
+"Perhaps you forgot to give dpkg-buildpackage the -sa option.\n"
+"--ignore=missingfile was given, searching for file...\n", filekey);
+
+ return files_checkincludefile(changes->incomingdirectory,
+ basefilename, filekey, checksums_p);
+}
+
+static retvalue dsc_prepare(struct changes *changes, struct fileentry *dsc, struct distribution *distribution, const char *dscfilename){
+ retvalue r;
+ const struct overridedata *oinfo;
+ char *dscbasename;
+ char *control;
+ int i;
+ bool broken;
+
+ assert (dsc->section != NULL);
+ assert (dsc->priority != NULL);
+ assert (atom_defined(changes->srccomponent));
+ assert (dsc->basename != NULL);
+ assert (dsc->checksums != NULL);
+ assert (changes->source != NULL);
+ assert (changes->sourceversion != NULL);
+
+ /* First make sure this distribution has a source section at all,
+ * for which it has to be listed in the "Architectures:"-field ;-) */
+ if (!atomlist_in(&distribution->architectures, architecture_source)) {
+ fprintf(stderr,
+"Cannot put a source package into Distribution '%s' not having 'source' in its 'Architectures:'-field!\n",
+ distribution->codename);
+ /* nota bene: this cannot be forced or ignored, as no target has
+ been created for this. */
+ return RET_ERROR;
+ }
+
+ /* Then take a closer look in the file: */
+ r = sources_readdsc(&dsc->pkg.dsc, dscfilename, dscfilename, &broken);
+ if (RET_IS_OK(r) && broken && !IGNORING(brokensignatures,
+"'%s' contains only broken signatures.\n"
+"This most likely means the file was damaged or edited improperly\n",
+ dscfilename))
+ r = RET_ERROR;
+ if (RET_IS_OK(r))
+ r = propersourcename(dsc->pkg.dsc.name);
+ if (RET_IS_OK(r))
+ r = properversion(dsc->pkg.dsc.version);
+ if (RET_IS_OK(r))
+ r = properfilenames(&dsc->pkg.dsc.files.names);
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ if (strcmp(changes->source, dsc->pkg.dsc.name) != 0) {
+ /* This cannot be ignored, as too much depends on it yet */
+ fprintf(stderr,
+"'%s' says it is '%s', while .changes file said it is '%s'\n",
+ dsc->basename, dsc->pkg.dsc.name,
+ changes->source);
+ return RET_ERROR;
+ }
+ if (strcmp(changes->sourceversion, dsc->pkg.dsc.version) != 0 &&
+ !IGNORING(wrongversion,
+"'%s' says it is version '%s', while .changes file said it is '%s'\n",
+ dsc->basename, dsc->pkg.dsc.version,
+ changes->sourceversion)) {
+ return RET_ERROR;
+ }
+
+ oinfo = override_search(distribution->overrides.dsc, dsc->pkg.dsc.name);
+
+ free(dsc->pkg.dsc.section);
+ dsc->pkg.dsc.section = strdup(dsc->section);
+ if (FAILEDTOALLOC(dsc->pkg.dsc.section))
+ return RET_ERROR_OOM;
+ free(dsc->pkg.dsc.priority);
+ dsc->pkg.dsc.priority = strdup(dsc->priority);
+ if (FAILEDTOALLOC(dsc->pkg.dsc.priority))
+ return RET_ERROR_OOM;
+
+ assert (dsc->pkg.dsc.name != NULL && dsc->pkg.dsc.version != NULL);
+
+ /* Add the dsc file to the list of files in this source package: */
+ dscbasename = strdup(dsc->basename);
+ if (FAILEDTOALLOC(dscbasename))
+ r = RET_ERROR_OOM;
+ else
+ r = checksumsarray_include(&dsc->pkg.dsc.files,
+ dscbasename, dsc->checksums);
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ /* Calculate the filekeys: */
+ r = calc_dirconcats(changes->srcdirectory,
+ &dsc->pkg.dsc.files.names, &dsc->needed_filekeys);
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ /* no one else might have looked yet, if we have them: */
+
+ assert (dsc->pkg.dsc.files.names.count == dsc->needed_filekeys.count);
+ for (i = 1 ; i < dsc->pkg.dsc.files.names.count ; i ++) {
+ if (!RET_WAS_ERROR(r)) {
+ r = changes_check_sourcefile(
+ changes, dsc,
+ dsc->pkg.dsc.files.names.values[i],
+ dsc->needed_filekeys.values[i],
+ &dsc->pkg.dsc.files.checksums[i]);
+ }
+ }
+
+ if (!RET_WAS_ERROR(r))
+ r = sources_complete(&dsc->pkg.dsc, changes->srcdirectory,
+ oinfo,
+ dsc->pkg.dsc.section, dsc->pkg.dsc.priority,
+ &control);
+ if (RET_IS_OK(r)) {
+ free(dsc->pkg.dsc.control);
+ dsc->pkg.dsc.control = control;
+ }
+ return r;
+}
+
+
+static retvalue changes_checkpkgs(struct distribution *distribution, struct changes *changes) {
+ struct fileentry *e;
+ retvalue r;
+
+ r = RET_NOTHING;
+
+ e = changes->files;
+ while (e != NULL) {
+ char *fullfilename;
+ if (!FE_PACKAGE(e->type)) {
+ e = e->next;
+ continue;
+ }
+ fullfilename = files_calcfullfilename(e->filekey);
+ if (FAILEDTOALLOC(fullfilename))
+ return RET_ERROR_OOM;
+ if (e->type == fe_DEB) {
+ r = deb_prepare(&e->pkg.deb,
+ e->component, e->architecture_into,
+ e->section, e->priority,
+ pt_deb,
+ distribution, fullfilename,
+ e->filekey, e->checksums,
+ &changes->binaries,
+ changes->source, changes->sourceversion);
+ } else if (e->type == fe_UDEB) {
+ r = deb_prepare(&e->pkg.deb,
+ e->component, e->architecture_into,
+ e->section, e->priority,
+ pt_udeb,
+ distribution, fullfilename,
+ e->filekey, e->checksums,
+ &changes->binaries,
+ changes->source, changes->sourceversion);
+ } else if (e->type == fe_DSC) {
+ if (!changes->isbinnmu || IGNORING(dscinbinnmu,
+"File '%s' looks like a source package, but this .changes looks like a binNMU\n"
+"(as '%s' (from Source:) and '%s' (From Version:) differ.)\n",
+ e->filekey, changes->sourceversion,
+ changes->changesversion)) {
+
+ assert (atom_defined(changes->srccomponent));
+ assert (changes->srcdirectory!=NULL);
+ r = dsc_prepare(changes, e,
+ distribution, fullfilename);
+ } else
+ r = RET_ERROR;
+ }
+
+ free(fullfilename);
+ if (RET_WAS_ERROR(r))
+ break;
+ e = e->next;
+ }
+
+ return r;
+}
+
+static retvalue changes_includepkgs(struct distribution *distribution, struct changes *changes, /*@null@*/struct trackingdata *trackingdata, const struct atomlist *forcearchitectures, bool *missed_p) {
+ struct fileentry *e;
+ retvalue result, r;
+
+ *missed_p = false;
+ r = distribution_prepareforwriting(distribution);
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ result = RET_NOTHING;
+
+ e = changes->files;
+ while (e != NULL) {
+ if (interrupted())
+ return RET_ERROR_INTERRUPTED;
+ if (e->type == fe_DEB) {
+ r = deb_addprepared(e->pkg.deb,
+ /* architecture all needs this, the rest is
+ * already filtered out */
+ (e->architecture_into == architecture_all)?
+ forcearchitectures:NULL,
+ pt_deb, distribution, trackingdata);
+ if (r == RET_NOTHING)
+ *missed_p = true;
+ } else if (e->type == fe_UDEB) {
+ r = deb_addprepared(e->pkg.deb,
+ /* architecture all needs this, the rest is
+ * already filtered out */
+ (e->architecture_into == architecture_all)?
+ forcearchitectures:NULL,
+ pt_udeb, distribution, trackingdata);
+ if (r == RET_NOTHING)
+ *missed_p = true;
+ } else if (e->type == fe_DSC) {
+ r = dsc_addprepared(&e->pkg.dsc,
+ changes->srccomponent,
+ &e->needed_filekeys,
+ distribution, trackingdata);
+ if (r == RET_NOTHING)
+ *missed_p = true;
+ } else if (e->type == fe_BUILDINFO && trackingdata != NULL) {
+ r = trackedpackage_addfilekey(trackingdata->tracks,
+ trackingdata->pkg,
+ ft_BUILDINFO, e->filekey, false);
+ e->filekey = NULL;
+ } else if (e->type == fe_LOG && trackingdata != NULL) {
+ r = trackedpackage_addfilekey(trackingdata->tracks,
+ trackingdata->pkg,
+ ft_LOG, e->filekey, false);
+ e->filekey = NULL;
+ } else if (e->type == fe_BYHAND && trackingdata != NULL) {
+ r = trackedpackage_addfilekey(trackingdata->tracks,
+ trackingdata->pkg,
+ ft_XTRA_DATA, e->filekey, false);
+ e->filekey = NULL;
+ } else
+ r = RET_NOTHING;
+ RET_UPDATE(result, r);
+
+ if (RET_WAS_ERROR(r))
+ break;
+ e = e->next;
+ }
+
+ logger_wait();
+
+ return result;
+}
+
+static void verifyarchitectures(const struct changes *changes, struct upload_conditions *conditions) {
+ const struct fileentry *e;
+
+ for (e = changes->files ; e != NULL ; e = e->next) {
+ if (FE_SOURCE(e->type)) {
+ if (!uploaders_verifyatom(conditions,
+ architecture_source))
+ break;
+ } else if (FE_BINARY(e->type)) {
+ if (!uploaders_verifyatom(conditions,
+ e->architecture_into))
+ break;
+ }
+ }
+}
+static void verifysection(const struct changes *changes, struct upload_conditions *conditions) {
+ const struct fileentry *e;
+
+ for (e = changes->files ; e != NULL ; e = e->next) {
+ if (FE_SOURCE(e->type)) {
+ if (!uploaders_verifystring(conditions, e->section))
+ break;
+ } else if (FE_BINARY(e->type)) {
+ if (!uploaders_verifystring(conditions, e->section))
+ break;
+ }
+ }
+}
+static void verifybinary(const struct changes *changes, struct upload_conditions *conditions) {
+ const struct fileentry *e;
+
+ for (e = changes->files ; e != NULL ; e = e->next) {
+ if (FE_BINARY(e->type)) {
+ if (!uploaders_verifystring(conditions, e->name))
+ break;
+ }
+ }
+}
+static void verifybyhands(const struct changes *changes, struct upload_conditions *conditions) {
+ const struct fileentry *e;
+
+ for (e = changes->files ; e != NULL ; e = e->next) {
+ if (e->type == fe_BYHAND) {
+ if (!uploaders_verifystring(conditions, e->name))
+ break;
+ }
+ }
+}
+
+static bool permissionssuffice(struct changes *changes, const struct distribution *into, struct upload_conditions *conditions) {
+ do switch (uploaders_nextcondition(conditions)) {
+ case uc_ACCEPTED:
+ return true;
+ case uc_REJECTED:
+ return false;
+ case uc_CODENAME:
+ (void)uploaders_verifystring(conditions,
+ into->codename);
+ break;
+ case uc_SOURCENAME:
+ assert (changes->source != NULL);
+ (void)uploaders_verifystring(conditions,
+ changes->source);
+ break;
+ case uc_SECTIONS:
+ verifysection(changes, conditions);
+ break;
+ case uc_BINARIES:
+ verifybinary(changes, conditions);
+ break;
+ case uc_BYHAND:
+ verifybyhands(changes, conditions);
+ break;
+ case uc_ARCHITECTURES:
+ verifyarchitectures(changes, conditions);
+ break;
+ } while (true);
+}
+
+/* insert the given .changes into the mirror in the <distribution>
+ * if forcecomponent, forcesection or forcepriority is NULL
+ * get it from the files or try to guess it. */
+retvalue changes_add(trackingdb const tracks, const struct atomlist *packagetypes, component_t forcecomponent, const struct atomlist *forcearchitectures, const char *forcesection, const char *forcepriority, struct distribution *distribution, const char *changesfilename, int delete) {
+ retvalue result, r;
+ struct changes *changes;
+ struct trackingdata trackingdata;
+ bool somethingwasmissed;
+
+ causingfile = changesfilename;
+
+ r = changes_read(changesfilename, &changes,
+ packagetypes, forcearchitectures,
+ distribution->trackingoptions.includebyhand,
+ distribution->trackingoptions.includelogs,
+ distribution->trackingoptions.includebuildinfos);
+ if (RET_WAS_ERROR(r))
+ return r;
+
+ if ((distribution->suite == NULL ||
+ !strlist_in(&changes->distributions, distribution->suite)) &&
+ !strlist_in(&changes->distributions, distribution->codename) &&
+ !strlist_intersects(&changes->distributions,
+ &distribution->alsoaccept)) {
+ if (!IGNORING(wrongdistribution,
+".changes put in a distribution not listed within it!\n")) {
+ changes_free(changes);
+ return RET_ERROR;
+ }
+ }
+
+ /* make sure caller has called distribution_loaduploaders */
+ assert (distribution->uploaders == NULL
+ || distribution->uploaderslist != NULL);
+ if (distribution->uploaderslist != NULL) {
+ struct upload_conditions *conditions;
+
+ r = uploaders_permissions(distribution->uploaderslist,
+ changes->signatures, &conditions);
+ assert (r != RET_NOTHING);
+ if (RET_WAS_ERROR(r)) {
+ changes_free(changes);
+ return r;
+ }
+ if (!permissionssuffice(changes, distribution, conditions) &&
+ !IGNORING(uploaders,
+"No rule allowing this package in found in %s!\n",
+ distribution->uploaders)) {
+ free(conditions);
+ changes_free(changes);
+ return RET_ERROR;
+ }
+ free(conditions);
+ }
+
+ /*look for component, section and priority to be correct or guess them*/
+ r = changes_fixfields(distribution, changesfilename, changes,
+ forcecomponent, forcesection, forcepriority);
+
+ /* do some tests if values are sensible */
+ if (!RET_WAS_ERROR(r))
+ r = changes_check(distribution, changesfilename, changes,
+ forcearchitectures, packagetypes);
+
+ if (interrupted())
+ RET_UPDATE(r, RET_ERROR_INTERRUPTED);
+
+ if (!RET_WAS_ERROR(r))
+ r = changes_checkfiles(changesfilename, changes);
+
+ if (interrupted())
+ RET_UPDATE(r, RET_ERROR_INTERRUPTED);
+
+ /* add files in the pool */
+ if (!RET_WAS_ERROR(r))
+ r = changes_includefiles(changes);
+
+ if (!RET_WAS_ERROR(r))
+ r = changes_checkpkgs(distribution, changes);
+
+ if (RET_WAS_ERROR(r)) {
+ changes_free(changes);
+ return r;
+ }
+
+ if (tracks != NULL) {
+ r = trackingdata_summon(tracks, changes->source,
+ changes->sourceversion, &trackingdata);
+ if (RET_WAS_ERROR(r)) {
+ changes_free(changes);
+ return r;
+ }
+ if (distribution->trackingoptions.includechanges) {
+ char *basefilename;
+ assert (changes->srcdirectory != NULL);
+
+ basefilename = calc_changes_basename(changes->source,
+ changes->changesversion,
+ &changes->architectures);
+ changes->changesfilekey =
+ calc_dirconcat(changes->srcdirectory,
+ basefilename);
+ free(basefilename);
+ if (FAILEDTOALLOC(changes->changesfilekey)) {
+ changes_free(changes);
+ trackingdata_done(&trackingdata);
+ return RET_ERROR_OOM;
+ }
+ if (interrupted())
+ r = RET_ERROR_INTERRUPTED;
+ else
+ r = files_preinclude(changesfilename,
+ changes->changesfilekey,
+ NULL);
+ if (RET_WAS_ERROR(r)) {
+ changes_free(changes);
+ trackingdata_done(&trackingdata);
+ return r;
+ }
+ }
+ }
+ if (interrupted()) {
+ if (tracks != NULL)
+ trackingdata_done(&trackingdata);
+ changes_free(changes);
+ return RET_ERROR_INTERRUPTED;
+ }
+
+ /* add the source and binary packages in the given distribution */
+ result = changes_includepkgs(distribution, changes,
+ (tracks!=NULL)?&trackingdata:NULL, forcearchitectures,
+ &somethingwasmissed);
+
+ if (RET_WAS_ERROR(result)) {
+ if (tracks != NULL) {
+ trackingdata_done(&trackingdata);
+ }
+ changes_free(changes);
+ return result;
+ }
+
+ if (tracks != NULL) {
+ if (changes->changesfilekey != NULL) {
+ char *changesfilekey = strdup(changes->changesfilekey);
+ assert (changes->srcdirectory != NULL);
+ if (FAILEDTOALLOC(changesfilekey)) {
+ trackingdata_done(&trackingdata);
+ changes_free(changes);
+ return RET_ERROR_OOM;
+ }
+
+ r = trackedpackage_addfilekey(tracks, trackingdata.pkg,
+ ft_CHANGES, changesfilekey, false);
+ RET_ENDUPDATE(result, r);
+ }
+ r = trackingdata_finish(tracks, &trackingdata);
+ RET_ENDUPDATE(result, r);
+ if (RET_WAS_ERROR(result)) {
+ changes_free(changes);
+ return result;
+ }
+ }
+
+ /* if something was included, call --changes notify scripts */
+ if (RET_IS_OK(result)) {
+ assert (logger_isprepared(distribution->logger));
+ logger_logchanges(distribution->logger, distribution->codename,
+ changes->source, changes->changesversion,
+ changes->control,
+ changesfilename, changes->changesfilekey);
+ }
+ /* wait for notify scripts (including those for the packages)
+ * before deleting the .changes */
+ logger_wait();
+
+ if ((delete >= D_MOVE && changes->changesfilekey != NULL) ||
+ delete >= D_DELETE) {
+ if (somethingwasmissed && delete < D_DELETE) {
+ if (verbose >= 0) {
+ fprintf(stderr,
+"Not deleting '%s' as no package was added or some package was missed.\n"
+"(Use --delete --delete to delete anyway in such cases)\n",
+ changesfilename);
+ }
+ } else {
+ if (verbose >= 5) {
+ printf("Deleting '%s'.\n", changesfilename);
+ }
+ if (unlink(changesfilename) != 0) {
+ int e = errno;
+ fprintf(stderr, "Error %d deleting '%s': %s\n",
+ e, changesfilename,
+ strerror(e));
+ }
+ }
+ }
+ result = changes_deleteleftoverfiles(changes, delete);
+ (void)changes_free(changes);
+
+ return result;
+}
diff --git a/checkin.h b/checkin.h
new file mode 100644
index 0000000..4bbf6b3
--- /dev/null
+++ b/checkin.h
@@ -0,0 +1,26 @@
+#ifndef REPREPRO_CHECKIN_H
+#define REPREPRO_CHECKIN_H
+
+#ifndef REPREPRO_ERROR_H
+#include "error.h"
+#warning "What's hapening here?"
+#endif
+#ifndef REPREPRO_DATABASE_H
+#include "database.h"
+#endif
+#ifndef REPREPRO_DISTRIBUTION_H
+#include "distribution.h"
+#endif
+#ifndef REPREPRO_ATOMS_H
+#include "atoms.h"
+#endif
+
+/* insert the given .changes into the mirror in the <distribution>
+ * if forcecomponent, forcesection or forcepriority is NULL
+ * get it from the files or try to guess it.
+ * if dereferencedfilekeys is != NULL, add filekeys that lost reference,
+ * if tracks != NULL, update/add tracking information there... */
+retvalue changes_add(/*@null@*/trackingdb, const struct atomlist * /*packagetypes*/, component_t, const struct atomlist * /*forcearchitecture*/, /*@null@*/const char * /*forcesection*/, /*@null@*/const char * /*forcepriority*/, struct distribution *, const char * /*changesfilename*/, int /*delete*/);
+
+#endif
+
diff --git a/checkindeb.c b/checkindeb.c
new file mode 100644
index 0000000..0cdd32f
--- /dev/null
+++ b/checkindeb.c
@@ -0,0 +1,401 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2003,2004,2005,2006,2007,2009,2012 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <ctype.h>
+#include "error.h"
+#include "ignore.h"
+#include "filecntl.h"
+#include "strlist.h"
+#include "checksums.h"
+#include "names.h"
+#include "checkindeb.h"
+#include "reference.h"
+#include "binaries.h"
+#include "files.h"
+#include "guesscomponent.h"
+#include "tracking.h"
+#include "override.h"
+#include "hooks.h"
+
+/* This file includes the code to include binaries, i.e.
+ to create the chunk for the Packages.gz-file and
+ to put it in the various databases.
+
+Things to do with .deb's checkin by hand: (by comparison with apt-ftparchive)
+- extract the control file (that's the hard part -> extractcontrol.c )
+- check for Package, Version, Architecture, Maintainer, Description
+- apply overwrite if necessary (section, priority and perhaps maintainer).
+- add Size, MD5sum, Filename, Priority, Section
+- remove Status (warning if existent?)
+- check for Optional-field and reject then..
+*/
+
+struct debpackage {
+ /* things to be set by deb_read: */
+ struct deb_headers deb;
+ /* things that will still be NULL then: */
+ component_t component;
+ /* with deb_calclocations: */
+ const char *filekey;
+ struct strlist filekeys;
+};
+
+void deb_free(/*@only@*/struct debpackage *pkg) {
+ if (pkg != NULL) {
+ binaries_debdone(&pkg->deb);
+ if (pkg->filekey != NULL)
+ strlist_done(&pkg->filekeys);
+ }
+ free(pkg);
+}
+
+/* read the data from a .deb, make some checks and extract some data */
+static retvalue deb_read(/*@out@*/struct debpackage **pkg, const char *filename, bool needssourceversion) {
+ retvalue r;
+ struct debpackage *deb;
+
+ deb = zNEW(struct debpackage);
+ if (FAILEDTOALLOC(deb))
+ return RET_ERROR_OOM;
+
+ r = binaries_readdeb(&deb->deb, filename, needssourceversion);
+ if (RET_IS_OK(r))
+ r = properpackagename(deb->deb.name);
+ if (RET_IS_OK(r))
+ r = propersourcename(deb->deb.source);
+ if (RET_IS_OK(r) && needssourceversion)
+ r = properversion(deb->deb.sourceversion);
+ if (RET_IS_OK(r))
+ r = properversion(deb->deb.version);
+ if (RET_WAS_ERROR(r)) {
+ deb_free(deb);
+ return r;
+ }
+ *pkg = deb;
+
+ return RET_OK;
+}
+
+static retvalue deb_preparelocation(struct debpackage *pkg, component_t forcecomponent, const struct atomlist *forcearchitectures, const char *forcesection, const char *forcepriority, packagetype_t packagetype, struct distribution *distribution, const struct overridedata **oinfo_ptr, const char *debfilename){
+ const struct atomlist *components;
+ const struct overridefile *binoverride;
+ const struct overridedata *oinfo;
+ retvalue r;
+
+ if (packagetype == pt_udeb) {
+ binoverride = distribution->overrides.udeb;
+ components = &distribution->udebcomponents;
+ } else {
+ binoverride = distribution->overrides.deb;
+ components = &distribution->components;
+ }
+
+ oinfo = override_search(binoverride, pkg->deb.name);
+ *oinfo_ptr = oinfo;
+ if (forcesection == NULL) {
+ forcesection = override_get(oinfo, SECTION_FIELDNAME);
+ }
+ if (forcepriority == NULL) {
+ forcepriority = override_get(oinfo, PRIORITY_FIELDNAME);
+ }
+ if (!atom_defined(forcecomponent)) {
+ const char *fc;
+
+ fc = override_get(oinfo, "$Component");
+ if (fc != NULL) {
+ forcecomponent = component_find(fc);
+ if (!atom_defined(forcecomponent)) {
+ fprintf(stderr,
+"Unparseable component '%s' in $Component override of '%s'\n",
+ fc, pkg->deb.name);
+ return RET_ERROR;
+ }
+ }
+ }
+
+ if (forcesection != NULL) {
+ free(pkg->deb.section);
+ pkg->deb.section = strdup(forcesection);
+ if (FAILEDTOALLOC(pkg->deb.section)) {
+ return RET_ERROR_OOM;
+ }
+ }
+ if (forcepriority != NULL) {
+ free(pkg->deb.priority);
+ pkg->deb.priority = strdup(forcepriority);
+ if (FAILEDTOALLOC(pkg->deb.priority)) {
+ return RET_ERROR_OOM;
+ }
+ }
+
+ if (pkg->deb.section == NULL) {
+ fprintf(stderr, "No section given for '%s', skipping.\n",
+ pkg->deb.name);
+ return RET_ERROR;
+ }
+ if (pkg->deb.priority == NULL) {
+ fprintf(stderr, "No priority given for '%s', skipping.\n",
+ pkg->deb.name);
+ return RET_ERROR;
+ }
+ if (strcmp(pkg->deb.section, "unknown") == 0 && verbose >= 0) {
+ fprintf(stderr, "Warning: strange section '%s'!\n",
+ pkg->deb.section);
+ }
+
+ /* decide where it has to go */
+
+ r = guess_component(distribution->codename, components,
+ pkg->deb.name, pkg->deb.section,
+ forcecomponent, &pkg->component);
+ if (RET_WAS_ERROR(r))
+ return r;
+ if (verbose > 0 && !atom_defined(forcecomponent)) {
+ fprintf(stderr, "%s: component guessed as '%s'\n", debfilename,
+ atoms_components[pkg->component]);
+ }
+
+ /* some sanity checks: */
+
+ if (forcearchitectures != NULL &&
+ pkg->deb.architecture != architecture_all &&
+ !atomlist_in(forcearchitectures,
+ pkg->deb.architecture)) {
+ fprintf(stderr,
+"Cannot add '%s', as it is architecture '%s' and you specified to only include ",
+ debfilename,
+ atoms_architectures[pkg->deb.architecture]);
+ atomlist_fprint(stderr, at_architecture, forcearchitectures);
+ fputs(".\n", stderr);
+ return RET_ERROR;
+ } else if (pkg->deb.architecture != architecture_all &&
+ !atomlist_in(&distribution->architectures,
+ pkg->deb.architecture)) {
+ (void)fprintf(stderr,
+"Error looking at '%s': '%s' is not one of the valid architectures: '",
+ debfilename,
+ atoms_architectures[pkg->deb.architecture]);
+ (void)atomlist_fprint(stderr, at_architecture,
+ &distribution->architectures);
+ (void)fputs("'\n", stderr);
+ return RET_ERROR;
+ }
+ if (!atomlist_in(components, pkg->component)) {
+ fprintf(stderr,
+"Error looking at %s': Would be placed in unavailable component '%s'!\n",
+ debfilename,
+ atoms_components[pkg->component]);
+ /* this cannot be ignored
+ * as there is not data structure available */
+ return RET_ERROR;
+ }
+
+ r = binaries_calcfilekeys(pkg->component, &pkg->deb,
+ packagetype, &pkg->filekeys);
+ if (RET_WAS_ERROR(r))
+ return r;
+ pkg->filekey = pkg->filekeys.values[0];
+ return RET_OK;
+}
+
+
+retvalue deb_prepare(/*@out@*/struct debpackage **deb, component_t forcecomponent, architecture_t forcearchitecture, const char *forcesection, const char *forcepriority, packagetype_t packagetype, struct distribution *distribution, const char *debfilename, const char * const givenfilekey, const struct checksums * checksums, const struct strlist *allowed_binaries, const char *expectedsourcepackage, const char *expectedsourceversion){
+ retvalue r;
+ struct debpackage *pkg;
+ const struct overridedata *oinfo;
+ char *control;
+ struct atomlist forcearchitectures;
+ const char *packagenametocheck;
+ char *base;
+ size_t l;
+
+ assert (givenfilekey != NULL);
+ assert (checksums != NULL);
+ assert (allowed_binaries != NULL);
+ assert (expectedsourcepackage != NULL);
+ assert (expectedsourceversion != NULL);
+
+ /* First taking a closer look in the file: */
+
+ r = deb_read(&pkg, debfilename, true);
+ if (RET_WAS_ERROR(r)) {
+ return r;
+ }
+
+ /* -dbgsym packages are not listed in the Binary header, so look
+ * for the base name instead */
+ packagenametocheck = pkg->deb.name;
+ l = strlen(pkg->deb.name);
+ if (l > sizeof("-dbgsym")-1 &&
+ strcmp(pkg->deb.name + l - (sizeof("dbgsym")), "-dbgsym") == 0) {
+ base = strndup(pkg->deb.name, l - (sizeof("dbgsym")));
+ if (FAILEDTOALLOC(base)) {
+ deb_free(pkg);
+ return RET_ERROR_OOM;
+ }
+ packagenametocheck = base;
+ } else {
+ base = NULL;
+ }
+
+ if (!strlist_in(allowed_binaries, packagenametocheck) &&
+ !IGNORING(surprisingbinary,
+"'%s' has packagename '%s' not listed in the .changes file!\n",
+ debfilename, packagenametocheck)) {
+ deb_free(pkg);
+ free(base);
+ return RET_ERROR;
+ }
+ free(base);
+ if (strcmp(pkg->deb.source, expectedsourcepackage) != 0) {
+ /* this cannot be ignored easily, as it determines
+ * the directory this file is stored into */
+ fprintf(stderr,
+"'%s' lists source package '%s', but .changes says it is '%s'!\n",
+ debfilename, pkg->deb.source,
+ expectedsourcepackage);
+ deb_free(pkg);
+ return RET_ERROR;
+ }
+ if (strcmp(pkg->deb.sourceversion, expectedsourceversion) != 0 &&
+ !IGNORING(wrongsourceversion,
+"'%s' lists source version '%s', but .changes says it is '%s'!\n",
+ debfilename, pkg->deb.sourceversion,
+ expectedsourceversion)) {
+ deb_free(pkg);
+ return RET_ERROR;
+ }
+
+ forcearchitectures.count = 1;
+ forcearchitectures.size = 1;
+ forcearchitectures.atoms = &forcearchitecture;
+
+ r = deb_preparelocation(pkg, forcecomponent, &forcearchitectures,
+ forcesection, forcepriority, packagetype, distribution,
+ &oinfo, debfilename);
+ if (RET_WAS_ERROR(r)) {
+ deb_free(pkg);
+ return r;
+ }
+
+ if (strcmp(givenfilekey, pkg->filekey) != 0) {
+ fprintf(stderr,
+"Name mismatch: .changes indicates '%s', but the file itself says '%s'!\n",
+ givenfilekey, pkg->filekey);
+ deb_free(pkg);
+ return RET_ERROR;
+ }
+ /* Prepare everything that can be prepared beforehand */
+ r = binaries_complete(&pkg->deb, pkg->filekey, checksums, oinfo,
+ pkg->deb.section, pkg->deb.priority, &control);
+ if (RET_WAS_ERROR(r)) {
+ deb_free(pkg);
+ return r;
+ }
+ free(pkg->deb.control); pkg->deb.control = control;
+ *deb = pkg;
+ return RET_OK;
+}
+
+retvalue deb_addprepared(const struct debpackage *pkg, const struct atomlist *forcearchitectures, packagetype_t packagetype, struct distribution *distribution, struct trackingdata *trackingdata) {
+ return binaries_adddeb(&pkg->deb, forcearchitectures,
+ packagetype, distribution, trackingdata,
+ pkg->component, &pkg->filekeys,
+ pkg->deb.control);
+}
+
+/* insert the given .deb into the mirror in <component> in the <distribution>
+ * putting things with architecture of "all" into <d->architectures> (and also
+ * causing error, if it is not one of them otherwise)
+ * if component is NULL, guessing it from the section. */
+retvalue deb_add(component_t forcecomponent, const struct atomlist *forcearchitectures, const char *forcesection, const char *forcepriority, packagetype_t packagetype, struct distribution *distribution, const char *debfilename, int delete, /*@null@*/trackingdb tracks) {
+ struct debpackage *pkg;
+ retvalue r;
+ struct trackingdata trackingdata;
+ const struct overridedata *oinfo;
+ char *control;
+ struct checksums *checksums;
+
+ causingfile = debfilename;
+
+ r = deb_read(&pkg, debfilename, tracks != NULL);
+ if (RET_WAS_ERROR(r)) {
+ return r;
+ }
+ r = deb_preparelocation(pkg, forcecomponent, forcearchitectures,
+ forcesection, forcepriority, packagetype, distribution,
+ &oinfo, debfilename);
+ if (RET_WAS_ERROR(r)) {
+ deb_free(pkg);
+ return r;
+ }
+ r = files_preinclude(debfilename, pkg->filekey, &checksums);
+ if (RET_WAS_ERROR(r)) {
+ deb_free(pkg);
+ return r;
+ }
+ /* Prepare everything that can be prepared beforehand */
+ r = binaries_complete(&pkg->deb, pkg->filekey, checksums, oinfo,
+ pkg->deb.section, pkg->deb.priority, &control);
+ checksums_free(checksums);
+ if (RET_WAS_ERROR(r)) {
+ deb_free(pkg);
+ return r;
+ }
+ free(pkg->deb.control); pkg->deb.control = control;
+
+ if (tracks != NULL) {
+ assert(pkg->deb.sourceversion != NULL);
+ r = trackingdata_summon(tracks,
+ pkg->deb.source, pkg->deb.sourceversion,
+ &trackingdata);
+ if (RET_WAS_ERROR(r)) {
+ deb_free(pkg);
+ return r;
+ }
+ }
+
+ r = binaries_adddeb(&pkg->deb, forcearchitectures,
+ packagetype, distribution,
+ (tracks!=NULL)?&trackingdata:NULL,
+ pkg->component, &pkg->filekeys,
+ pkg->deb.control);
+ RET_UPDATE(distribution->status, r);
+ deb_free(pkg);
+
+ if (tracks != NULL) {
+ retvalue r2;
+ r2 = trackingdata_finish(tracks, &trackingdata);
+ RET_ENDUPDATE(r, r2);
+ }
+
+ if (RET_IS_OK(r) && delete >= D_MOVE) {
+ deletefile(debfilename);
+ } else if (r == RET_NOTHING && delete >= D_DELETE)
+ deletefile(debfilename);
+
+ return r;
+}
diff --git a/checkindeb.h b/checkindeb.h
new file mode 100644
index 0000000..ebc2ec8
--- /dev/null
+++ b/checkindeb.h
@@ -0,0 +1,28 @@
+#ifndef REPREPRO_CHECKINDEB_H
+#define REPREPRO_CHECKINDEB_H
+
+#ifndef REPREPRO_ERROR_H
+#include "error.h"
+#warning "What's hapening here?"
+#endif
+#ifndef REPREPRO_DISTRIBUTION_H
+#include "distribution.h"
+#endif
+#ifndef REPREPRO_DATABASE_H
+#include "database.h"
+#endif
+
+/* insert the given .deb into the mirror in <component> in the <distribution>
+ * putting things with architecture of "all" into <architectures> (and also
+ * causing error, if it is not one of them otherwise)
+ * if overwrite is not NULL, it will be search for fields to reset for this
+ * package. (forcesection and forcepriority have higher priority than the
+ * information there), */
+retvalue deb_add(component_t, const struct atomlist * /*forcearchitectures*/, /*@null@*/const char * /*forcesection*/, /*@null@*/const char * /*forcepriority*/, packagetype_t, struct distribution *, const char * /*debfilename*/, int /*delete*/, /*@null@*/trackingdb);
+
+/* in two steps */
+struct debpackage;
+retvalue deb_addprepared(const struct debpackage *, const struct atomlist * /*forcearchitectures*/, packagetype_t, struct distribution *, struct trackingdata *);
+retvalue deb_prepare(/*@out@*/struct debpackage **, component_t, architecture_t /*forcearchitectures*/, const char * /*forcesection*/, const char * /*forcepriority*/, packagetype_t, struct distribution *, const char * /*debfilename*/, const char * const /*filekey*/, const struct checksums *, const struct strlist * /*allowed_binaries*/, const char * /*expectedsourcename*/, const char * /*expectedsourceversion*/);
+void deb_free(/*@only@*/struct debpackage *);
+#endif
diff --git a/checkindsc.c b/checkindsc.c
new file mode 100644
index 0000000..164115e
--- /dev/null
+++ b/checkindsc.c
@@ -0,0 +1,435 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2003,2004,2005,2006,2007,2008,2012 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <ctype.h>
+#include "error.h"
+#include "filecntl.h"
+#include "strlist.h"
+#include "checksums.h"
+#include "names.h"
+#include "checksums.h"
+#include "dirs.h"
+#include "checkindsc.h"
+#include "reference.h"
+#include "sources.h"
+#include "files.h"
+#include "guesscomponent.h"
+#include "tracking.h"
+#include "ignore.h"
+#include "override.h"
+#include "log.h"
+#include "sourceextraction.h"
+
+/* This file includes the code to include sources, i.e.
+ to create the chunk for the Sources.gz-file and
+ to put it in the various databases.
+
+things to do with .dsc's checkin by hand: (by comparison with apt-ftparchive)
+* Get all from .dsc (search the chunk with
+ the Source:-field. end the chunk artificial
+ before the pgp-end-block.(in case someone
+ missed the newline there))
+
+* check to have source, version, maintainer,
+ standards-version, files. And also look
+ at binary, architecture and build*, as
+ described in policy 5.4
+
+* Get overwrite information, especially
+ the priority(if there is a binaries field,
+ check the one with the highest) and the section
+ (...what else...?)
+
+* Rename Source-Field to Package-Field
+
+* add dsc to files-list. (check other files md5sum and size)
+
+* add Directory-field
+
+* Add Priority and Status
+
+* apply possible maintainer-updates from the overwrite-file
+ or arbitrary tag changes from the extra-overwrite-file
+
+* keep rest (perhaps sort alphabetical)
+
+*/
+
+struct dscpackage {
+ /* things to be set by dsc_read: */
+ struct dsc_headers dsc;
+ /* things that will still be NULL then: */
+ component_t component;
+ /* Things that may be calculated by dsc_calclocations: */
+ struct strlist filekeys;
+};
+
+static void dsc_free(/*@only@*/struct dscpackage *pkg) {
+ if (pkg != NULL) {
+ sources_done(&pkg->dsc);
+ strlist_done(&pkg->filekeys);
+ free(pkg);
+ }
+}
+
+static retvalue dsc_read(/*@out@*/struct dscpackage **pkg, const char *filename) {
+ retvalue r;
+ struct dscpackage *dsc;
+ bool broken;
+
+
+ dsc = zNEW(struct dscpackage);
+ if (FAILEDTOALLOC(dsc))
+ return RET_ERROR_OOM;
+
+ r = sources_readdsc(&dsc->dsc, filename, filename, &broken);
+ if (RET_IS_OK(r) && broken && !IGNORING(brokensignatures,
+"'%s' contains only broken signatures.\n"
+"This most likely means the file was damaged or edited improperly\n",
+ filename))
+ r = RET_ERROR;
+ if (RET_IS_OK(r))
+ r = propersourcename(dsc->dsc.name);
+ if (RET_IS_OK(r))
+ r = properversion(dsc->dsc.version);
+ if (RET_IS_OK(r))
+ r = properfilenames(&dsc->dsc.files.names);
+ if (RET_WAS_ERROR(r)) {
+ dsc_free(dsc);
+ return r;
+ }
+ dsc->component = atom_unknown;
+ *pkg = dsc;
+
+ return RET_OK;
+}
+
+retvalue dsc_addprepared(const struct dsc_headers *dsc, component_t component, const struct strlist *filekeys, struct distribution *distribution, struct trackingdata *trackingdata){
+ retvalue r;
+ struct target *t = distribution_getpart(distribution,
+ component, architecture_source, pt_dsc);
+
+ assert (logger_isprepared(distribution->logger));
+
+ /* finally put it into the source distribution */
+ r = target_initpackagesdb(t, READWRITE);
+ if (!RET_WAS_ERROR(r)) {
+ retvalue r2;
+ if (interrupted())
+ r = RET_ERROR_INTERRUPTED;
+ else
+ r = target_addpackage(t, distribution->logger,
+ dsc->name, dsc->version,
+ dsc->control, filekeys,
+ false, trackingdata,
+ architecture_source,
+ NULL, NULL, NULL);
+ r2 = target_closepackagesdb(t);
+ RET_ENDUPDATE(r, r2);
+ }
+ RET_UPDATE(distribution->status, r);
+ return r;
+}
+
+/* insert the given .dsc into the mirror in <component> in the <distribution>
+ * if component is NULL, guessing it from the section.
+ * If basename, filekey and directory are != NULL, then they are used instead
+ * of being newly calculated.
+ * (And all files are expected to already be in the pool). */
+retvalue dsc_add(component_t forcecomponent, const char *forcesection, const char *forcepriority, struct distribution *distribution, const char *dscfilename, int delete, trackingdb tracks){
+ retvalue r;
+ struct dscpackage *pkg;
+ struct trackingdata trackingdata;
+ char *destdirectory, *origdirectory;
+ const struct overridedata *oinfo;
+ char *control;
+ int i;
+
+ causingfile = dscfilename;
+
+ /* First make sure this distribution has a source section at all,
+ * for which it has to be listed in the "Architectures:"-field ;-) */
+ if (!atomlist_in(&distribution->architectures, architecture_source)) {
+ fprintf(stderr,
+"Cannot put a source package into Distribution '%s' not having 'source' in its 'Architectures:'-field!\n",
+ distribution->codename);
+ /* nota bene: this cannot be forced or ignored, as no target has
+ been created for this. */
+ return RET_ERROR;
+ }
+
+ r = dsc_read(&pkg, dscfilename);
+ if (RET_WAS_ERROR(r)) {
+ return r;
+ }
+
+ oinfo = override_search(distribution->overrides.dsc, pkg->dsc.name);
+ if (forcesection == NULL) {
+ forcesection = override_get(oinfo, SECTION_FIELDNAME);
+ }
+ if (forcepriority == NULL) {
+ forcepriority = override_get(oinfo, PRIORITY_FIELDNAME);
+ }
+
+ if (forcesection != NULL) {
+ free(pkg->dsc.section);
+ pkg->dsc.section = strdup(forcesection);
+ if (FAILEDTOALLOC(pkg->dsc.section)) {
+ dsc_free(pkg);
+ return RET_ERROR_OOM;
+ }
+ }
+ if (forcepriority != NULL) {
+ free(pkg->dsc.priority);
+ pkg->dsc.priority = strdup(forcepriority);
+ if (FAILEDTOALLOC(pkg->dsc.priority)) {
+ dsc_free(pkg);
+ return RET_ERROR_OOM;
+ }
+ }
+
+ r = dirs_getdirectory(dscfilename, &origdirectory);
+ if (RET_WAS_ERROR(r)) {
+ dsc_free(pkg);
+ return r;
+ }
+
+ if (pkg->dsc.section == NULL || pkg->dsc.priority == NULL) {
+ struct sourceextraction *extraction;
+
+ extraction = sourceextraction_init(
+ (pkg->dsc.section == NULL)?&pkg->dsc.section:NULL,
+ (pkg->dsc.priority == NULL)?&pkg->dsc.priority:NULL);
+ if (FAILEDTOALLOC(extraction)) {
+ free(origdirectory);
+ dsc_free(pkg);
+ return RET_ERROR_OOM;
+ }
+ for (i = 0 ; i < pkg->dsc.files.names.count ; i ++)
+ sourceextraction_setpart(extraction, i,
+ pkg->dsc.files.names.values[i]);
+ while (sourceextraction_needs(extraction, &i)) {
+ char *fullfilename = calc_dirconcat(origdirectory,
+ pkg->dsc.files.names.values[i]);
+ if (FAILEDTOALLOC(fullfilename)) {
+ free(origdirectory);
+ dsc_free(pkg);
+ return RET_ERROR_OOM;
+ }
+ /* while it would nice to try at the pool if we
+ * do not have the file here, to know its location
+ * in the pool we need to know the component. And
+ * for the component we might need the section first */
+ // TODO: but if forcecomponent is set it might be possible.
+ r = sourceextraction_analyse(extraction, fullfilename);
+ free(fullfilename);
+ if (RET_WAS_ERROR(r)) {
+ free(origdirectory);
+ dsc_free(pkg);
+ sourceextraction_abort(extraction);
+ return r;
+ }
+ }
+ r = sourceextraction_finish(extraction);
+ if (RET_WAS_ERROR(r)) {
+ free(origdirectory);
+ dsc_free(pkg);
+ return r;
+ }
+ }
+
+ if (pkg->dsc.section == NULL && pkg->dsc.priority == NULL) {
+ fprintf(stderr,
+"No section and no priority for '%s', skipping.\n",
+ pkg->dsc.name);
+ free(origdirectory);
+ dsc_free(pkg);
+ return RET_ERROR;
+ }
+ if (pkg->dsc.section == NULL) {
+ fprintf(stderr, "No section for '%s', skipping.\n",
+ pkg->dsc.name);
+ free(origdirectory);
+ dsc_free(pkg);
+ return RET_ERROR;
+ }
+ if (pkg->dsc.priority == NULL) {
+ fprintf(stderr, "No priority for '%s', skipping.\n",
+ pkg->dsc.name);
+ free(origdirectory);
+ dsc_free(pkg);
+ return RET_ERROR;
+ }
+ if (strcmp(pkg->dsc.section, "unknown") == 0 && verbose >= 0) {
+ fprintf(stderr, "Warning: strange section '%s'!\n",
+ pkg->dsc.section);
+ }
+ if (!atom_defined(forcecomponent)) {
+ const char *fc;
+
+ fc = override_get(oinfo, "$Component");
+ if (fc != NULL) {
+ forcecomponent = component_find(fc);
+ if (!atom_defined(forcecomponent)) {
+ fprintf(stderr,
+"Unparseable component '%s' in $Component override of '%s'\n",
+ fc, pkg->dsc.name);
+ return RET_ERROR;
+ }
+ }
+ }
+
+ /* decide where it has to go */
+
+ r = guess_component(distribution->codename, &distribution->components,
+ pkg->dsc.name, pkg->dsc.section, forcecomponent,
+ &pkg->component);
+ if (RET_WAS_ERROR(r)) {
+ free(origdirectory);
+ dsc_free(pkg);
+ return r;
+ }
+ if (verbose > 0 && !atom_defined(forcecomponent)) {
+ fprintf(stderr, "%s: component guessed as '%s'\n", dscfilename,
+ atoms_components[pkg->component]);
+ }
+
+ { char *dscbasename, *dscfilekey;
+ struct checksums *dscchecksums;
+
+ dscbasename = calc_source_basename(pkg->dsc.name, pkg->dsc.version);
+ destdirectory = calc_sourcedir(pkg->component, pkg->dsc.name);
+ /* Calculate the filekeys: */
+ if (destdirectory != NULL)
+ r = calc_dirconcats(destdirectory,
+ &pkg->dsc.files.names,
+ &pkg->filekeys);
+ if (dscbasename == NULL || destdirectory == NULL || RET_WAS_ERROR(r)) {
+ free(dscbasename);
+ free(destdirectory); free(origdirectory);
+ dsc_free(pkg);
+ return r;
+ }
+ dscfilekey = calc_dirconcat(destdirectory, dscbasename);
+ dscchecksums = NULL;
+ if (FAILEDTOALLOC(dscfilename))
+ r = RET_ERROR_OOM;
+ else
+ /* then look if we already have this, or copy it in */
+ r = files_preinclude(
+ dscfilename, dscfilekey,
+ &dscchecksums);
+
+ if (!RET_WAS_ERROR(r)) {
+ /* Add the dsc-file to basenames, filekeys and md5sums,
+ * so that it will be listed in the Sources.gz */
+
+ r = checksumsarray_include(&pkg->dsc.files,
+ dscbasename, dscchecksums);
+ if (RET_IS_OK(r))
+ r = strlist_include(&pkg->filekeys, dscfilekey);
+ else
+ free(dscfilekey);
+ } else {
+ free(dscfilekey);
+ free(dscbasename);
+ }
+ checksums_free(dscchecksums);
+ }
+
+ assert (pkg->dsc.files.names.count == pkg->filekeys.count);
+ for (i = 1 ; i < pkg->dsc.files.names.count ; i ++) {
+ if (!RET_WAS_ERROR(r)) {
+ r = files_checkincludefile(origdirectory,
+ pkg->dsc.files.names.values[i],
+ pkg->filekeys.values[i],
+ &pkg->dsc.files.checksums[i]);
+ }
+ }
+
+ /* Calculate the chunk to include: */
+
+ if (!RET_WAS_ERROR(r))
+ r = sources_complete(&pkg->dsc, destdirectory, oinfo,
+ pkg->dsc.section, pkg->dsc.priority, &control);
+ free(destdirectory);
+ if (RET_IS_OK(r)) {
+ free(pkg->dsc.control);
+ pkg->dsc.control = control;
+ } else {
+ free(origdirectory);
+ dsc_free(pkg);
+ return r;
+ }
+
+ if (interrupted()) {
+ dsc_free(pkg);
+ free(origdirectory);
+ return RET_ERROR_INTERRUPTED;
+ }
+
+ if (tracks != NULL) {
+ r = trackingdata_summon(tracks, pkg->dsc.name,
+ pkg->dsc.version, &trackingdata);
+ if (RET_WAS_ERROR(r)) {
+ free(origdirectory);
+ dsc_free(pkg);
+ return r;
+ }
+ }
+
+ r = dsc_addprepared(&pkg->dsc, pkg->component,
+ &pkg->filekeys, distribution,
+ (tracks!=NULL)?&trackingdata:NULL);
+
+ /* delete source files, if they are to be */
+ if ((RET_IS_OK(r) && delete >= D_MOVE) ||
+ (r == RET_NOTHING && delete >= D_DELETE)) {
+ char *fullfilename;
+
+ for (i = 0 ; i < pkg->dsc.files.names.count ; i++) {
+ fullfilename = calc_dirconcat(origdirectory,
+ pkg->dsc.files.names.values[i]);
+ if (FAILEDTOALLOC(fullfilename)) {
+ r = RET_ERROR_OOM;
+ break;
+ }
+ if (isregularfile(fullfilename))
+ deletefile(fullfilename);
+ free(fullfilename);
+ }
+ }
+ free(origdirectory);
+ dsc_free(pkg);
+
+ if (tracks != NULL) {
+ retvalue r2;
+ r2 = trackingdata_finish(tracks, &trackingdata);
+ RET_ENDUPDATE(r, r2);
+ }
+ return r;
+}
diff --git a/checkindsc.h b/checkindsc.h
new file mode 100644
index 0000000..cf732ac
--- /dev/null
+++ b/checkindsc.h
@@ -0,0 +1,31 @@
+#ifndef REPREPRO_CHECKINDSC_H
+#define REPREPRO_CHECKINDSC_H
+
+#ifndef REPREPRO_ERROR_H
+#include "error.h"
+#warning "What's hapening here?"
+#endif
+#ifndef REPREPRO_DATABASE_H
+#include "database.h"
+#endif
+#ifndef REPREPRO_DISTRIBUTION_H
+#include "distribution.h"
+#endif
+#ifndef REPREPRO_SOURCES_H
+#include "sources.h"
+#endif
+
+/* insert the given .dsc into the mirror in <component> in the <distribution>
+ * if component is NULL, guess it from the section. */
+retvalue dsc_add(component_t, /*@null@*/const char * /*forcesection*/, /*@null@*/const char * /*forcepriority*/, struct distribution *, const char * /*dscfilename*/, int /*delete*/, /*@null@*/trackingdb);
+
+/* in two steps:
+ * If basename, filekey and directory are != NULL, then they are used instead
+ * of being newly calculated.
+ * (And all files are expected to already be in the pool),
+ * delete should be D_INPLACE then
+ */
+
+retvalue dsc_addprepared(const struct dsc_headers *, component_t, const struct strlist * /*filekeys*/, struct distribution *, /*@null@*/struct trackingdata *);
+
+#endif
diff --git a/checks.c b/checks.c
new file mode 100644
index 0000000..bbba928
--- /dev/null
+++ b/checks.c
@@ -0,0 +1,382 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2003,2004,2005,2006,2007 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include <config.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include "error.h"
+#include "ignore.h"
+#include "strlist.h"
+#include "mprintf.h"
+#include "names.h"
+#include "checks.h"
+
+typedef unsigned char uchar;
+
+/* check if the character starting where <character> points
+ * at is a overlong one */
+static inline bool overlongUTF8(const char *character) {
+ /* This checks for overlong utf-8 characters.
+ * (as they might mask '.' '\0' or '/' chars).
+ * we assume no filesystem/ar/gpg code will parse
+ * invalid utf8, as we would only be able to rule
+ * this out if we knew it is utf8 we are coping
+ * with. (Well, you should not use --ignore=validchars
+ * anyway). */
+ uchar c = *character;
+
+ if ((c & (uchar)0xC2 /*11000010*/) == (uchar)0xC0 /*11000000*/) {
+ uchar nextc = *(character+1);
+
+ if ((nextc & (uchar)0xC0 /*11000000*/)
+ != (uchar)0x80 /*10000000*/)
+ return false;
+
+ if ((c & (uchar)0x3E /* 00111110 */) == (uchar)0)
+ return true;
+ if (c == (uchar)0xE0 /*11100000*/ &&
+ (nextc & (uchar)0x20 /*00100000*/) == (uchar)0)
+ return true;
+ if (c == (uchar)0xF0 /*11110000*/ &&
+ (nextc & (uchar)0x30 /*00110000*/) == (uchar)0)
+ return true;
+ if (c == (uchar)0xF8 /*11111000*/ &&
+ (nextc & (uchar)0x38 /*00111000*/) == (uchar)0)
+ return true;
+ if (c == (uchar)0xFC /*11111100*/ &&
+ (nextc & (uchar)0x3C /*00111100*/) == (uchar)0)
+ return true;
+ }
+ return false;
+}
+
+#define REJECTLOWCHARS(s, str, descr) \
+ if ((uchar)*s < (uchar)' ') { \
+ fprintf(stderr, \
+ "Character 0x%02hhx not allowed within %s '%s'!\n", \
+ *s, descr, str); \
+ return RET_ERROR; \
+ }
+
+#define REJECTCHARIF(c, s, str, descr) \
+ if (c) { \
+ fprintf(stderr, \
+ "Character '%c' not allowed within %s '%s'!\n", \
+ *s, descr, string); \
+ return RET_ERROR; \
+ }
+
+
+/* check if this is something that can be used as directory safely */
+retvalue propersourcename(const char *string) {
+ const char *s;
+ bool firstcharacter = true;
+
+ if (string[0] == '\0') {
+ /* This is not really ignoreable, as this will lead
+ * to paths not normalized, so all checks go wrong */
+ fprintf(stderr, "Source name is not allowed to be empty!\n");
+ return RET_ERROR;
+ }
+ if (string[0] == '.') {
+ /* A dot is not only hard to see, it would cause the directory
+ * to become /./.bla, which is quite dangerous. */
+ fprintf(stderr,
+"Source names are not allowed to start with a dot!\n");
+ return RET_ERROR;
+ }
+ s = string;
+ while (*s != '\0') {
+ if ((*s > 'z' || *s < 'a') &&
+ (*s > '9' || *s < '0') &&
+ (firstcharacter ||
+ (*s != '+' && *s != '-' && *s != '.'))) {
+ REJECTLOWCHARS(s, string, "sourcename");
+ REJECTCHARIF (*s == '/', s, string, "sourcename");
+ if (overlongUTF8(s)) {
+ fprintf(stderr,
+"This could contain an overlong UTF8 sequence, rejecting source name '%s'!\n",
+ string);
+ return RET_ERROR;
+ }
+ if (!IGNORING_(forbiddenchar,
+"Character 0x%02hhx not allowed in sourcename: '%s'!\n", *s, string)) {
+ return RET_ERROR;
+ }
+ if (ISSET(*s, 0x80)) {
+ if (!IGNORING_(8bit,
+"8bit character in source name: '%s'!\n", string)) {
+ return RET_ERROR;
+ }
+ }
+ }
+ s++;
+ firstcharacter = false;
+ }
+ return RET_OK;
+}
+
+/* check if this is something that can be used as directory safely */
+retvalue properfilename(const char *string) {
+ const char *s;
+
+ if (string[0] == '\0') {
+ fprintf(stderr, "Error: empty filename!\n");
+ return RET_ERROR;
+ }
+ if ((string[0] == '.' && string[1] == '\0') ||
+ (string[0] == '.' && string[1] == '.' && string[2] == '\0')) {
+ fprintf(stderr, "File name not allowed: '%s'!\n", string);
+ return RET_ERROR;
+ }
+ for (s = string ; *s != '\0' ; s++) {
+ REJECTLOWCHARS(s, string, "filename");
+ REJECTCHARIF (*s == '/' , s, string, "filename");
+ if (ISSET(*s, 0x80)) {
+ if (overlongUTF8(s)) {
+ fprintf(stderr,
+"This could contain an overlong UTF8 sequence, rejecting file name '%s'!\n",
+ string);
+ return RET_ERROR;
+ }
+ if (!IGNORING_(8bit,
+"8bit character in file name: '%s'!\n", string)) {
+ return RET_ERROR;
+ }
+ }
+ }
+ return RET_OK;
+}
+
+static const char *formaterror(const char *format, ...) {
+ va_list ap;
+ static char *data = NULL;
+
+ if (data != NULL)
+ free(data);
+ va_start(ap, format);
+ data = vmprintf(format, ap);
+ va_end(ap);
+ if (data == NULL)
+ return "Out of memory";
+ return data;
+}
+
+/* check if this is something that can be used as directory *and* identifier safely */
+const char *checkfordirectoryandidentifier(const char *string) {
+ const char *s;
+
+ assert (string != NULL && string[0] != '\0');
+
+ if ((string[0] == '.' && (string[1] == '\0'||string[1]=='/')))
+ return "'.' is not allowed as directory part";
+ if ((string[0] == '.' && string[1] == '.'
+ && (string[2] == '\0'||string[2] =='/')))
+ return "'..' is not allowed as directory part";
+ for (s = string; *s != '\0'; s++) {
+ if (*s == '|')
+ return "'|' is not allowed";
+ if ((uchar)*s < (uchar)' ')
+ return formaterror("Character 0x%02hhx not allowed", *s);
+ if (*s == '/' && s[1] == '.' && (s[2] == '\0' || s[2] == '/'))
+ return "'.' is not allowed as directory part";
+ if (*s == '/' && s[1] == '.' && s[2] == '.'
+ && (s[3] == '\0' || s[3] =='/'))
+ return "'..' is not allowed as directory part";
+ if (*s == '/' && s[1] == '/')
+ return "\"//\" is not allowed";
+ if (ISSET(*s, 0x80)) {
+ if (overlongUTF8(s))
+ return
+"Contains overlong UTF-8 sequence if treated as UTF-8";
+ if (!IGNORABLE(8bit))
+ return
+"Contains 8bit character (use --ignore=8bit to ignore)";
+ }
+ }
+ return NULL;
+}
+
+/* check if this can be used as part of identifier (and as part of a filename) */
+const char *checkforidentifierpart(const char *string) {
+ const char *s;
+
+ assert (string != NULL && string[0] != '\0');
+
+ for (s = string; *s != '\0' ; s++) {
+ if (*s == '|')
+ return "'|' is not allowed";
+ if (*s == '/')
+ return "'/' is not allowed";
+ if ((uchar)*s < (uchar)' ')
+ return formaterror("Character 0x%02hhx not allowed", *s);
+ if (ISSET(*s, 0x80)) {
+ if (overlongUTF8(s))
+ return
+"Contains overlong UTF-8 sequence if treated as UTF-8";
+ if (!IGNORABLE(8bit))
+ return
+"Contains 8bit character (use --ignore=8bit to ignore)";
+ }
+ }
+ return NULL;
+}
+
+retvalue properfilenamepart(const char *string) {
+ const char *s;
+
+ for (s = string ; *s != '\0' ; s++) {
+ REJECTLOWCHARS(s, string, "filenamepart");
+ REJECTCHARIF (*s == '/' , s, string, "filenamepart");
+ if (ISSET(*s, 0x80)) {
+ if (overlongUTF8(s)) {
+ fprintf(stderr,
+"This could contain an overlong UTF8 sequence, rejecting part of file name '%s'!\n",
+ string);
+ return RET_ERROR;
+ }
+ if (!IGNORING_(8bit,
+"8bit character in part of file name: '%s'!\n",
+ string))
+ return RET_ERROR;
+ }
+ }
+ return RET_OK;
+}
+
+retvalue properversion(const char *string) {
+ const char *s = string;
+ bool hadepoch = false;
+ bool first = true;
+ bool yetonlydigits = true;
+
+ if (string[0] == '\0' && !IGNORING(emptyfilenamepart,
+"A version string is empty!\n")) {
+ return RET_ERROR;
+ }
+ if ((*s < '0' || *s > '9') &&
+ ((*s >= 'a' && *s <= 'z') || (*s >='A' && *s <= 'Z'))) {
+ /* As there are official packages violating the rule
+ * of policy 5.6.11 to start with a digit, disabling
+ * this test, and only omitting a warning. */
+ if (verbose >= 0)
+ fprintf(stderr,
+"Warning: Package version '%s' does not start with a digit, violating 'should'-directive in policy 5.6.11\n",
+ string);
+ }
+ for (; *s != '\0' ; s++, first=false) {
+ if ((*s <= '9' && *s >= '0')) {
+ continue;
+ }
+ if (!first && yetonlydigits && *s == ':') {
+ hadepoch = true;
+ continue;
+ }
+ yetonlydigits = false;
+ if ((*s >= 'A' && *s <= 'Z') ||
+ (*s >= 'a' && *s <= 'z')) {
+ yetonlydigits = false;
+ continue;
+ }
+ if (first || (*s != '+' && *s != '-'
+ && *s != '.' && *s != '~'
+ && (!hadepoch || *s != ':'))) {
+ REJECTLOWCHARS(s, string, "version");
+ REJECTCHARIF (*s == '/' , s, string, "version");
+ if (overlongUTF8(s)) {
+ fprintf(stderr,
+"This could contain an overlong UTF8 sequence, rejecting version '%s'!\n",
+ string);
+ return RET_ERROR;
+ }
+ if (!IGNORING_(forbiddenchar,
+"Character '%c' not allowed in version: '%s'!\n", *s, string))
+ return RET_ERROR;
+ if (ISSET(*s, 0x80)) {
+ if (!IGNORING_(8bit,
+"8bit character in version: '%s'!\n", string))
+ return RET_ERROR;
+ }
+ }
+ }
+ return RET_OK;
+}
+
+retvalue properfilenames(const struct strlist *names) {
+ int i;
+
+ for (i = 0 ; i < names->count ; i ++) {
+ retvalue r = properfilename(names->values[i]);
+ assert (r != RET_NOTHING);
+ if (RET_WAS_ERROR(r))
+ return r;
+ }
+ return RET_OK;
+}
+
+retvalue properpackagename(const char *string) {
+ const char *s;
+ bool firstcharacter = true;
+
+ /* To be able to avoid multiple warnings,
+ * this should always be a subset of propersourcename */
+
+ if (string[0] == '\0') {
+ /* This is not really ignoreable, as this is a primary
+ * key for our database */
+ fprintf(stderr, "Package name is not allowed to be empty!\n");
+ return RET_ERROR;
+ }
+ s = string;
+ while (*s != '\0') {
+ /* DAK also allowed upper case letters last I looked, policy
+ * does not, so they are not allowed without --ignore=forbiddenchar */
+ // perhaps some extra ignore-rule for upper case?
+ if ((*s > 'z' || *s < 'a') &&
+ (*s > '9' || *s < '0') &&
+ (firstcharacter
+ || (*s != '+' && *s != '-' && *s != '.'))) {
+ REJECTLOWCHARS(s, string, "package name");
+ REJECTCHARIF (*s == '/' , s, string, "package name");
+ if (overlongUTF8(s)) {
+ fprintf(stderr,
+"This could contain an overlong UTF8 sequence, rejecting package name '%s'!\n",
+ string);
+ return RET_ERROR;
+ }
+ if (!IGNORING(forbiddenchar,
+"Character 0x%02hhx not allowed in package name: '%s'!\n", *s, string)) {
+ return RET_ERROR;
+ }
+ if (ISSET(*s, 0x80)) {
+ if (!IGNORING_(8bit,
+"8bit character in package name: '%s'!\n", string)) {
+ return RET_ERROR;
+ }
+ }
+ }
+ s++;
+ firstcharacter = false;
+ }
+ return RET_OK;
+}
+
diff --git a/checks.h b/checks.h
new file mode 100644
index 0000000..ed5a167
--- /dev/null
+++ b/checks.h
@@ -0,0 +1,16 @@
+#ifndef REPREPRO_CHECKS_H
+#define REPREPRO_CHECKS_H
+
+/* return NULL if no problem, statically allocated string otherwise */
+
+typedef const char *checkfunc(const char *);
+
+const char *checkfordirectoryandidentifier(const char *);
+#define checkforcomponent checkfordirectoryandidentifier
+#define checkforcodename checkfordirectoryandidentifier
+const char *checkforidentifierpart(const char *);
+#define checkforarchitecture checkforidentifierpart
+
+/* not yet used */
+static inline void checkerror_free(UNUSED(const char *dummy)) {};
+#endif
diff --git a/checksums.c b/checksums.c
new file mode 100644
index 0000000..81a65b1
--- /dev/null
+++ b/checksums.c
@@ -0,0 +1,1467 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2006,2007,2008,2009 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define CHECKSUMS_CONTEXT visible
+#include "error.h"
+#include "mprintf.h"
+#include "checksums.h"
+#include "filecntl.h"
+#include "names.h"
+#include "dirs.h"
+#include "configparser.h"
+
+const char * const changes_checksum_names[] = {
+ "Files", "Checksums-Sha1", "Checksums-Sha256"
+};
+const char * const source_checksum_names[] = {
+ "Files", "Checksums-Sha1", "Checksums-Sha256"
+};
+const char * const release_checksum_names[cs_hashCOUNT] = {
+ "MD5Sum", "SHA1", "SHA256"
+};
+
+
+/* The internal representation of a checksum, as written to the databases,
+ * is \(:[1-9a-z]:[^ ]\+ \)*[0-9a-fA-F]\+ [0-9]\+
+ * first some hashes, whose type is determined by a single character
+ * (also yet unknown hashes are supported and should be preserved, but are
+ * not generated)
+ * after that the md5sum and finaly the size in dezimal representation.
+ *
+ * Checksums are parsed and stored in a structure for fast access of their
+ * known parts:
+ */
+#ifdef SPLINT
+typedef size_t hashlen_t;
+#else
+typedef unsigned short hashlen_t;
+#endif
+
+struct checksums {
+ struct { unsigned short ofs;
+ hashlen_t len;
+ } parts[cs_COUNT];
+ char representation[];
+};
+#define checksums_hashpart(c, t) ((c)->representation + (c)->parts[t].ofs)
+#define checksums_totallength(c) ((c)->parts[cs_length].ofs + (c)->parts[cs_length].len)
+
+
+static const char * const hash_name[cs_COUNT] =
+ { "md5", "sha1", "sha256", "size" };
+
+void checksums_free(struct checksums *checksums) {
+ free(checksums);
+}
+
+retvalue checksums_init(/*@out@*/struct checksums **checksums_p, char *hashes[cs_COUNT]) {
+ const char *p, *size;
+ char *d;
+ struct checksums *n;
+ enum checksumtype type;
+ size_t len, hashlens[cs_COUNT];
+
+ /* everything assumes yet that this is available */
+ if (hashes[cs_length] == NULL) {
+ for (type = cs_md5sum ; type < cs_COUNT ; type++)
+ free(hashes[type]);
+ *checksums_p = NULL;
+ return RET_OK;
+ }
+
+ size = hashes[cs_length];
+ while (*size == '0' && size[1] >= '0' && size[1] <= '9')
+ size++;
+
+ if (hashes[cs_md5sum] == NULL)
+ hashlens[cs_md5sum] = 1;
+ else
+ hashlens[cs_md5sum] = strlen(hashes[cs_md5sum]);
+ hashlens[cs_length] = strlen(size);
+ len = hashlens[cs_md5sum] + 1 + hashlens[cs_length];
+
+ p = hashes[cs_md5sum];
+ if (p != NULL) {
+ while ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f')
+ || (*p >= 'A' && *p <= 'F'))
+ p++;
+ if (*p != '\0') {
+ // TODO: find way to give more meaningfull error message
+ fprintf(stderr, "Invalid md5 hash: '%s'\n",
+ hashes[cs_md5sum]);
+ for (type = cs_md5sum ; type < cs_COUNT ; type++)
+ free(hashes[type]);
+ return RET_ERROR;
+ }
+ }
+ p = size;
+ while ((*p >= '0' && *p <= '9'))
+ p++;
+ if (*p != '\0') {
+ // TODO: find way to give more meaningfull error message
+ fprintf(stderr, "Invalid size: '%s'\n", size);
+ for (type = cs_md5sum ; type < cs_COUNT ; type++)
+ free(hashes[type]);
+ return RET_ERROR;
+ }
+
+ for (type = cs_firstEXTENDED ; type < cs_hashCOUNT ; type++) {
+ if (hashes[type] == NULL)
+ continue;
+ p = hashes[type];
+ while ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f')
+ || (*p >= 'A' && *p <= 'F'))
+ p++;
+ if (*p != '\0') {
+ // TODO: find way to give more meaningfull error message
+ fprintf(stderr, "Invalid hash: '%s'\n", hashes[type]);
+ for (type = cs_md5sum ; type < cs_COUNT ; type++)
+ free(hashes[type]);
+ return RET_ERROR;
+ }
+ hashlens[type] = (size_t)(p - hashes[type]);
+ len += strlen(" :x:") + hashlens[type];
+ }
+
+ n = malloc(sizeof(struct checksums) + len + 1);
+ if (FAILEDTOALLOC(n)) {
+ for (type = cs_md5sum ; type < cs_COUNT ; type++)
+ free(hashes[type]);
+ return RET_ERROR_OOM;
+ }
+ setzero(struct checksums, n);
+ d = n->representation;
+
+ for (type = cs_firstEXTENDED ; type < cs_hashCOUNT ; type++) {
+ if (hashes[type] == NULL)
+ continue;
+ *(d++) = ':';
+ *(d++) = '1' + (char)(type - cs_sha1sum);
+ *(d++) = ':';
+ n->parts[type].ofs = d - n->representation;
+ n->parts[type].len = (hashlen_t)hashlens[type];
+ memcpy(d, hashes[type], hashlens[type]);
+ d += hashlens[type];
+ *(d++) = ' ';
+ }
+ if (hashes[cs_md5sum] == NULL) {
+ n->parts[cs_md5sum].ofs = d - n->representation;
+ n->parts[cs_md5sum].len = 0;
+ *(d++) = '-';
+ } else {
+ n->parts[cs_md5sum].ofs = d - n->representation;
+ n->parts[cs_md5sum].len = (hashlen_t)hashlens[cs_md5sum];
+ memcpy(d, hashes[cs_md5sum], hashlens[cs_md5sum]);
+ d += hashlens[cs_md5sum];
+ }
+ *(d++) = ' ';
+ n->parts[cs_length].ofs = d - n->representation;
+ n->parts[cs_length].len = (hashlen_t)hashlens[cs_length];
+ memcpy(d, size, hashlens[cs_length] + 1);
+ d += hashlens[cs_length] + 1;
+ assert ((size_t)(d-n->representation) == len + 1);
+
+ for (type = cs_md5sum ; type < cs_COUNT ; type++)
+ free(hashes[type]);
+ *checksums_p = n;
+ return RET_OK;
+}
+
+retvalue checksums_initialize(struct checksums **checksums_p, const struct hash_data *hashes) {
+ char *d;
+ struct checksums *n;
+ enum checksumtype type;
+ size_t len;
+
+ /* everything assumes that this is available */
+ if (hashes[cs_length].start == NULL) {
+ assert (0 == 1);
+ *checksums_p = NULL;
+ return RET_ERROR;
+ }
+
+ len = hashes[cs_md5sum].len + 1 + hashes[cs_length].len;
+ if (hashes[cs_md5sum].start == NULL) {
+ assert(hashes[cs_md5sum].len == 0);
+ len++;
+ }
+
+ for (type = cs_firstEXTENDED ; type < cs_hashCOUNT ; type++) {
+ if (hashes[type].start == NULL)
+ continue;
+ len += strlen(" :x:") + hashes[type].len;
+ }
+
+ n = malloc(sizeof(struct checksums) + len + 1);
+ if (FAILEDTOALLOC(n))
+ return RET_ERROR_OOM;
+
+ setzero(struct checksums, n);
+ d = n->representation;
+
+ for (type = cs_firstEXTENDED ; type < cs_hashCOUNT ; type++) {
+ if (hashes[type].start == NULL)
+ continue;
+ *(d++) = ':';
+ *(d++) = '1' + (char)(type - cs_firstEXTENDED);
+ *(d++) = ':';
+ n->parts[type].ofs = d - n->representation;
+ n->parts[type].len = (hashlen_t)hashes[type].len;
+ memcpy(d, hashes[type].start, hashes[type].len);
+ d += hashes[type].len;
+ *(d++) = ' ';
+ }
+ if (hashes[cs_md5sum].start == NULL) {
+ n->parts[cs_md5sum].ofs = d - n->representation;
+ n->parts[cs_md5sum].len = 0;
+ *(d++) = '-';
+ } else {
+ n->parts[cs_md5sum].ofs = d - n->representation;
+ n->parts[cs_md5sum].len = (hashlen_t)hashes[cs_md5sum].len;
+ memcpy(d, hashes[cs_md5sum].start, hashes[cs_md5sum].len);
+ d += hashes[cs_md5sum].len;
+ }
+ *(d++) = ' ';
+ n->parts[cs_length].ofs = d - n->representation;
+ n->parts[cs_length].len = (hashlen_t)hashes[cs_length].len;
+ memcpy(d, hashes[cs_length].start, hashes[cs_length].len);
+ d += hashes[cs_length].len;
+ *(d++) = '\0';
+ assert ((size_t)(d-n->representation) == len + 1);
+ *checksums_p = n;
+ return RET_OK;
+}
+
+retvalue checksums_setall(/*@out@*/struct checksums **checksums_p, const char *combinedchecksum, UNUSED(size_t len)) {
+ // This comes from our database, so it surely well formed
+ // (as alreadyassumed above), so this should be possible to
+ // do faster than that...
+ return checksums_parse(checksums_p, combinedchecksum);
+}
+
+retvalue checksums_parse(struct checksums **checksums_p, const char *combinedchecksum) {
+ struct checksums *n;
+ size_t len = strlen(combinedchecksum);
+ const char *p = combinedchecksum;
+ /*@dependent@*/char *d;
+ char type;
+ /*@dependent@*/const char *start;
+
+ n = malloc(sizeof(struct checksums) + len + 1);
+ if (FAILEDTOALLOC(n))
+ return RET_ERROR_OOM;
+ setzero(struct checksums, n);
+ d = n->representation;
+ while (*p == ':') {
+
+ p++;
+ if (p[0] == '\0' || p[1] != ':') {
+ // TODO: how to get some context in this?
+ fprintf(stderr,
+"Malformed checksums representation: '%s'!\n",
+ combinedchecksum);
+ free(n);
+ return RET_ERROR;
+ }
+ type = p[0];
+ p += 2;
+ *(d++) = ':';
+ *(d++) = type;
+ *(d++) = ':';
+ if (type == '1') {
+ start = d;
+ n->parts[cs_sha1sum].ofs = d - n->representation;
+ while (*p != ' ' && *p != '\0')
+ *(d++) = *(p++);
+ n->parts[cs_sha1sum].len = (hashlen_t)(d - start);
+ } else if (type == '2') {
+ start = d;
+ n->parts[cs_sha256sum].ofs = d - n->representation;
+ while (*p != ' ' && *p != '\0')
+ *(d++) = *(p++);
+ n->parts[cs_sha256sum].len = (hashlen_t)(d - start);
+ } else {
+ while (*p != ' ' && *p != '\0')
+ *(d++) = *(p++);
+ }
+
+ *(d++) = ' ';
+ while (*p == ' ')
+ p++;
+ }
+ n->parts[cs_md5sum].ofs = d - n->representation;
+ start = d;
+ if (*p == '-' && p[1] == ' ') {
+ p++;
+ *(d++) = '-';
+ start = d;
+ } else while (*p != ' ' && *p != '\0') {
+ if ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f')) {
+ *(d++) = *(p++);
+ } else if (*p >= 'A' && *p <= 'F') {
+ *(d++) = *(p++) + ('a' - 'A');
+ } else {
+ // TODO: how to get some context in this?
+ fprintf(stderr,
+"Malformed checksums representation (invalid md5sum): '%s'!\n",
+ combinedchecksum);
+ free(n);
+ return RET_ERROR;
+ }
+ }
+ n->parts[cs_md5sum].len = (hashlen_t)(d - start);
+ *(d++) = ' ';
+ while (*p == ' ')
+ p++;
+ n->parts[cs_length].ofs = d - n->representation;
+ while (*p == '0' && (p[1] >= '0' && p[1] <= '9'))
+ p++;
+ start = d;
+ while (*p != '\0') {
+ if (*p >= '0' && *p <= '9') {
+ *(d++) = *(p++);
+ } else {
+ // TODO: how to get some context in this?
+ fprintf(stderr,
+"Malformed checksums representation (invalid size): '%s'!\n",
+ combinedchecksum);
+ free(n);
+ return RET_ERROR;
+ }
+ }
+ n->parts[cs_length].len = (hashlen_t)(d - start);
+ if (d == start) {
+ // TODO: how to get some context in this?
+ fprintf(stderr,
+"Malformed checksums representation (no size): '%s'!\n",
+ combinedchecksum);
+ free(n);
+ return RET_ERROR;
+ }
+ *d = '\0';
+ assert ((size_t)(d - n->representation) <= len);
+ *checksums_p = n;
+ return RET_OK;
+}
+
+struct checksums *checksums_dup(const struct checksums *checksums) {
+ struct checksums *n;
+ size_t len;
+
+ assert (checksums != NULL);
+ len = checksums_totallength(checksums);
+ assert (checksums->representation[len] == '\0');
+
+ n = malloc(sizeof(struct checksums) + len + 1);
+ if (FAILEDTOALLOC(n))
+ return NULL;
+ memcpy(n, checksums, sizeof(struct checksums) + len + 1);
+ assert (n->representation[len] == '\0');
+ return n;
+}
+
+bool checksums_getpart(const struct checksums *checksums, enum checksumtype type, const char **sum_p, size_t *size_p) {
+
+ assert (type < cs_COUNT);
+
+ if (checksums->parts[type].len == 0)
+ return false;
+ *size_p = checksums->parts[type].len;
+ *sum_p = checksums_hashpart(checksums, type);
+ return true;
+}
+
+bool checksums_gethashpart(const struct checksums *checksums, enum checksumtype type, const char **hash_p, size_t *hashlen_p, const char **size_p, size_t *sizelen_p) {
+ assert (type < cs_hashCOUNT);
+ if (checksums->parts[type].len == 0)
+ return false;
+ *hashlen_p = checksums->parts[type].len;
+ *hash_p = checksums_hashpart(checksums, type);
+ *sizelen_p = checksums->parts[cs_length].len;
+ *size_p = checksums_hashpart(checksums, cs_length);
+ return true;
+}
+
+retvalue checksums_getcombined(const struct checksums *checksums, /*@out@*/const char **data_p, /*@out@*/size_t *datalen_p) {
+ size_t len;
+
+ assert (checksums != NULL);
+ len = checksums->parts[cs_length].ofs + checksums->parts[cs_length].len;
+ assert (checksums->representation[len] == '\0');
+
+ *data_p = checksums->representation;
+ *datalen_p = len;
+ return RET_OK;
+}
+
+off_t checksums_getfilesize(const struct checksums *checksums) {
+ const char *p = checksums_hashpart(checksums, cs_length);
+ off_t filesize;
+
+ filesize = 0;
+ while (*p <= '9' && *p >= '0') {
+ filesize = filesize*10 + (size_t)(*p-'0');
+ p++;
+ }
+ assert (*p == '\0');
+ return filesize;
+}
+
+bool checksums_matches(const struct checksums *checksums, enum checksumtype type, const char *sum) {
+ size_t len = (size_t)checksums->parts[type].len;
+
+ assert (type < cs_hashCOUNT);
+
+ if (len == 0)
+ return true;
+
+ if (strncmp(sum, checksums_hashpart(checksums, type), len) != 0)
+ return false;
+ if (sum[len] != ' ')
+ return false;
+ /* assuming count is the last part: */
+ if (strncmp(sum + len + 1, checksums_hashpart(checksums, cs_length),
+ checksums->parts[cs_length].len + 1) != 0)
+ return false;
+ return true;
+}
+
+static inline bool differ(const struct checksums *a, const struct checksums *b, enum checksumtype type) {
+ if (a->parts[type].len == 0 || b->parts[type].len == 0)
+ return false;
+ if (a->parts[type].len != b->parts[type].len)
+ return true;
+ return memcmp(checksums_hashpart(a, type),
+ checksums_hashpart(b, type),
+ a->parts[type].len) != 0;
+}
+
+bool checksums_check(const struct checksums *checksums, const struct checksums *realchecksums, bool *improves) {
+ enum checksumtype type;
+ bool additional = false;
+
+ for (type = cs_md5sum ; type < cs_COUNT ; type++) {
+ if (differ(checksums, realchecksums, type))
+ return false;
+ if (checksums->parts[type].len == 0 &&
+ realchecksums->parts[type].len != 0)
+ additional = true;
+ }
+ if (improves != NULL)
+ *improves = additional;
+ return true;
+}
+
+void checksums_printdifferences(FILE *f, const struct checksums *expected, const struct checksums *got) {
+ enum checksumtype type;
+
+ for (type = cs_md5sum ; type < cs_COUNT ; type++) {
+ if (differ(expected, got, type)) {
+ fprintf(f, "%s expected: %.*s, got: %.*s\n",
+ hash_name[type],
+ (int)expected->parts[type].len,
+ checksums_hashpart(expected, type),
+ (int)got->parts[type].len,
+ checksums_hashpart(got, type));
+ }
+ }
+}
+
+retvalue checksums_combine(struct checksums **checksums_p, const struct checksums *by, bool *improvedhashes) /*@requires only *checksums_p @*/ /*@ensures only *checksums_p @*/ {
+ struct checksums *old = *checksums_p, *n;
+ size_t len = checksums_totallength(old) + checksums_totallength(by);
+ const char *o, *b, *start;
+ char /*@dependent@*/ *d;
+ char typeid;
+
+ n = malloc(sizeof(struct checksums)+ len + 1);
+ if (FAILEDTOALLOC(n))
+ return RET_ERROR_OOM;
+ setzero(struct checksums, n);
+ o = old->representation;
+ b = by->representation;
+ d = n->representation;
+ while (*o == ':' || *b == ':') {
+ if (b[0] != ':' || (o[0] == ':' && o[1] <= b[1])) {
+ *(d++) = *(o++);
+ typeid = *o;
+ *(d++) = *(o++);
+ *(d++) = *(o++);
+ if (typeid == '1') {
+ start = d;
+ n->parts[cs_sha1sum].ofs = d - n->representation;
+ while (*o != ' ' && *o != '\0')
+ *(d++) = *(o++);
+ n->parts[cs_sha1sum].len = (hashlen_t)(d - start);
+ } else if (typeid == '2') {
+ start = d;
+ n->parts[cs_sha256sum].ofs = d - n->representation;
+ while (*o != ' ' && *o != '\0')
+ *(d++) = *(o++);
+ n->parts[cs_sha256sum].len = (hashlen_t)(d - start);
+ } else
+ while (*o != ' ' && *o != '\0')
+ *(d++) = *(o++);
+ assert (*o == ' ');
+ if (*o == ' ')
+ *(d++) = *(o++);
+
+ if (b[0] == ':' && typeid == b[1]) {
+ while (*b != ' ' && *b != '\0')
+ b++;
+ assert (*b == ' ');
+ if (*b == ' ')
+ b++;
+ }
+ } else {
+ *(d++) = *(b++);
+ typeid = *b;
+ *(d++) = *(b++);
+ *(d++) = *(b++);
+ if (typeid == '1') {
+ if (improvedhashes != NULL)
+ improvedhashes[cs_sha1sum] = true;
+ start = d;
+ n->parts[cs_sha1sum].ofs = d - n->representation;
+ while (*b != ' ' && *b != '\0')
+ *(d++) = *(b++);
+ n->parts[cs_sha1sum].len = (hashlen_t)(d - start);
+ } else if (typeid == '2') {
+ if (improvedhashes != NULL)
+ improvedhashes[cs_sha256sum] = true;
+ start = d;
+ n->parts[cs_sha256sum].ofs = d - n->representation;
+ while (*b != ' ' && *b != '\0')
+ *(d++) = *(b++);
+ n->parts[cs_sha256sum].len = (hashlen_t)(d - start);
+ } else
+ while (*b != ' ' && *b != '\0')
+ *(d++) = *(b++);
+ assert (*b == ' ');
+ if (*b == ' ')
+ *(d++) = *(b++);
+ }
+ }
+ /* now take md5sum from original code, unless only the new one has it */
+ n->parts[cs_md5sum].ofs = d - n->representation;
+ start = d;
+ if (*o == '-' && *b != '-')
+ o = b;
+ while (*o != ' ' && *o != '\0')
+ *(d++) = *(o++);
+ n->parts[cs_md5sum].len = (hashlen_t)(d - start);
+ assert (*o == ' ');
+ if (*o == ' ')
+ *(d++) = *(o++);
+ /* and now the size */
+ n->parts[cs_length].ofs = d - n->representation;
+ start = d;
+ while (*o != '\0')
+ *(d++) = *(o++);
+ n->parts[cs_length].len = (hashlen_t)(d - start);
+ assert ((size_t)(d - n->representation) <= len);
+ *(d++) = '\0';
+ *checksums_p = realloc(n, sizeof(struct checksums)
+ + (d-n->representation));
+ if (*checksums_p == NULL)
+ *checksums_p = n;
+ checksums_free(old);
+ return RET_OK;
+}
+
+void checksumsarray_done(struct checksumsarray *array) {
+ if (array->names.count > 0) {
+ int i;
+ assert (array->checksums != NULL);
+ for (i = 0 ; i < array->names.count ; i++) {
+ checksums_free(array->checksums[i]);
+ }
+ } else
+ assert (array->checksums == NULL);
+ strlist_done(&array->names);
+ free(array->checksums);
+}
+
+retvalue hashline_parse(const char *filenametoshow, const char *line, enum checksumtype cs, const char **basename_p, struct hash_data *data_p, struct hash_data *size_p) {
+ const char *p = line;
+ const char *hash_start, *size_start, *filename;
+ size_t hash_len, size_len;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+ hash_start = p;
+ while ((*p >= '0' && *p <= '9') ||
+ (*p >= 'a' && *p <= 'f'))
+ p++;
+ hash_len = p - hash_start;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ while (*p == '0' && p[1] >= '0' && p[1] <= '9')
+ p++;
+ size_start = p;
+ while ((*p >= '0' && *p <= '9'))
+ p++;
+ size_len = p - size_start;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ filename = p;
+ while (*p != '\0' && *p != ' ' && *p != '\t'
+ && *p != '\r' && *p != '\n')
+ p++;
+ if (unlikely(size_len == 0 || hash_len == 0
+ || filename == p || *p != '\0')) {
+ fprintf(stderr,
+"Error parsing %s checksum line ' %s' within '%s'\n",
+ hash_name[cs], line,
+ filenametoshow);
+ return RET_ERROR;
+ }
+ *basename_p = filename;
+ data_p->start = hash_start;
+ data_p->len = hash_len;
+ size_p->start = size_start;
+ size_p->len = size_len;
+ return RET_OK;
+}
+
+retvalue checksumsarray_parse(struct checksumsarray *out, const struct strlist l[cs_hashCOUNT], const char *filenametoshow) {
+ retvalue r;
+ int i;
+ struct checksumsarray a;
+ struct strlist filenames;
+ size_t count;
+ bool foundhashtype[cs_hashCOUNT];
+ struct hashes *parsed;
+ enum checksumtype cs;
+
+ memset(foundhashtype, 0, sizeof(foundhashtype));
+
+ /* avoid realloc by allocing the absolute maximum only
+ * if every checksum field contains different files */
+ count = 0;
+ for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) {
+ count += l[cs].count;
+ }
+
+ parsed = nzNEW(count, struct hashes);
+ if (FAILEDTOALLOC(parsed))
+ return RET_ERROR_OOM;
+ strlist_init_n(count + 1, &filenames);
+ for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) {
+ for (i = 0 ; i < l[cs].count ; i++) {
+ const char *line = l[cs].values[i];
+ const char *p = line,
+ *hash_start, *size_start, *filename;
+ size_t hash_len, size_len;
+ int fileofs;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+ hash_start = p;
+ while ((*p >= '0' && *p <= '9') ||
+ (*p >= 'a' && *p <= 'f'))
+ p++;
+ hash_len = p - hash_start;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ while (*p == '0' && p[1] >= '0' && p[1] <= '9')
+ p++;
+ size_start = p;
+ while ((*p >= '0' && *p <= '9'))
+ p++;
+ size_len = p - size_start;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ filename = p;
+ while (*p != '\0' && *p != ' ' && *p != '\t'
+ && *p != '\r' && *p != '\n')
+ p++;
+ if (unlikely(size_len == 0 || hash_len == 0
+ || filename == p || *p != '\0')) {
+ fprintf(stderr,
+"Error parsing %s checksum line ' %s' within '%s'\n",
+ hash_name[cs], line,
+ filenametoshow);
+ strlist_done(&filenames);
+ free(parsed);
+ return RET_ERROR;
+ } else {
+ struct hash_data *hashes;
+
+ fileofs = strlist_ofs(&filenames, filename);
+ if (fileofs == -1) {
+ fileofs = filenames.count;
+ r = strlist_add_dup(&filenames, filename);
+ if (RET_WAS_ERROR(r)) {
+ strlist_done(&filenames);
+ free(parsed);
+ return r;
+ }
+ hashes = parsed[fileofs].hashes;
+ hashes[cs_length].start = size_start;
+ hashes[cs_length].len = size_len;
+ } else {
+ hashes = parsed[fileofs].hashes;
+ if (unlikely(hashes[cs_length].len
+ != size_len
+ || memcmp(hashes[cs_length].start,
+ size_start, size_len) != 0)) {
+ fprintf(stderr,
+"WARNING: %s checksum line ' %s' in '%s' contradicts previous filesize!\n",
+ hash_name[cs], line,
+ filenametoshow);
+ continue;
+ }
+ }
+ hashes[cs].start = hash_start;
+ hashes[cs].len = hash_len;
+ foundhashtype[cs] = true;
+ }
+ }
+ }
+ assert (count >= (size_t)filenames.count);
+
+ if (filenames.count == 0) {
+ strlist_done(&filenames);
+ strlist_init(&out->names);
+ out->checksums = NULL;
+ free(parsed);
+ return RET_OK;
+ }
+#if 0
+// TODO: re-enable this once apt-utils is fixed for a long enough time...
+ for (i = 0 ; i < filenames.count ; i++) {
+ for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) {
+ if (!foundhashtype[cs])
+ continue;
+ if (parsed[i].hashes[cs].start == NULL) {
+ fprintf(stderr,
+"WARNING: Inconsistent hashes in %s: '%s' missing %s!\n",
+ filenametoshow,
+ filenames.values[i],
+ hash_name[cs]);
+ r = RET_ERROR;
+ /* show one per file, but list all problematic files */
+ break;
+ }
+ }
+ }
+#endif
+ a.checksums = nzNEW(filenames.count+1, struct checksums *);
+ if (FAILEDTOALLOC(a.checksums)) {
+ strlist_done(&filenames);
+ free(parsed);
+ return RET_ERROR_OOM;
+ }
+ strlist_move(&a.names, &filenames);
+
+ for (i = 0 ; i < a.names.count ; i++) {
+ r = checksums_initialize(a.checksums + i, parsed[i].hashes);
+ if (RET_WAS_ERROR(r)) {
+ free(parsed);
+ checksumsarray_done(&a);
+ return r;
+ }
+ }
+ checksumsarray_move(out, &a);
+ free(parsed);
+ return RET_OK;
+}
+
+retvalue checksumsarray_genfilelist(const struct checksumsarray *a, char **md5_p, char **sha1_p, char **sha256_p) {
+ size_t lens[cs_hashCOUNT];
+ bool missing[cs_hashCOUNT];
+ char *filelines[cs_hashCOUNT];
+ int i;
+ enum checksumtype cs;
+ size_t filenamelen[a->names.count];
+
+ memset(missing, 0, sizeof(missing));
+ memset(lens, 0, sizeof(lens));
+
+ for (i=0 ; i < a->names.count ; i++) {
+ const struct checksums *checksums = a->checksums[i];
+ size_t len;
+
+ filenamelen[i] = strlen(a->names.values[i]);
+
+ len = 4 + filenamelen[i] + checksums->parts[cs_length].len;
+ assert (checksums != NULL);
+ if (checksums->parts[cs_md5sum].len == 0)
+ lens[cs_md5sum] += len + 1;
+ else
+ lens[cs_md5sum] += len + checksums->parts[cs_md5sum].len;
+ for (cs = cs_md5sum+1 ; cs < cs_hashCOUNT ; cs++) {
+ if (checksums->parts[cs].len == 0)
+ missing[cs] = true;
+ lens[cs] += len + checksums->parts[cs].len;
+ }
+ }
+ for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) {
+ if (missing[cs])
+ filelines[cs] = NULL;
+ else {
+ filelines[cs] = malloc(lens[cs] + 1);
+ if (FAILEDTOALLOC(filelines[cs])) {
+ while (cs-- > cs_md5sum)
+ free(filelines[cs]);
+ return RET_ERROR_OOM;
+ }
+ }
+ }
+ for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) {
+ char *p;
+
+ if (missing[cs])
+ continue;
+
+ p = filelines[cs];
+ *(p++) = '\n';
+ for (i=0 ; i < a->names.count ; i++) {
+ const struct checksums *c = a->checksums[i];
+
+ *(p++) = ' ';
+ if (c->parts[cs].len == 0) {
+ *(p++) = '-';
+ } else {
+ memcpy(p, checksums_hashpart(c, cs),
+ c->parts[cs].len);
+ p += c->parts[cs].len;
+ }
+ *(p++) = ' ';
+ memcpy(p, checksums_hashpart(c, cs_length),
+ c->parts[cs_length].len);
+ p += c->parts[cs_length].len;
+ *(p++) = ' ';
+ memcpy(p, a->names.values[i], filenamelen[i]);
+ p += filenamelen[i];
+ *(p++) = '\n';
+ }
+ *(--p) = '\0';
+ assert ((size_t)(p - filelines[cs]) == lens[cs]);
+ }
+ *md5_p = filelines[cs_md5sum];
+ *sha1_p = filelines[cs_sha1sum];
+ *sha256_p = filelines[cs_sha256sum];
+ return RET_OK;
+}
+
+void checksumsarray_move(/*@out@*/struct checksumsarray *destination, struct checksumsarray *origin) {
+ strlist_move(&destination->names, &origin->names);
+ destination->checksums = origin->checksums;
+ origin->checksums = NULL;
+}
+
+void checksumsarray_resetunsupported(const struct checksumsarray *a, bool *types) {
+ int i;
+ enum checksumtype cs;
+
+ for (i = 0 ; i < a->names.count ; i++) {
+ struct checksums *c = a->checksums[i];
+ for (cs = cs_md5sum ; cs < cs_hashCOUNT ; cs++) {
+ if (c->parts[cs].len == 0)
+ types[cs] = false;
+ }
+ }
+}
+
+retvalue checksumsarray_include(struct checksumsarray *a, /*@only@*/char *name, const struct checksums *checksums) {
+ retvalue r;
+ struct checksums **n;
+ int count = a->names.count;
+
+ n = nNEW(count + 1, struct checksums *);
+ if (FAILEDTOALLOC(n)) {
+ free(name);
+ return RET_ERROR_OOM;
+ }
+ n[0] = checksums_dup(checksums);
+ if (FAILEDTOALLOC(n[0])) {
+ free(name);
+ free(n);
+ return RET_ERROR_OOM;
+ }
+ r = strlist_include(&a->names, name);
+ if (!RET_IS_OK(r)) {
+ checksums_free(n[0]);
+ free(n);
+ return r;
+ }
+ assert (a->names.count == count + 1);
+ if (count > 0) {
+ assert (a->checksums != NULL);
+ memcpy(&n[1], a->checksums, count*sizeof(struct checksums*));
+ }
+ free(a->checksums);
+ a->checksums = n;
+ return RET_OK;
+}
+
+/* check if the file has the given md5sum (only cheap tests like size),
+ * RET_NOTHING means file does not exist, RET_ERROR_WRONG_MD5 means wrong size */
+retvalue checksums_cheaptest(const char *fullfilename, const struct checksums *checksums, bool complain) {
+ off_t expectedsize;
+ int i;
+ struct stat s;
+
+ i = stat(fullfilename, &s);
+ if (i < 0) {
+ i = errno;
+ if (i == EACCES || i == ENOENT)
+ return RET_NOTHING;
+ else {
+ fprintf(stderr, "Error %d stating '%s': %s!\n",
+ i, fullfilename, strerror(i));
+ return RET_ERRNO(i);
+ }
+ }
+
+ expectedsize = checksums_getfilesize(checksums);
+
+ if (s.st_size == expectedsize)
+ return RET_OK;
+ if (complain)
+ fprintf(stderr,
+ "WRONG SIZE of '%s': expected %lld found %lld\n",
+ fullfilename,
+ (long long)expectedsize,
+ (long long)s.st_size);
+ return RET_ERROR_WRONG_MD5;
+}
+
+retvalue checksums_test(const char *filename, const struct checksums *checksums, struct checksums **checksums_p) {
+ retvalue r;
+ struct checksums *filechecksums;
+ bool improves;
+
+ /* check if it is there and has the correct size */
+ r = checksums_cheaptest(filename, checksums, false);
+ /* if it is, read its checksums */
+ if (RET_IS_OK(r))
+ r = checksums_read(filename, &filechecksums);
+ if (!RET_IS_OK(r))
+ return r;
+ if (!checksums_check(checksums, filechecksums, &improves)) {
+ checksums_free(filechecksums);
+ return RET_ERROR_WRONG_MD5;
+ }
+ if (improves && checksums_p != NULL) {
+ if (*checksums_p == NULL) {
+ *checksums_p = checksums_dup(checksums);
+ if (FAILEDTOALLOC(*checksums_p)) {
+ checksums_free(filechecksums);
+ return RET_ERROR_OOM;
+ }
+ }
+ r = checksums_combine(checksums_p, filechecksums, NULL);
+ if (RET_WAS_ERROR(r)) {
+ checksums_free(filechecksums);
+ return r;
+ }
+ }
+ checksums_free(filechecksums);
+ return RET_OK;
+}
+
+/* copy, only checking file size, perhaps add some paranoia checks later */
+static retvalue copy(const char *destination, const char *source, const struct checksums *checksums) {
+ off_t filesize = 0, expected;
+ static const size_t bufsize = 16384;
+ char *buffer = malloc(bufsize);
+ ssize_t sizeread, towrite, written;
+ const char *start;
+ int e, i;
+ int infd, outfd;
+
+ if (FAILEDTOALLOC(buffer))
+ return RET_ERROR_OOM;
+
+ infd = open(source, O_RDONLY);
+ if (infd < 0) {
+ e = errno;
+ fprintf(stderr, "Error %d opening '%s': %s\n",
+ e, source, strerror(e));
+ free(buffer);
+ return RET_ERRNO(e);
+ }
+ outfd = open(destination, O_NOCTTY|O_WRONLY|O_CREAT|O_EXCL, 0666);
+ if (outfd < 0) {
+ e = errno;
+ fprintf(stderr, "Error %d creating '%s': %s\n",
+ e, destination, strerror(e));
+ (void)close(infd);
+ free(buffer);
+ return RET_ERRNO(e);
+ }
+ filesize = 0;
+ do {
+ sizeread = read(infd, buffer, bufsize);
+ if (sizeread < 0) {
+ e = errno;
+ fprintf(stderr, "Error %d while reading %s: %s\n",
+ e, source, strerror(e));
+ free(buffer);
+ (void)close(infd); (void)close(outfd);
+ deletefile(destination);
+ return RET_ERRNO(e);;
+ }
+ filesize += sizeread;
+ towrite = sizeread;
+ start = buffer;
+ while (towrite > 0) {
+ written = write(outfd, start, (size_t)towrite);
+ if (written < 0) {
+ e = errno;
+ fprintf(stderr,
+"Error %d while writing to %s: %s\n",
+ e, destination, strerror(e));
+ free(buffer);
+ (void)close(infd); (void)close(outfd);
+ deletefile(destination);
+ return RET_ERRNO(e);;
+ }
+ towrite -= written;
+ start += written;
+ }
+ } while (sizeread > 0);
+ free(buffer);
+ i = close(infd);
+ if (i != 0) {
+ e = errno;
+ fprintf(stderr, "Error %d reading %s: %s\n",
+ e, source, strerror(e));
+ (void)close(outfd);
+ deletefile(destination);
+ return RET_ERRNO(e);;
+ }
+ i = close(outfd);
+ if (i != 0) {
+ e = errno;
+ fprintf(stderr, "Error %d writing to %s: %s\n",
+ e, destination, strerror(e));
+ deletefile(destination);
+ return RET_ERRNO(e);;
+ }
+ expected = checksums_getfilesize(checksums);
+ if (filesize != expected) {
+ fprintf(stderr,
+"Error copying %s to %s:\n"
+" File seems to be of size %llu, while %llu was expected!\n",
+ source, destination,
+ (unsigned long long)filesize,
+ (unsigned long long)expected);
+ deletefile(destination);
+ return RET_ERROR_WRONG_MD5;
+ }
+ return RET_OK;
+}
+
+retvalue checksums_hardlink(const char *directory, const char *filekey, const char *sourcefilename, const struct checksums *checksums) {
+ retvalue r;
+ int i, e;
+ char *fullfilename = calc_dirconcat(directory, filekey);
+ if (FAILEDTOALLOC(fullfilename))
+ return RET_ERROR_OOM;
+
+ i = link(sourcefilename, fullfilename);
+ e = errno;
+ if (i != 0 && e == EEXIST) {
+ (void)unlink(fullfilename);
+ errno = 0;
+ i = link(sourcefilename, fullfilename);
+ e = errno;
+ }
+ if (i != 0 && (e == EACCES || e == ENOENT || e == ENOTDIR)) {
+ errno = 0;
+ (void)dirs_make_parent(fullfilename);
+ i = link(sourcefilename, fullfilename);
+ e = errno;
+ }
+ if (i != 0) {
+ if (e == EXDEV || e == EPERM || e == EMLINK) {
+ r = copy(fullfilename, sourcefilename, checksums);
+ if (RET_WAS_ERROR(r)) {
+ free(fullfilename);
+ return r;
+ }
+ } else {
+ fprintf(stderr,
+"Error %d creating hardlink of '%s' as '%s': %s\n",
+ e, sourcefilename, fullfilename, strerror(e));
+ free(fullfilename);
+ return RET_ERRNO(e);
+ }
+ }
+ free(fullfilename);
+ return RET_OK;
+}
+
+void checksumscontext_init(struct checksumscontext *context) {
+ MD5Init(&context->md5);
+ SHA1Init(&context->sha1);
+ SHA256Init(&context->sha256);
+}
+
+void checksumscontext_update(struct checksumscontext *context, const unsigned char *data, size_t len) {
+ MD5Update(&context->md5, data, len);
+// TODO: sha1 and sha256 share quite some stuff,
+// the code can most likely be combined with quite some synergies..
+ SHA1Update(&context->sha1, data, len);
+ SHA256Update(&context->sha256, data, len);
+}
+
+static const char tab[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+retvalue checksums_from_context(struct checksums **out, struct checksumscontext *context) {
+ unsigned char md5buffer[MD5_DIGEST_SIZE], sha1buffer[SHA1_DIGEST_SIZE],
+ sha256buffer[SHA256_DIGEST_SIZE];
+ char *d;
+ unsigned int i;
+ struct checksums *n;
+
+ n = malloc(sizeof(struct checksums) + 2*MD5_DIGEST_SIZE
+ + 2*SHA1_DIGEST_SIZE + 2*SHA256_DIGEST_SIZE + 30);
+ if (FAILEDTOALLOC(n))
+ return RET_ERROR_OOM;
+ setzero(struct checksums, n);
+ d = n->representation;
+ *(d++) = ':';
+ *(d++) = '1';
+ *(d++) = ':';
+ n->parts[cs_sha1sum].ofs = 3;
+ n->parts[cs_sha1sum].len = 2*SHA1_DIGEST_SIZE;
+ SHA1Final(&context->sha1, sha1buffer);
+ for (i = 0 ; i < SHA1_DIGEST_SIZE ; i++) {
+ *(d++) = tab[sha1buffer[i] >> 4];
+ *(d++) = tab[sha1buffer[i] & 0xF];
+ }
+ *(d++) = ' ';
+
+ *(d++) = ':';
+ *(d++) = '2';
+ *(d++) = ':';
+ n->parts[cs_sha256sum].ofs = d - n->representation;
+ n->parts[cs_sha256sum].len = 2*SHA256_DIGEST_SIZE;
+ SHA256Final(&context->sha256, sha256buffer);
+ for (i = 0 ; i < SHA256_DIGEST_SIZE ; i++) {
+ *(d++) = tab[sha256buffer[i] >> 4];
+ *(d++) = tab[sha256buffer[i] & 0xF];
+ }
+ *(d++) = ' ';
+
+ n->parts[cs_md5sum].ofs = d - n->representation;
+ assert (d - n->representation == n->parts[cs_md5sum].ofs);
+ n->parts[cs_md5sum].len = 2*MD5_DIGEST_SIZE;
+ MD5Final(md5buffer, &context->md5);
+ for (i=0 ; i < MD5_DIGEST_SIZE ; i++) {
+ *(d++) = tab[md5buffer[i] >> 4];
+ *(d++) = tab[md5buffer[i] & 0xF];
+ }
+ *(d++) = ' ';
+ n->parts[cs_length].ofs = d - n->representation;
+ assert (d - n->representation == n->parts[cs_length].ofs);
+ n->parts[cs_length].len = (hashlen_t)snprintf(d,
+ 2*MD5_DIGEST_SIZE + 2*SHA1_DIGEST_SIZE
+ + 2*SHA256_DIGEST_SIZE + 30
+ - (d - n->representation), "%lld",
+ (long long)context->sha1.count);
+ assert (strlen(d) == n->parts[cs_length].len);
+ *out = n;
+ return RET_OK;
+}
+
+bool checksums_iscomplete(const struct checksums *checksums) {
+ return checksums->parts[cs_md5sum].len != 0 &&
+ checksums->parts[cs_sha1sum].len != 0 &&
+ checksums->parts[cs_sha256sum].len != 0;
+}
+
+/* Collect missing checksums.
+ * if the file is not there, return RET_NOTHING.
+ * return RET_ERROR_WRONG_MD5 if already existing do not match */
+retvalue checksums_complete(struct checksums **checksums_p, const char *fullfilename) {
+ if (checksums_iscomplete(*checksums_p))
+ return RET_OK;
+ return checksums_test(fullfilename, *checksums_p, checksums_p);
+}
+
+retvalue checksums_read(const char *fullfilename, /*@out@*/struct checksums **checksums_p) {
+ struct checksumscontext context;
+ static const size_t bufsize = 16384;
+ unsigned char *buffer = malloc(bufsize);
+ ssize_t sizeread;
+ int e, i;
+ int infd;
+
+ if (FAILEDTOALLOC(buffer))
+ return RET_ERROR_OOM;
+
+ checksumscontext_init(&context);
+
+ infd = open(fullfilename, O_RDONLY);
+ if (infd < 0) {
+ e = errno;
+ if ((e == EACCES || e == ENOENT) &&
+ !isregularfile(fullfilename)) {
+ free(buffer);
+ return RET_NOTHING;
+ }
+ fprintf(stderr, "Error %d opening '%s': %s\n",
+ e, fullfilename, strerror(e));
+ free(buffer);
+ return RET_ERRNO(e);
+ }
+ do {
+ sizeread = read(infd, buffer, bufsize);
+ if (sizeread < 0) {
+ e = errno;
+ fprintf(stderr, "Error %d while reading %s: %s\n",
+ e, fullfilename, strerror(e));
+ free(buffer);
+ (void)close(infd);
+ return RET_ERRNO(e);;
+ }
+ checksumscontext_update(&context, buffer, (size_t)sizeread);
+ } while (sizeread > 0);
+ free(buffer);
+ i = close(infd);
+ if (i != 0) {
+ e = errno;
+ fprintf(stderr, "Error %d reading %s: %s\n",
+ e, fullfilename, strerror(e));
+ return RET_ERRNO(e);;
+ }
+ return checksums_from_context(checksums_p, &context);
+}
+
+retvalue checksums_copyfile(const char *destination, const char *source, bool deletetarget, struct checksums **checksums_p) {
+ struct checksumscontext context;
+ static const size_t bufsize = 16384;
+ unsigned char *buffer = malloc(bufsize);
+ ssize_t sizeread, towrite, written;
+ const unsigned char *start;
+ int e, i;
+ int infd, outfd;
+
+ if (FAILEDTOALLOC(buffer))
+ return RET_ERROR_OOM;
+
+ infd = open(source, O_RDONLY);
+ if (infd < 0) {
+ e = errno;
+ fprintf(stderr, "Error %d opening '%s': %s\n",
+ e, source, strerror(e));
+ free(buffer);
+ return RET_ERRNO(e);
+ }
+ outfd = open(destination, O_NOCTTY|O_WRONLY|O_CREAT|O_EXCL, 0666);
+ if (outfd < 0) {
+ e = errno;
+ if (e == EEXIST) {
+ if (deletetarget) {
+ i = unlink(destination);
+ if (i != 0) {
+ e = errno;
+ fprintf(stderr,
+"Error %d deleting '%s': %s\n",
+ e, destination, strerror(e));
+ (void)close(infd);
+ free(buffer);
+ return RET_ERRNO(e);
+ }
+ outfd = open(destination,
+ O_NOCTTY|O_WRONLY|O_CREAT|O_EXCL,
+ 0666);
+ e = errno;
+ } else {
+ (void)close(infd);
+ free(buffer);
+ return RET_ERROR_EXIST;
+ }
+ }
+ if (outfd < 0) {
+ fprintf(stderr,
+"Error %d creating '%s': %s\n",
+ e, destination, strerror(e));
+ (void)close(infd);
+ free(buffer);
+ return RET_ERRNO(e);
+ }
+ }
+ checksumscontext_init(&context);
+ do {
+ sizeread = read(infd, buffer, bufsize);
+ if (sizeread < 0) {
+ e = errno;
+ fprintf(stderr, "Error %d while reading %s: %s\n",
+ e, source, strerror(e));
+ free(buffer);
+ (void)close(infd); (void)close(outfd);
+ deletefile(destination);
+ return RET_ERRNO(e);;
+ }
+ checksumscontext_update(&context, buffer, (size_t)sizeread);
+ towrite = sizeread;
+ start = buffer;
+ while (towrite > 0) {
+ written = write(outfd, start, (size_t)towrite);
+ if (written < 0) {
+ e = errno;
+ fprintf(stderr,
+"Error %d while writing to %s: %s\n",
+ e, destination, strerror(e));
+ free(buffer);
+ (void)close(infd); (void)close(outfd);
+ deletefile(destination);
+ return RET_ERRNO(e);;
+ }
+ towrite -= written;
+ start += written;
+ }
+ } while (sizeread > 0);
+ free(buffer);
+ i = close(infd);
+ if (i != 0) {
+ e = errno;
+ fprintf(stderr, "Error %d reading %s: %s\n",
+ e, source, strerror(e));
+ (void)close(outfd);
+ deletefile(destination);
+ return RET_ERRNO(e);;
+ }
+ i = close(outfd);
+ if (i != 0) {
+ e = errno;
+ fprintf(stderr, "Error %d writing to %s: %s\n",
+ e, destination, strerror(e));
+ deletefile(destination);
+ return RET_ERRNO(e);;
+ }
+ return checksums_from_context(checksums_p, &context);
+}
+
+retvalue checksums_linkorcopyfile(const char *destination, const char *source, struct checksums **checksums_p) {
+ int i;
+ retvalue r;
+
+ // TODO: is this needed? perhaps move this duty to the caller...
+ r = dirs_make_parent(destination);
+ if (RET_WAS_ERROR