]> git.saurik.com Git - apt.git/blame - ftparchive/writer.cc
Consistently use Dpkg::Progress* in documentation
[apt.git] / ftparchive / writer.cc
CommitLineData
b2e465d6
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
5200ec6f 3// $Id: writer.cc,v 1.14 2004/03/24 01:40:43 mdz Exp $
b2e465d6
AL
4/* ######################################################################
5
6 Writer
7
8 The file writer classes. These write various types of output, sources,
9 packages and contents.
10
11 ##################################################################### */
12 /*}}}*/
13// Include Files /*{{{*/
ea542140
DK
14#include <config.h>
15
b2e465d6 16#include <apt-pkg/configuration.h>
b2e465d6 17#include <apt-pkg/deblistparser.h>
453b82a3 18#include <apt-pkg/error.h>
f1828b69
DK
19#include <apt-pkg/fileutl.h>
20#include <apt-pkg/gpgv.h>
453b82a3
DK
21#include <apt-pkg/hashes.h>
22#include <apt-pkg/md5.h>
23#include <apt-pkg/strutl.h>
24#include <apt-pkg/debfile.h>
25#include <apt-pkg/pkgcache.h>
26#include <apt-pkg/sha1.h>
27#include <apt-pkg/sha2.h>
28#include <apt-pkg/tagfile.h>
b2e465d6 29
453b82a3
DK
30#include <ctype.h>
31#include <fnmatch.h>
32#include <ftw.h>
33#include <locale.h>
34#include <string.h>
35#include <sys/stat.h>
b2e465d6
AL
36#include <sys/types.h>
37#include <unistd.h>
98953965 38#include <ctime>
8c58f506 39#include <iostream>
bf99a6d3 40#include <sstream>
4f333a8b 41#include <memory>
453b82a3 42#include <utility>
ea542140 43
453b82a3 44#include "apt-ftparchive.h"
ea542140 45#include "writer.h"
b2e465d6 46#include "cachedb.h"
b2e465d6 47#include "multicompress.h"
ea542140
DK
48
49#include <apti18n.h>
b2e465d6 50 /*}}}*/
8c58f506 51using namespace std;
b2e465d6
AL
52FTWScanner *FTWScanner::Owner;
53
64177f17
AL
54// SetTFRewriteData - Helper for setting rewrite lists /*{{{*/
55// ---------------------------------------------------------------------
56/* */
57inline void SetTFRewriteData(struct TFRewriteData &tfrd,
58 const char *tag,
59 const char *rewrite,
60 const char *newtag = 0)
61{
62 tfrd.Tag = tag;
63 tfrd.Rewrite = rewrite;
64 tfrd.NewTag = newtag;
65}
66 /*}}}*/
67
b2e465d6
AL
68// FTWScanner::FTWScanner - Constructor /*{{{*/
69// ---------------------------------------------------------------------
70/* */
31981076 71FTWScanner::FTWScanner(string const &Arch): Arch(Arch)
b2e465d6
AL
72{
73 ErrorPrinted = false;
74 NoLinkAct = !_config->FindB("APT::FTPArchive::DeLinkAct",true);
3c54407f
DK
75
76 DoMD5 = _config->FindB("APT::FTPArchive::MD5",true);
77 DoSHA1 = _config->FindB("APT::FTPArchive::SHA1",true);
78 DoSHA256 = _config->FindB("APT::FTPArchive::SHA256",true);
9abccf4a 79 DoSHA512 = _config->FindB("APT::FTPArchive::SHA512",true);
b2e465d6
AL
80}
81 /*}}}*/
82// FTWScanner::Scanner - FTW Scanner /*{{{*/
83// ---------------------------------------------------------------------
65512241 84/* This is the FTW scanner, it processes each directory element in the
b2e465d6 85 directory tree. */
65512241 86int FTWScanner::ScannerFTW(const char *File,const struct stat * /*sb*/,int Flag)
b2e465d6
AL
87{
88 if (Flag == FTW_DNR)
89 {
90 Owner->NewLine(1);
dc738e7a 91 ioprintf(c1out, _("W: Unable to read directory %s\n"), File);
b2e465d6
AL
92 }
93 if (Flag == FTW_NS)
94 {
95 Owner->NewLine(1);
dc738e7a 96 ioprintf(c1out, _("W: Unable to stat %s\n"), File);
b2e465d6
AL
97 }
98 if (Flag != FTW_F)
99 return 0;
100
cde41ae8
MV
101 return ScannerFile(File, true);
102}
103 /*}}}*/
104// FTWScanner::ScannerFile - File Scanner /*{{{*/
105// ---------------------------------------------------------------------
106/* */
9209ec47 107int FTWScanner::ScannerFile(const char *File, bool const &ReadLink)
cde41ae8 108{
98953965 109 const char *LastComponent = strrchr(File, '/');
ab3846c0
MV
110 char *RealPath = NULL;
111
98953965
AL
112 if (LastComponent == NULL)
113 LastComponent = File;
114 else
115 LastComponent++;
116
9209ec47 117 vector<string>::const_iterator I;
98953965
AL
118 for(I = Owner->Patterns.begin(); I != Owner->Patterns.end(); ++I)
119 {
120 if (fnmatch((*I).c_str(), LastComponent, 0) == 0)
121 break;
122 }
123 if (I == Owner->Patterns.end())
b2e465d6
AL
124 return 0;
125
126 /* Process it. If the file is a link then resolve it into an absolute
127 name.. This works best if the directory components the scanner are
128 given are not links themselves. */
129 char Jnk[2];
130 Owner->OriginalPath = File;
ab3846c0 131 if (ReadLink &&
cde41ae8 132 readlink(File,Jnk,sizeof(Jnk)) != -1 &&
ab3846c0
MV
133 (RealPath = realpath(File,NULL)) != 0)
134 {
135 Owner->DoPackage(RealPath);
136 free(RealPath);
137 }
b2e465d6
AL
138 else
139 Owner->DoPackage(File);
140
141 if (_error->empty() == false)
142 {
143 // Print any errors or warnings found
144 string Err;
145 bool SeenPath = false;
146 while (_error->empty() == false)
147 {
148 Owner->NewLine(1);
149
9209ec47 150 bool const Type = _error->PopMessage(Err);
b2e465d6 151 if (Type == true)
dc738e7a 152 cerr << _("E: ") << Err << endl;
b2e465d6 153 else
dc738e7a 154 cerr << _("W: ") << Err << endl;
b2e465d6
AL
155
156 if (Err.find(File) != string::npos)
157 SeenPath = true;
158 }
159
160 if (SeenPath == false)
dc738e7a 161 cerr << _("E: Errors apply to file ") << "'" << File << "'" << endl;
b2e465d6
AL
162 return 0;
163 }
164
165 return 0;
166}
167 /*}}}*/
168// FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
169// ---------------------------------------------------------------------
170/* */
9209ec47 171bool FTWScanner::RecursiveScan(string const &Dir)
b2e465d6 172{
ab3846c0 173 char *RealPath = NULL;
b2e465d6
AL
174 /* If noprefix is set then jam the scan root in, so we don't generate
175 link followed paths out of control */
176 if (InternalPrefix.empty() == true)
177 {
ab3846c0 178 if ((RealPath = realpath(Dir.c_str(),NULL)) == 0)
dc738e7a 179 return _error->Errno("realpath",_("Failed to resolve %s"),Dir.c_str());
ab3846c0
MV
180 InternalPrefix = RealPath;
181 free(RealPath);
b2e465d6
AL
182 }
183
184 // Do recursive directory searching
185 Owner = this;
9209ec47 186 int const Res = ftw(Dir.c_str(),ScannerFTW,30);
b2e465d6
AL
187
188 // Error treewalking?
189 if (Res != 0)
190 {
191 if (_error->PendingError() == false)
dc738e7a 192 _error->Errno("ftw",_("Tree walking failed"));
b2e465d6
AL
193 return false;
194 }
195
196 return true;
197}
198 /*}}}*/
199// FTWScanner::LoadFileList - Load the file list from a file /*{{{*/
200// ---------------------------------------------------------------------
201/* This is an alternative to using FTW to locate files, it reads the list
202 of files from another file. */
9209ec47 203bool FTWScanner::LoadFileList(string const &Dir, string const &File)
b2e465d6 204{
ab3846c0 205 char *RealPath = NULL;
b2e465d6
AL
206 /* If noprefix is set then jam the scan root in, so we don't generate
207 link followed paths out of control */
208 if (InternalPrefix.empty() == true)
209 {
ab3846c0 210 if ((RealPath = realpath(Dir.c_str(),NULL)) == 0)
dc738e7a 211 return _error->Errno("realpath",_("Failed to resolve %s"),Dir.c_str());
b2e465d6 212 InternalPrefix = RealPath;
ab3846c0 213 free(RealPath);
b2e465d6
AL
214 }
215
216 Owner = this;
217 FILE *List = fopen(File.c_str(),"r");
218 if (List == 0)
dc738e7a 219 return _error->Errno("fopen",_("Failed to open %s"),File.c_str());
b2e465d6
AL
220
221 /* We are a tad tricky here.. We prefix the buffer with the directory
222 name, that way if we need a full path with just use line.. Sneaky and
223 fully evil. */
224 char Line[1000];
225 char *FileStart;
226 if (Dir.empty() == true || Dir.end()[-1] != '/')
227 FileStart = Line + snprintf(Line,sizeof(Line),"%s/",Dir.c_str());
228 else
229 FileStart = Line + snprintf(Line,sizeof(Line),"%s",Dir.c_str());
230 while (fgets(FileStart,sizeof(Line) - (FileStart - Line),List) != 0)
231 {
232 char *FileName = _strstrip(FileStart);
233 if (FileName[0] == 0)
234 continue;
235
236 if (FileName[0] != '/')
237 {
238 if (FileName != FileStart)
239 memmove(FileStart,FileName,strlen(FileStart));
240 FileName = Line;
241 }
242
cde41ae8 243#if 0
b2e465d6
AL
244 struct stat St;
245 int Flag = FTW_F;
246 if (stat(FileName,&St) != 0)
247 Flag = FTW_NS;
cde41ae8 248#endif
b2e465d6 249
cde41ae8 250 if (ScannerFile(FileName, false) != 0)
b2e465d6
AL
251 break;
252 }
253
254 fclose(List);
255 return true;
256}
257 /*}}}*/
258// FTWScanner::Delink - Delink symlinks /*{{{*/
259// ---------------------------------------------------------------------
260/* */
261bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
650faab0
DK
262 unsigned long long &DeLinkBytes,
263 unsigned long long const &FileSize)
b2e465d6
AL
264{
265 // See if this isn't an internaly prefix'd file name.
266 if (InternalPrefix.empty() == false &&
267 InternalPrefix.length() < FileName.length() &&
268 stringcmp(FileName.begin(),FileName.begin() + InternalPrefix.length(),
269 InternalPrefix.begin(),InternalPrefix.end()) != 0)
270 {
271 if (DeLinkLimit != 0 && DeLinkBytes/1024 < DeLinkLimit)
272 {
273 // Tidy up the display
274 if (DeLinkBytes == 0)
275 cout << endl;
276
277 NewLine(1);
dc738e7a 278 ioprintf(c1out, _(" DeLink %s [%s]\n"), (OriginalPath + InternalPrefix.length()),
cde41ae8 279 SizeToStr(FileSize).c_str());
dc738e7a 280 c1out << flush;
b2e465d6
AL
281
282 if (NoLinkAct == false)
283 {
284 char OldLink[400];
285 if (readlink(OriginalPath,OldLink,sizeof(OldLink)) == -1)
dc738e7a 286 _error->Errno("readlink",_("Failed to readlink %s"),OriginalPath);
b2e465d6
AL
287 else
288 {
289 if (unlink(OriginalPath) != 0)
dc738e7a 290 _error->Errno("unlink",_("Failed to unlink %s"),OriginalPath);
b2e465d6
AL
291 else
292 {
293 if (link(FileName.c_str(),OriginalPath) != 0)
294 {
295 // Panic! Restore the symlink
f52037d6
MV
296 if (symlink(OldLink,OriginalPath) != 0)
297 _error->Errno("symlink", "failed to restore symlink");
dc738e7a 298 return _error->Errno("link",_("*** Failed to link %s to %s"),
b2e465d6
AL
299 FileName.c_str(),
300 OriginalPath);
301 }
302 }
303 }
304 }
305
cde41ae8 306 DeLinkBytes += FileSize;
b2e465d6 307 if (DeLinkBytes/1024 >= DeLinkLimit)
dc738e7a 308 ioprintf(c1out, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes).c_str());
b2e465d6
AL
309 }
310
311 FileName = OriginalPath;
312 }
313
314 return true;
315}
316 /*}}}*/
b2e465d6
AL
317
318// PackagesWriter::PackagesWriter - Constructor /*{{{*/
319// ---------------------------------------------------------------------
320/* */
9209ec47 321PackagesWriter::PackagesWriter(string const &DB,string const &Overrides,string const &ExtOverrides,
31981076 322 string const &Arch) :
66905344 323 FTWScanner(Arch), Db(DB), Stats(Db.Stats), TransWriter(NULL)
b2e465d6
AL
324{
325 Output = stdout;
31981076 326 SetExts(".deb .udeb");
b2e465d6 327 DeLinkLimit = 0;
3cb3fe76 328
b2e465d6 329 // Process the command line options
3c54407f
DK
330 DoMD5 = _config->FindB("APT::FTPArchive::Packages::MD5",DoMD5);
331 DoSHA1 = _config->FindB("APT::FTPArchive::Packages::SHA1",DoSHA1);
332 DoSHA256 = _config->FindB("APT::FTPArchive::Packages::SHA256",DoSHA256);
8e5d47a3 333 DoSHA512 = _config->FindB("APT::FTPArchive::Packages::SHA512",DoSHA512);
ff574e76 334 DoAlwaysStat = _config->FindB("APT::FTPArchive::AlwaysStat", false);
b2e465d6
AL
335 DoContents = _config->FindB("APT::FTPArchive::Contents",true);
336 NoOverride = _config->FindB("APT::FTPArchive::NoOverrideMsg",false);
9c24493f 337 LongDescription = _config->FindB("APT::FTPArchive::LongDescription",true);
b2e465d6
AL
338
339 if (Db.Loaded() == false)
340 DoContents = false;
66905344 341
b2e465d6
AL
342 // Read the override file
343 if (Overrides.empty() == false && Over.ReadOverride(Overrides) == false)
344 return;
345 else
346 NoOverride = true;
64177f17
AL
347
348 if (ExtOverrides.empty() == false)
349 Over.ReadExtraOverride(ExtOverrides);
350
b2e465d6
AL
351 _error->DumpErrors();
352}
98953965
AL
353 /*}}}*/
354// FTWScanner::SetExts - Set extensions to support /*{{{*/
355// ---------------------------------------------------------------------
356/* */
9209ec47 357bool FTWScanner::SetExts(string const &Vals)
98953965
AL
358{
359 ClearPatterns();
360 string::size_type Start = 0;
d6689735 361 while (Start <= Vals.length()-1)
98953965 362 {
31981076
DK
363 string::size_type const Space = Vals.find(' ',Start);
364 string::size_type const Length = ((Space == string::npos) ? Vals.length() : Space) - Start;
365 if ( Arch.empty() == false )
98953965 366 {
31981076
DK
367 AddPattern(string("*_") + Arch + Vals.substr(Start, Length));
368 AddPattern(string("*_all") + Vals.substr(Start, Length));
98953965 369 }
d6689735 370 else
31981076
DK
371 AddPattern(string("*") + Vals.substr(Start, Length));
372
d6689735 373 Start += Length + 1;
98953965
AL
374 }
375
376 return true;
377}
378
b2e465d6
AL
379 /*}}}*/
380// PackagesWriter::DoPackage - Process a single package /*{{{*/
381// ---------------------------------------------------------------------
382/* This method takes a package and gets its control information and
cde41ae8
MV
383 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
384 rewritten and the path/size/hash appended. */
b2e465d6
AL
385bool PackagesWriter::DoPackage(string FileName)
386{
b2e465d6 387 // Pull all the data we need form the DB
9a961efc 388 if (Db.GetFileInfo(FileName, true, DoContents, true, DoMD5, DoSHA1, DoSHA256, DoSHA512, DoAlwaysStat)
cde41ae8
MV
389 == false)
390 {
b2e465d6 391 return false;
cde41ae8 392 }
b2e465d6 393
650faab0 394 unsigned long long FileSize = Db.GetFileSize();
cde41ae8 395 if (Delink(FileName,OriginalPath,Stats.DeLinkBytes,FileSize) == false)
b2e465d6
AL
396 return false;
397
398 // Lookup the overide information
399 pkgTagSection &Tags = Db.Control.Section;
400 string Package = Tags.FindS("Package");
0b41e0e7
MV
401 string Architecture;
402 // if we generate a Packages file for a given arch, we use it to
403 // look for overrides. if we run in "simple" mode without the
404 // "Architecures" variable in the config we use the architecure value
405 // from the deb file
406 if(Arch != "")
407 Architecture = Arch;
408 else
409 Architecture = Tags.FindS("Architecture");
410 auto_ptr<Override::Item> OverItem(Over.GetItem(Package,Architecture));
b2e465d6
AL
411
412 if (Package.empty() == true)
dc738e7a 413 return _error->Error(_("Archive had no package field"));
0b41e0e7 414
b2e465d6 415 // If we need to do any rewriting of the header do it now..
0b41e0e7 416 if (OverItem.get() == 0)
b2e465d6
AL
417 {
418 if (NoOverride == false)
419 {
420 NewLine(1);
dc738e7a 421 ioprintf(c1out, _(" %s has no override entry\n"), Package.c_str());
b2e465d6
AL
422 }
423
0b41e0e7
MV
424 OverItem = auto_ptr<Override::Item>(new Override::Item);
425 OverItem->FieldOverride["Section"] = Tags.FindS("Section");
426 OverItem->Priority = Tags.FindS("Priority");
b2e465d6
AL
427 }
428
429 char Size[40];
650faab0 430 sprintf(Size,"%llu", (unsigned long long) FileSize);
b2e465d6
AL
431
432 // Strip the DirStrip prefix from the FileName and add the PathPrefix
433 string NewFileName;
434 if (DirStrip.empty() == false &&
435 FileName.length() > DirStrip.length() &&
436 stringcmp(FileName.begin(),FileName.begin() + DirStrip.length(),
437 DirStrip.begin(),DirStrip.end()) == 0)
438 NewFileName = string(FileName.begin() + DirStrip.length(),FileName.end());
439 else
440 NewFileName = FileName;
441 if (PathPrefix.empty() == false)
442 NewFileName = flCombine(PathPrefix,NewFileName);
9c24493f
DK
443
444 /* Configuration says we don't want to include the long Description
445 in the package file - instead we want to ship a separated file */
446 string desc;
447 if (LongDescription == false) {
448 desc = Tags.FindS("Description").append("\n");
449 OverItem->FieldOverride["Description"] = desc.substr(0, desc.find('\n')).c_str();
450 }
451
b2e465d6 452 // This lists all the changes to the fields we are going to make.
64177f17 453 // (7 hardcoded + maintainer + suggests + end marker)
9c24493f 454 TFRewriteData Changes[6+2+OverItem->FieldOverride.size()+1+1];
64177f17 455
b2e465d6 456 unsigned int End = 0;
64177f17 457 SetTFRewriteData(Changes[End++], "Size", Size);
3c54407f
DK
458 if (DoMD5 == true)
459 SetTFRewriteData(Changes[End++], "MD5sum", Db.MD5Res.c_str());
460 if (DoSHA1 == true)
461 SetTFRewriteData(Changes[End++], "SHA1", Db.SHA1Res.c_str());
462 if (DoSHA256 == true)
463 SetTFRewriteData(Changes[End++], "SHA256", Db.SHA256Res.c_str());
12cd178d
MV
464 if (DoSHA512 == true)
465 SetTFRewriteData(Changes[End++], "SHA512", Db.SHA512Res.c_str());
64177f17
AL
466 SetTFRewriteData(Changes[End++], "Filename", NewFileName.c_str());
467 SetTFRewriteData(Changes[End++], "Priority", OverItem->Priority.c_str());
468 SetTFRewriteData(Changes[End++], "Status", 0);
469 SetTFRewriteData(Changes[End++], "Optional", 0);
470
9c24493f
DK
471 string DescriptionMd5;
472 if (LongDescription == false) {
473 MD5Summation descmd5;
474 descmd5.Add(desc.c_str());
475 DescriptionMd5 = descmd5.Result().Value();
476 SetTFRewriteData(Changes[End++], "Description-md5", DescriptionMd5.c_str());
66905344
DK
477 if (TransWriter != NULL)
478 TransWriter->DoPackage(Package, desc, DescriptionMd5);
9c24493f
DK
479 }
480
b2e465d6
AL
481 // Rewrite the maintainer field if necessary
482 bool MaintFailed;
483 string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
484 if (MaintFailed == true)
485 {
486 if (NoOverride == false)
487 {
488 NewLine(1);
dc738e7a
AL
489 ioprintf(c1out, _(" %s maintainer is %s not %s\n"),
490 Package.c_str(), Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
b2e465d6
AL
491 }
492 }
493
494 if (NewMaint.empty() == false)
64177f17 495 SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
b2e465d6
AL
496
497 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
c6474fb6 498 dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
b2e465d6
AL
499 but dpkg does this append bit. So we do the append bit, at least that way the
500 status file and package file will remain similar. There are other transforms
501 but optional is the only legacy one still in use for some lazy reason. */
502 string OptionalStr = Tags.FindS("Optional");
503 if (OptionalStr.empty() == false)
504 {
505 if (Tags.FindS("Suggests").empty() == false)
506 OptionalStr = Tags.FindS("Suggests") + ", " + OptionalStr;
64177f17 507 SetTFRewriteData(Changes[End++], "Suggests", OptionalStr.c_str());
b2e465d6 508 }
64177f17 509
9209ec47 510 for (map<string,string>::const_iterator I = OverItem->FieldOverride.begin();
f7f0d6c7 511 I != OverItem->FieldOverride.end(); ++I)
64177f17
AL
512 SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
513
514 SetTFRewriteData(Changes[End++], 0, 0);
515
b2e465d6
AL
516 // Rewrite and store the fields.
517 if (TFRewrite(Output,Tags,TFRewritePackageOrder,Changes) == false)
518 return false;
519 fprintf(Output,"\n");
520
521 return Db.Finish();
522}
523 /*}}}*/
524
66905344
DK
525// TranslationWriter::TranslationWriter - Constructor /*{{{*/
526// ---------------------------------------------------------------------
527/* Create a Translation-Master file for this Packages file */
34f1d96c
DK
528TranslationWriter::TranslationWriter(string const &File, string const &TransCompress,
529 mode_t const &Permissions) : Output(NULL),
66905344
DK
530 RefCounter(0)
531{
532 if (File.empty() == true)
533 return;
534
34f1d96c
DK
535 Comp = new MultiCompress(File, TransCompress, Permissions);
536 Output = Comp->Input;
66905344
DK
537}
538 /*}}}*/
539// TranslationWriter::DoPackage - Process a single package /*{{{*/
540// ---------------------------------------------------------------------
541/* Create a Translation-Master file for this Packages file */
542bool TranslationWriter::DoPackage(string const &Pkg, string const &Desc,
543 string const &MD5)
544{
545 if (Output == NULL)
546 return true;
547
548 // Different archs can include different versions and therefore
549 // different descriptions - so we need to check for both name and md5.
550 string const Record = Pkg + ":" + MD5;
551
552 if (Included.find(Record) != Included.end())
553 return true;
554
555 fprintf(Output, "Package: %s\nDescription-md5: %s\nDescription-en: %s\n",
556 Pkg.c_str(), MD5.c_str(), Desc.c_str());
557
558 Included.insert(Record);
559 return true;
560}
561 /*}}}*/
562// TranslationWriter::~TranslationWriter - Destructor /*{{{*/
563// ---------------------------------------------------------------------
564/* */
565TranslationWriter::~TranslationWriter()
566{
34f1d96c
DK
567 if (Comp == NULL)
568 return;
569
570 delete Comp;
66905344
DK
571}
572 /*}}}*/
573
b2e465d6
AL
574// SourcesWriter::SourcesWriter - Constructor /*{{{*/
575// ---------------------------------------------------------------------
576/* */
f6f06a8f
MV
577SourcesWriter::SourcesWriter(string const &DB, string const &BOverrides,string const &SOverrides,
578 string const &ExtOverrides) :
579 Db(DB), Stats(Db.Stats)
b2e465d6
AL
580{
581 Output = stdout;
98953965 582 AddPattern("*.dsc");
b2e465d6
AL
583 DeLinkLimit = 0;
584 Buffer = 0;
585 BufSize = 0;
586
587 // Process the command line options
3c54407f
DK
588 DoMD5 = _config->FindB("APT::FTPArchive::Sources::MD5",DoMD5);
589 DoSHA1 = _config->FindB("APT::FTPArchive::Sources::SHA1",DoSHA1);
590 DoSHA256 = _config->FindB("APT::FTPArchive::Sources::SHA256",DoSHA256);
f6f06a8f 591 DoSHA512 = _config->FindB("APT::FTPArchive::Sources::SHA512",DoSHA512);
b2e465d6 592 NoOverride = _config->FindB("APT::FTPArchive::NoOverrideMsg",false);
f6f06a8f 593 DoAlwaysStat = _config->FindB("APT::FTPArchive::AlwaysStat", false);
b2e465d6
AL
594
595 // Read the override file
596 if (BOverrides.empty() == false && BOver.ReadOverride(BOverrides) == false)
597 return;
598 else
599 NoOverride = true;
64177f17 600
cde41ae8
MV
601 // WTF?? The logic above: if we can't read binary overrides, don't even try
602 // reading source overrides. if we can read binary overrides, then say there
603 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
604
64177f17
AL
605 if (ExtOverrides.empty() == false)
606 SOver.ReadExtraOverride(ExtOverrides);
b2e465d6 607
64177f17
AL
608 if (SOverrides.empty() == false && FileExists(SOverrides) == true)
609 SOver.ReadOverride(SOverrides,true);
b2e465d6
AL
610}
611 /*}}}*/
612// SourcesWriter::DoPackage - Process a single package /*{{{*/
613// ---------------------------------------------------------------------
614/* */
615bool SourcesWriter::DoPackage(string FileName)
f1828b69 616{
b2e465d6 617 // Open the archive
f1828b69
DK
618 FileFd F;
619 if (OpenMaybeClearSignedFile(FileName, F) == false)
b2e465d6 620 return false;
b2e465d6 621
f1828b69
DK
622 unsigned long long const FSize = F.FileSize();
623 //FIXME: do we really need to enforce a maximum size of the dsc file?
624 if (FSize > 128*1024)
b2e465d6 625 return _error->Error("DSC file '%s' is too large!",FileName.c_str());
f1828b69
DK
626
627 if (BufSize < FSize + 2)
b2e465d6 628 {
f1828b69
DK
629 BufSize = FSize + 2;
630 Buffer = (char *)realloc(Buffer , BufSize);
b2e465d6 631 }
f1828b69
DK
632
633 if (F.Read(Buffer, FSize) == false)
b2e465d6
AL
634 return false;
635
f1828b69
DK
636 // Stat the file for later (F might be clearsigned, so not F.FileSize())
637 struct stat St;
638 if (stat(FileName.c_str(), &St) != 0)
639 return _error->Errno("fstat","Failed to stat %s",FileName.c_str());
640
b2e465d6
AL
641 // Hash the file
642 char *Start = Buffer;
f1828b69 643 char *BlkEnd = Buffer + FSize;
f99da908 644
f1828b69
DK
645 Hashes DscHashes;
646 if (FSize == (unsigned long long) St.st_size)
b2e465d6 647 {
f1828b69
DK
648 if (DoMD5 == true)
649 DscHashes.MD5.Add((unsigned char *)Start,BlkEnd - Start);
650 if (DoSHA1 == true)
651 DscHashes.SHA1.Add((unsigned char *)Start,BlkEnd - Start);
652 if (DoSHA256 == true)
653 DscHashes.SHA256.Add((unsigned char *)Start,BlkEnd - Start);
654 if (DoSHA512 == true)
655 DscHashes.SHA512.Add((unsigned char *)Start,BlkEnd - Start);
b2e465d6 656 }
f1828b69 657 else
b2e465d6 658 {
f1828b69
DK
659 FileFd DscFile(FileName, FileFd::ReadOnly);
660 DscHashes.AddFD(DscFile, St.st_size, DoMD5, DoSHA1, DoSHA256, DoSHA512);
b2e465d6 661 }
f1828b69
DK
662
663 // Add extra \n to the end, just in case (as in clearsigned they are missing)
664 *BlkEnd++ = '\n';
665 *BlkEnd++ = '\n';
666
667 pkgTagSection Tags;
668 if (Tags.Scan(Start,BlkEnd - Start) == false || Tags.Exists("Source") == false)
669 return _error->Error("Could not find a record in the DSC '%s'",FileName.c_str());
b2e465d6 670 Tags.Trim();
f1828b69 671
b2e465d6
AL
672 // Lookup the overide information, finding first the best priority.
673 string BestPrio;
b2e465d6 674 string Bins = Tags.FindS("Binary");
5200ec6f 675 char Buffer[Bins.length() + 1];
0b41e0e7 676 auto_ptr<Override::Item> OverItem(0);
5200ec6f 677 if (Bins.empty() == false)
b2e465d6
AL
678 {
679 strcpy(Buffer,Bins.c_str());
680
681 // Ignore too-long errors.
682 char *BinList[400];
683 TokSplitString(',',Buffer,BinList,sizeof(BinList)/sizeof(BinList[0]));
684
685 // Look at all the binaries
686 unsigned char BestPrioV = pkgCache::State::Extra;
687 for (unsigned I = 0; BinList[I] != 0; I++)
688 {
0b41e0e7
MV
689 auto_ptr<Override::Item> Itm(BOver.GetItem(BinList[I]));
690 if (Itm.get() == 0)
b2e465d6 691 continue;
b2e465d6
AL
692
693 unsigned char NewPrioV = debListParser::GetPrio(Itm->Priority);
694 if (NewPrioV < BestPrioV || BestPrio.empty() == true)
695 {
696 BestPrioV = NewPrioV;
697 BestPrio = Itm->Priority;
698 }
7524e348
MV
699
700 if (OverItem.get() == 0)
701 OverItem = Itm;
b2e465d6
AL
702 }
703 }
704
705 // If we need to do any rewriting of the header do it now..
0b41e0e7 706 if (OverItem.get() == 0)
b2e465d6
AL
707 {
708 if (NoOverride == false)
709 {
710 NewLine(1);
dc738e7a 711 ioprintf(c1out, _(" %s has no override entry\n"), Tags.FindS("Source").c_str());
b2e465d6
AL
712 }
713
0b41e0e7 714 OverItem = auto_ptr<Override::Item>(new Override::Item);
b2e465d6
AL
715 }
716
0b41e0e7 717 auto_ptr<Override::Item> SOverItem(SOver.GetItem(Tags.FindS("Source")));
cde41ae8 718 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
0b41e0e7 719 if (SOverItem.get() == 0)
b2e465d6 720 {
cde41ae8 721 ioprintf(c1out, _(" %s has no source override entry\n"), Tags.FindS("Source").c_str());
0b41e0e7
MV
722 SOverItem = auto_ptr<Override::Item>(BOver.GetItem(Tags.FindS("Source")));
723 if (SOverItem.get() == 0)
724 {
cde41ae8 725 ioprintf(c1out, _(" %s has no binary override entry either\n"), Tags.FindS("Source").c_str());
0b41e0e7
MV
726 SOverItem = auto_ptr<Override::Item>(new Override::Item);
727 *SOverItem = *OverItem;
728 }
b2e465d6
AL
729 }
730
731 // Add the dsc to the files hash list
f99da908 732 string const strippedName = flNotDir(FileName);
bf99a6d3 733 std::ostringstream ostreamFiles;
3c54407f 734 if (DoMD5 == true && Tags.Exists("Files"))
f1828b69 735 ostreamFiles << "\n " << string(DscHashes.MD5.Result()) << " " << St.st_size << " "
2a19ec29 736 << strippedName << "\n " << Tags.FindS("Files");
bf99a6d3
DK
737 string const Files = ostreamFiles.str();
738
739 std::ostringstream ostreamSha1;
3c54407f 740 if (DoSHA1 == true && Tags.Exists("Checksums-Sha1"))
f1828b69 741 ostreamSha1 << "\n " << string(DscHashes.SHA1.Result()) << " " << St.st_size << " "
2a19ec29 742 << strippedName << "\n " << Tags.FindS("Checksums-Sha1");
bf99a6d3
DK
743
744 std::ostringstream ostreamSha256;
3c54407f 745 if (DoSHA256 == true && Tags.Exists("Checksums-Sha256"))
f1828b69 746 ostreamSha256 << "\n " << string(DscHashes.SHA256.Result()) << " " << St.st_size << " "
2a19ec29 747 << strippedName << "\n " << Tags.FindS("Checksums-Sha256");
f99da908 748
9a961efc 749 std::ostringstream ostreamSha512;
f6f06a8f 750 if (DoSHA512 == true && Tags.Exists("Checksums-Sha512"))
f1828b69 751 ostreamSha512 << "\n " << string(DscHashes.SHA512.Result()) << " " << St.st_size << " "
9a961efc 752 << strippedName << "\n " << Tags.FindS("Checksums-Sha512");
9a961efc 753
b2e465d6
AL
754 // Strip the DirStrip prefix from the FileName and add the PathPrefix
755 string NewFileName;
756 if (DirStrip.empty() == false &&
757 FileName.length() > DirStrip.length() &&
8c58f506 758 stringcmp(DirStrip,OriginalPath,OriginalPath + DirStrip.length()) == 0)
b2e465d6
AL
759 NewFileName = string(OriginalPath + DirStrip.length());
760 else
761 NewFileName = OriginalPath;
762 if (PathPrefix.empty() == false)
763 NewFileName = flCombine(PathPrefix,NewFileName);
171c45bc 764
b2e465d6
AL
765 string Directory = flNotFile(OriginalPath);
766 string Package = Tags.FindS("Source");
171c45bc 767
f6f06a8f 768 // Perform operation over all of the files
b2e465d6 769 string ParseJnk;
bf99a6d3 770 const char *C = Files.c_str();
ab3846c0 771 char *RealPath = NULL;
b2e465d6
AL
772 for (;isspace(*C); C++);
773 while (*C != 0)
774 {
775 // Parse each of the elements
776 if (ParseQuoteWord(C,ParseJnk) == false ||
777 ParseQuoteWord(C,ParseJnk) == false ||
778 ParseQuoteWord(C,ParseJnk) == false)
779 return _error->Error("Error parsing file record");
f6f06a8f 780
b2e465d6 781 string OriginalPath = Directory + ParseJnk;
f6f06a8f
MV
782
783 // Add missing hashes to source files
784 if ((DoSHA1 == true && !Tags.Exists("Checksums-Sha1")) ||
785 (DoSHA256 == true && !Tags.Exists("Checksums-Sha256")) ||
786 (DoSHA512 == true && !Tags.Exists("Checksums-Sha512")))
787 {
788 if (Db.GetFileInfo(OriginalPath, false, false, false, DoMD5, DoSHA1, DoSHA256, DoSHA512, DoAlwaysStat)
789 == false)
790 {
791 return _error->Error("Error getting file info");
792 }
793
794 if (DoSHA1 == true && !Tags.Exists("Checksums-Sha1"))
795 ostreamSha1 << "\n " << string(Db.SHA1Res) << " "
796 << Db.GetFileSize() << " " << ParseJnk;
797
798 if (DoSHA256 == true && !Tags.Exists("Checksums-Sha256"))
799 ostreamSha256 << "\n " << string(Db.SHA256Res) << " "
800 << Db.GetFileSize() << " " << ParseJnk;
801
802 if (DoSHA512 == true && !Tags.Exists("Checksums-Sha512"))
803 ostreamSha512 << "\n " << string(Db.SHA512Res) << " "
804 << Db.GetFileSize() << " " << ParseJnk;
805 }
806
807 // Perform the delinking operation
808 char Jnk[2];
809
ab3846c0
MV
810 if (readlink(OriginalPath.c_str(),Jnk,sizeof(Jnk)) != -1 &&
811 (RealPath = realpath(OriginalPath.c_str(),NULL)) != 0)
b2e465d6
AL
812 {
813 string RP = RealPath;
ab3846c0 814 free(RealPath);
cde41ae8 815 if (Delink(RP,OriginalPath.c_str(),Stats.DeLinkBytes,St.st_size) == false)
b2e465d6
AL
816 return false;
817 }
818 }
819
820 Directory = flNotFile(NewFileName);
821 if (Directory.length() > 2)
822 Directory.erase(Directory.end()-1);
171c45bc 823
f6f06a8f
MV
824 string const ChecksumsSha1 = ostreamSha1.str();
825 string const ChecksumsSha256 = ostreamSha256.str();
826 string const ChecksumsSha512 = ostreamSha512.str();
827
b2e465d6 828 // This lists all the changes to the fields we are going to make.
f99da908
DK
829 // (5 hardcoded + checksums + maintainer + end marker)
830 TFRewriteData Changes[5+2+1+SOverItem->FieldOverride.size()+1];
64177f17 831
b2e465d6 832 unsigned int End = 0;
64177f17 833 SetTFRewriteData(Changes[End++],"Source",Package.c_str(),"Package");
3c54407f
DK
834 if (Files.empty() == false)
835 SetTFRewriteData(Changes[End++],"Files",Files.c_str());
836 if (ChecksumsSha1.empty() == false)
837 SetTFRewriteData(Changes[End++],"Checksums-Sha1",ChecksumsSha1.c_str());
838 if (ChecksumsSha256.empty() == false)
839 SetTFRewriteData(Changes[End++],"Checksums-Sha256",ChecksumsSha256.c_str());
12cd178d
MV
840 if (ChecksumsSha512.empty() == false)
841 SetTFRewriteData(Changes[End++],"Checksums-Sha512",ChecksumsSha512.c_str());
171c45bc
AL
842 if (Directory != "./")
843 SetTFRewriteData(Changes[End++],"Directory",Directory.c_str());
64177f17
AL
844 SetTFRewriteData(Changes[End++],"Priority",BestPrio.c_str());
845 SetTFRewriteData(Changes[End++],"Status",0);
b2e465d6
AL
846
847 // Rewrite the maintainer field if necessary
848 bool MaintFailed;
849 string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
850 if (MaintFailed == true)
851 {
852 if (NoOverride == false)
853 {
854 NewLine(1);
dc738e7a
AL
855 ioprintf(c1out, _(" %s maintainer is %s not %s\n"), Package.c_str(),
856 Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
b2e465d6
AL
857 }
858 }
859 if (NewMaint.empty() == false)
64177f17
AL
860 SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
861
9209ec47 862 for (map<string,string>::const_iterator I = SOverItem->FieldOverride.begin();
f7f0d6c7 863 I != SOverItem->FieldOverride.end(); ++I)
64177f17
AL
864 SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
865
866 SetTFRewriteData(Changes[End++], 0, 0);
b2e465d6
AL
867
868 // Rewrite and store the fields.
869 if (TFRewrite(Output,Tags,TFRewriteSourceOrder,Changes) == false)
870 return false;
871 fprintf(Output,"\n");
872
873 Stats.Packages++;
874
f6f06a8f 875 return Db.Finish();
b2e465d6
AL
876}
877 /*}}}*/
878
879// ContentsWriter::ContentsWriter - Constructor /*{{{*/
880// ---------------------------------------------------------------------
881/* */
31981076
DK
882ContentsWriter::ContentsWriter(string const &DB, string const &Arch) :
883 FTWScanner(Arch), Db(DB), Stats(Db.Stats)
b2e465d6
AL
884
885{
31981076 886 SetExts(".deb");
b2e465d6
AL
887 Output = stdout;
888}
889 /*}}}*/
890// ContentsWriter::DoPackage - Process a single package /*{{{*/
891// ---------------------------------------------------------------------
892/* If Package is the empty string the control record will be parsed to
893 determine what the package name is. */
9209ec47 894bool ContentsWriter::DoPackage(string FileName, string Package)
b2e465d6 895{
ff574e76 896 if (!Db.GetFileInfo(FileName, Package.empty(), true, false, false, false, false, false))
cde41ae8 897 {
b2e465d6 898 return false;
cde41ae8 899 }
b2e465d6
AL
900
901 // Parse the package name
902 if (Package.empty() == true)
903 {
b2e465d6
AL
904 Package = Db.Control.Section.FindS("Package");
905 }
906
907 Db.Contents.Add(Gen,Package);
908
909 return Db.Finish();
910}
911 /*}}}*/
912// ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
913// ---------------------------------------------------------------------
914/* */
9209ec47 915bool ContentsWriter::ReadFromPkgs(string const &PkgFile,string const &PkgCompress)
b2e465d6
AL
916{
917 MultiCompress Pkgs(PkgFile,PkgCompress,0,false);
918 if (_error->PendingError() == true)
919 return false;
12d1f5b3 920
b2e465d6 921 // Open the package file
12d1f5b3
DK
922 FileFd Fd;
923 if (Pkgs.OpenOld(Fd) == false)
b2e465d6 924 return false;
12d1f5b3 925
b2e465d6
AL
926 pkgTagFile Tags(&Fd);
927 if (_error->PendingError() == true)
b2e465d6 928 return false;
12d1f5b3 929
b2e465d6
AL
930 // Parse.
931 pkgTagSection Section;
932 while (Tags.Step(Section) == true)
933 {
934 string File = flCombine(Prefix,Section.FindS("FileName"));
935 string Package = Section.FindS("Section");
936 if (Package.empty() == false && Package.end()[-1] != '/')
937 {
938 Package += '/';
939 Package += Section.FindS("Package");
940 }
941 else
942 Package += Section.FindS("Package");
943
944 DoPackage(File,Package);
945 if (_error->empty() == false)
946 {
947 _error->Error("Errors apply to file '%s'",File.c_str());
948 _error->DumpErrors();
949 }
950 }
12d1f5b3 951
b2e465d6 952 // Tidy the compressor
12d1f5b3
DK
953 Fd.Close();
954
b2e465d6
AL
955 return true;
956}
98953965 957
b2e465d6 958 /*}}}*/
98953965
AL
959
960// ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
961// ---------------------------------------------------------------------
962/* */
65512241 963ReleaseWriter::ReleaseWriter(string const &/*DB*/)
98953965 964{
3cb3fe76
DK
965 if (_config->FindB("APT::FTPArchive::Release::Default-Patterns", true) == true)
966 {
967 AddPattern("Packages");
968 AddPattern("Packages.gz");
969 AddPattern("Packages.bz2");
970 AddPattern("Packages.lzma");
b7080ced 971 AddPattern("Packages.xz");
8e3900d0 972 AddPattern("Translation-*");
3cb3fe76
DK
973 AddPattern("Sources");
974 AddPattern("Sources.gz");
975 AddPattern("Sources.bz2");
976 AddPattern("Sources.lzma");
b7080ced 977 AddPattern("Sources.xz");
3cb3fe76 978 AddPattern("Release");
0baf849d 979 AddPattern("Contents-*");
8d16c617 980 AddPattern("Index");
3cb3fe76
DK
981 AddPattern("md5sum.txt");
982 }
983 AddPatterns(_config->FindVector("APT::FTPArchive::Release::Patterns"));
187492a6 984
98953965 985 Output = stdout;
9209ec47 986 time_t const now = time(NULL);
cb12d0a6
DK
987
988 setlocale(LC_TIME, "C");
989
98953965
AL
990 char datestr[128];
991 if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S UTC",
992 gmtime(&now)) == 0)
993 {
994 datestr[0] = '\0';
995 }
996
c99e48ec 997 time_t const validuntil = now + _config->FindI("APT::FTPArchive::Release::ValidTime", 0);
cdb623ed 998 char validstr[128];
c99e48ec
DK
999 if (now == validuntil ||
1000 strftime(validstr, sizeof(validstr), "%a, %d %b %Y %H:%M:%S UTC",
1001 gmtime(&validuntil)) == 0)
1002 {
cdb623ed 1003 validstr[0] = '\0';
c99e48ec
DK
1004 }
1005
cb12d0a6
DK
1006 setlocale(LC_TIME, "");
1007
98953965
AL
1008 map<string,string> Fields;
1009 Fields["Origin"] = "";
1010 Fields["Label"] = "";
1011 Fields["Suite"] = "";
1012 Fields["Version"] = "";
1013 Fields["Codename"] = "";
1014 Fields["Date"] = datestr;
c99e48ec 1015 Fields["Valid-Until"] = validstr;
98953965
AL
1016 Fields["Architectures"] = "";
1017 Fields["Components"] = "";
1018 Fields["Description"] = "";
1019
1020 for(map<string,string>::const_iterator I = Fields.begin();
1021 I != Fields.end();
1022 ++I)
1023 {
1024 string Config = string("APT::FTPArchive::Release::") + (*I).first;
1025 string Value = _config->Find(Config, (*I).second.c_str());
1026 if (Value == "")
1027 continue;
1028
1029 fprintf(Output, "%s: %s\n", (*I).first.c_str(), Value.c_str());
1030 }
3c54407f
DK
1031
1032 DoMD5 = _config->FindB("APT::FTPArchive::Release::MD5",DoMD5);
1033 DoSHA1 = _config->FindB("APT::FTPArchive::Release::SHA1",DoSHA1);
1034 DoSHA256 = _config->FindB("APT::FTPArchive::Release::SHA256",DoSHA256);
98953965
AL
1035}
1036 /*}}}*/
1037// ReleaseWriter::DoPackage - Process a single package /*{{{*/
1038// ---------------------------------------------------------------------
1039bool ReleaseWriter::DoPackage(string FileName)
1040{
1041 // Strip the DirStrip prefix from the FileName and add the PathPrefix
1042 string NewFileName;
1043 if (DirStrip.empty() == false &&
1044 FileName.length() > DirStrip.length() &&
1045 stringcmp(FileName.begin(),FileName.begin() + DirStrip.length(),
1046 DirStrip.begin(),DirStrip.end()) == 0)
c0eb6bc6 1047 {
98953965 1048 NewFileName = string(FileName.begin() + DirStrip.length(),FileName.end());
c0eb6bc6 1049 while (NewFileName[0] == '/')
9202409d 1050 NewFileName = string(NewFileName.begin() + 1,NewFileName.end());
c0eb6bc6 1051 }
98953965
AL
1052 else
1053 NewFileName = FileName;
c0eb6bc6 1054
98953965
AL
1055 if (PathPrefix.empty() == false)
1056 NewFileName = flCombine(PathPrefix,NewFileName);
1057
1058 FileFd fd(FileName, FileFd::ReadOnly);
1059
1060 if (!fd.IsOpen())
1061 {
1062 return false;
1063 }
1064
c0eb6bc6 1065 CheckSums[NewFileName].size = fd.Size();
f7291f62 1066
8c4e1f97 1067 Hashes hs;
109eb151 1068 hs.AddFD(fd, 0, DoMD5, DoSHA1, DoSHA256, DoSHA512);
3c54407f 1069 if (DoMD5 == true)
8c4e1f97 1070 CheckSums[NewFileName].MD5 = hs.MD5.Result();
3c54407f 1071 if (DoSHA1 == true)
8c4e1f97 1072 CheckSums[NewFileName].SHA1 = hs.SHA1.Result();
3c54407f 1073 if (DoSHA256 == true)
8c4e1f97 1074 CheckSums[NewFileName].SHA256 = hs.SHA256.Result();
9abccf4a 1075 if (DoSHA512 == true)
8c4e1f97 1076 CheckSums[NewFileName].SHA512 = hs.SHA512.Result();
98953965 1077 fd.Close();
8c4e1f97 1078
98953965
AL
1079 return true;
1080}
f7291f62
AL
1081
1082 /*}}}*/
1083// ReleaseWriter::Finish - Output the checksums /*{{{*/
1084// ---------------------------------------------------------------------
1085void ReleaseWriter::Finish()
1086{
3c54407f 1087 if (DoMD5 == true)
f7291f62 1088 {
3c54407f
DK
1089 fprintf(Output, "MD5Sum:\n");
1090 for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
1091 I != CheckSums.end(); ++I)
1092 {
650faab0 1093 fprintf(Output, " %s %16llu %s\n",
3c54407f
DK
1094 (*I).second.MD5.c_str(),
1095 (*I).second.size,
1096 (*I).first.c_str());
1097 }
f7291f62 1098 }
3c54407f 1099 if (DoSHA1 == true)
f7291f62 1100 {
3c54407f
DK
1101 fprintf(Output, "SHA1:\n");
1102 for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
1103 I != CheckSums.end(); ++I)
1104 {
650faab0 1105 fprintf(Output, " %s %16llu %s\n",
3c54407f
DK
1106 (*I).second.SHA1.c_str(),
1107 (*I).second.size,
1108 (*I).first.c_str());
1109 }
f7291f62 1110 }
3c54407f 1111 if (DoSHA256 == true)
cde41ae8 1112 {
3c54407f
DK
1113 fprintf(Output, "SHA256:\n");
1114 for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
1115 I != CheckSums.end(); ++I)
1116 {
650faab0 1117 fprintf(Output, " %s %16llu %s\n",
3c54407f
DK
1118 (*I).second.SHA256.c_str(),
1119 (*I).second.size,
1120 (*I).first.c_str());
1121 }
cde41ae8 1122 }
9a961efc
MV
1123
1124 fprintf(Output, "SHA512:\n");
1125 for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
1126 I != CheckSums.end();
1127 ++I)
1128 {
650faab0 1129 fprintf(Output, " %s %16llu %s\n",
9a961efc
MV
1130 (*I).second.SHA512.c_str(),
1131 (*I).second.size,
1132 (*I).first.c_str());
1133 }
1134
f7291f62 1135}