]> git.saurik.com Git - apt.git/blame - ftparchive/writer.cc
releasing package apt version 1.0.5
[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
ce928105
MV
388 if (Db.GetFileInfo(FileName,
389 true, /* DoControl */
390 DoContents,
391 true, /* GenContentsOnly */
392 false, /* DoSource */
393 DoMD5, DoSHA1, DoSHA256, DoSHA512, DoAlwaysStat) == false)
cde41ae8 394 {
ce928105 395 return false;
cde41ae8 396 }
b2e465d6 397
650faab0 398 unsigned long long FileSize = Db.GetFileSize();
cde41ae8 399 if (Delink(FileName,OriginalPath,Stats.DeLinkBytes,FileSize) == false)
b2e465d6
AL
400 return false;
401
402 // Lookup the overide information
403 pkgTagSection &Tags = Db.Control.Section;
404 string Package = Tags.FindS("Package");
0b41e0e7
MV
405 string Architecture;
406 // if we generate a Packages file for a given arch, we use it to
407 // look for overrides. if we run in "simple" mode without the
408 // "Architecures" variable in the config we use the architecure value
409 // from the deb file
410 if(Arch != "")
411 Architecture = Arch;
412 else
413 Architecture = Tags.FindS("Architecture");
414 auto_ptr<Override::Item> OverItem(Over.GetItem(Package,Architecture));
b2e465d6
AL
415
416 if (Package.empty() == true)
dc738e7a 417 return _error->Error(_("Archive had no package field"));
0b41e0e7 418
b2e465d6 419 // If we need to do any rewriting of the header do it now..
0b41e0e7 420 if (OverItem.get() == 0)
b2e465d6
AL
421 {
422 if (NoOverride == false)
423 {
424 NewLine(1);
dc738e7a 425 ioprintf(c1out, _(" %s has no override entry\n"), Package.c_str());
b2e465d6
AL
426 }
427
0b41e0e7
MV
428 OverItem = auto_ptr<Override::Item>(new Override::Item);
429 OverItem->FieldOverride["Section"] = Tags.FindS("Section");
430 OverItem->Priority = Tags.FindS("Priority");
b2e465d6
AL
431 }
432
433 char Size[40];
650faab0 434 sprintf(Size,"%llu", (unsigned long long) FileSize);
b2e465d6
AL
435
436 // Strip the DirStrip prefix from the FileName and add the PathPrefix
437 string NewFileName;
438 if (DirStrip.empty() == false &&
439 FileName.length() > DirStrip.length() &&
440 stringcmp(FileName.begin(),FileName.begin() + DirStrip.length(),
441 DirStrip.begin(),DirStrip.end()) == 0)
442 NewFileName = string(FileName.begin() + DirStrip.length(),FileName.end());
443 else
444 NewFileName = FileName;
445 if (PathPrefix.empty() == false)
446 NewFileName = flCombine(PathPrefix,NewFileName);
9c24493f
DK
447
448 /* Configuration says we don't want to include the long Description
449 in the package file - instead we want to ship a separated file */
450 string desc;
451 if (LongDescription == false) {
452 desc = Tags.FindS("Description").append("\n");
453 OverItem->FieldOverride["Description"] = desc.substr(0, desc.find('\n')).c_str();
454 }
455
b2e465d6 456 // This lists all the changes to the fields we are going to make.
64177f17 457 // (7 hardcoded + maintainer + suggests + end marker)
9c24493f 458 TFRewriteData Changes[6+2+OverItem->FieldOverride.size()+1+1];
64177f17 459
b2e465d6 460 unsigned int End = 0;
64177f17 461 SetTFRewriteData(Changes[End++], "Size", Size);
3c54407f
DK
462 if (DoMD5 == true)
463 SetTFRewriteData(Changes[End++], "MD5sum", Db.MD5Res.c_str());
464 if (DoSHA1 == true)
465 SetTFRewriteData(Changes[End++], "SHA1", Db.SHA1Res.c_str());
466 if (DoSHA256 == true)
467 SetTFRewriteData(Changes[End++], "SHA256", Db.SHA256Res.c_str());
12cd178d
MV
468 if (DoSHA512 == true)
469 SetTFRewriteData(Changes[End++], "SHA512", Db.SHA512Res.c_str());
64177f17
AL
470 SetTFRewriteData(Changes[End++], "Filename", NewFileName.c_str());
471 SetTFRewriteData(Changes[End++], "Priority", OverItem->Priority.c_str());
472 SetTFRewriteData(Changes[End++], "Status", 0);
473 SetTFRewriteData(Changes[End++], "Optional", 0);
474
9c24493f
DK
475 string DescriptionMd5;
476 if (LongDescription == false) {
477 MD5Summation descmd5;
478 descmd5.Add(desc.c_str());
479 DescriptionMd5 = descmd5.Result().Value();
480 SetTFRewriteData(Changes[End++], "Description-md5", DescriptionMd5.c_str());
66905344
DK
481 if (TransWriter != NULL)
482 TransWriter->DoPackage(Package, desc, DescriptionMd5);
9c24493f
DK
483 }
484
b2e465d6
AL
485 // Rewrite the maintainer field if necessary
486 bool MaintFailed;
487 string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
488 if (MaintFailed == true)
489 {
490 if (NoOverride == false)
491 {
492 NewLine(1);
dc738e7a
AL
493 ioprintf(c1out, _(" %s maintainer is %s not %s\n"),
494 Package.c_str(), Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
b2e465d6
AL
495 }
496 }
497
498 if (NewMaint.empty() == false)
64177f17 499 SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
b2e465d6
AL
500
501 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
c6474fb6 502 dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
b2e465d6
AL
503 but dpkg does this append bit. So we do the append bit, at least that way the
504 status file and package file will remain similar. There are other transforms
505 but optional is the only legacy one still in use for some lazy reason. */
506 string OptionalStr = Tags.FindS("Optional");
507 if (OptionalStr.empty() == false)
508 {
509 if (Tags.FindS("Suggests").empty() == false)
510 OptionalStr = Tags.FindS("Suggests") + ", " + OptionalStr;
64177f17 511 SetTFRewriteData(Changes[End++], "Suggests", OptionalStr.c_str());
b2e465d6 512 }
64177f17 513
9209ec47 514 for (map<string,string>::const_iterator I = OverItem->FieldOverride.begin();
f7f0d6c7 515 I != OverItem->FieldOverride.end(); ++I)
64177f17
AL
516 SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
517
518 SetTFRewriteData(Changes[End++], 0, 0);
519
b2e465d6
AL
520 // Rewrite and store the fields.
521 if (TFRewrite(Output,Tags,TFRewritePackageOrder,Changes) == false)
522 return false;
523 fprintf(Output,"\n");
524
525 return Db.Finish();
526}
527 /*}}}*/
528
66905344
DK
529// TranslationWriter::TranslationWriter - Constructor /*{{{*/
530// ---------------------------------------------------------------------
531/* Create a Translation-Master file for this Packages file */
34f1d96c
DK
532TranslationWriter::TranslationWriter(string const &File, string const &TransCompress,
533 mode_t const &Permissions) : Output(NULL),
66905344
DK
534 RefCounter(0)
535{
536 if (File.empty() == true)
537 return;
538
34f1d96c
DK
539 Comp = new MultiCompress(File, TransCompress, Permissions);
540 Output = Comp->Input;
66905344
DK
541}
542 /*}}}*/
543// TranslationWriter::DoPackage - Process a single package /*{{{*/
544// ---------------------------------------------------------------------
545/* Create a Translation-Master file for this Packages file */
546bool TranslationWriter::DoPackage(string const &Pkg, string const &Desc,
547 string const &MD5)
548{
549 if (Output == NULL)
550 return true;
551
552 // Different archs can include different versions and therefore
553 // different descriptions - so we need to check for both name and md5.
554 string const Record = Pkg + ":" + MD5;
555
556 if (Included.find(Record) != Included.end())
557 return true;
558
559 fprintf(Output, "Package: %s\nDescription-md5: %s\nDescription-en: %s\n",
560 Pkg.c_str(), MD5.c_str(), Desc.c_str());
561
562 Included.insert(Record);
563 return true;
564}
565 /*}}}*/
566// TranslationWriter::~TranslationWriter - Destructor /*{{{*/
567// ---------------------------------------------------------------------
568/* */
569TranslationWriter::~TranslationWriter()
570{
34f1d96c
DK
571 if (Comp == NULL)
572 return;
573
574 delete Comp;
66905344
DK
575}
576 /*}}}*/
577
b2e465d6
AL
578// SourcesWriter::SourcesWriter - Constructor /*{{{*/
579// ---------------------------------------------------------------------
580/* */
f6f06a8f
MV
581SourcesWriter::SourcesWriter(string const &DB, string const &BOverrides,string const &SOverrides,
582 string const &ExtOverrides) :
583 Db(DB), Stats(Db.Stats)
b2e465d6
AL
584{
585 Output = stdout;
98953965 586 AddPattern("*.dsc");
b2e465d6
AL
587 DeLinkLimit = 0;
588 Buffer = 0;
589 BufSize = 0;
590
591 // Process the command line options
3c54407f
DK
592 DoMD5 = _config->FindB("APT::FTPArchive::Sources::MD5",DoMD5);
593 DoSHA1 = _config->FindB("APT::FTPArchive::Sources::SHA1",DoSHA1);
594 DoSHA256 = _config->FindB("APT::FTPArchive::Sources::SHA256",DoSHA256);
f6f06a8f 595 DoSHA512 = _config->FindB("APT::FTPArchive::Sources::SHA512",DoSHA512);
b2e465d6 596 NoOverride = _config->FindB("APT::FTPArchive::NoOverrideMsg",false);
f6f06a8f 597 DoAlwaysStat = _config->FindB("APT::FTPArchive::AlwaysStat", false);
b2e465d6
AL
598
599 // Read the override file
600 if (BOverrides.empty() == false && BOver.ReadOverride(BOverrides) == false)
601 return;
602 else
603 NoOverride = true;
64177f17 604
cde41ae8
MV
605 // WTF?? The logic above: if we can't read binary overrides, don't even try
606 // reading source overrides. if we can read binary overrides, then say there
607 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
608
64177f17
AL
609 if (ExtOverrides.empty() == false)
610 SOver.ReadExtraOverride(ExtOverrides);
b2e465d6 611
64177f17
AL
612 if (SOverrides.empty() == false && FileExists(SOverrides) == true)
613 SOver.ReadOverride(SOverrides,true);
b2e465d6
AL
614}
615 /*}}}*/
616// SourcesWriter::DoPackage - Process a single package /*{{{*/
617// ---------------------------------------------------------------------
618/* */
619bool SourcesWriter::DoPackage(string FileName)
f1828b69 620{
ce928105
MV
621 // Pull all the data we need form the DB
622 if (Db.GetFileInfo(FileName,
623 false, /* DoControl */
624 false, /* DoContents */
625 false, /* GenContentsOnly */
626 true, /* DoSource */
627 DoMD5, DoSHA1, DoSHA256, DoSHA512, DoAlwaysStat) == false)
b2e465d6 628 {
b2e465d6 629 return false;
ce928105 630 }
b2e465d6 631
ce928105
MV
632 // we need to perform a "write" here (this is what finish is doing)
633 // because the call to Db.GetFileInfo() in the loop will change
634 // the "db cursor"
635 Db.Finish();
f1828b69 636
ce928105
MV
637 // read stuff
638 char *Start = Db.Dsc.Data;
639 char *BlkEnd = Db.Dsc.Data + Db.Dsc.Length;
f1828b69
DK
640
641 // Add extra \n to the end, just in case (as in clearsigned they are missing)
642 *BlkEnd++ = '\n';
643 *BlkEnd++ = '\n';
644
645 pkgTagSection Tags;
ce928105 646 if (Tags.Scan(Start,BlkEnd - Start) == false)
f1828b69 647 return _error->Error("Could not find a record in the DSC '%s'",FileName.c_str());
ce928105
MV
648
649 if (Tags.Exists("Source") == false)
650 return _error->Error("Could not find a Source entry in the DSC '%s'",FileName.c_str());
b2e465d6 651 Tags.Trim();
f1828b69 652
b2e465d6
AL
653 // Lookup the overide information, finding first the best priority.
654 string BestPrio;
b2e465d6 655 string Bins = Tags.FindS("Binary");
5200ec6f 656 char Buffer[Bins.length() + 1];
0b41e0e7 657 auto_ptr<Override::Item> OverItem(0);
5200ec6f 658 if (Bins.empty() == false)
b2e465d6
AL
659 {
660 strcpy(Buffer,Bins.c_str());
661
662 // Ignore too-long errors.
663 char *BinList[400];
664 TokSplitString(',',Buffer,BinList,sizeof(BinList)/sizeof(BinList[0]));
665
666 // Look at all the binaries
667 unsigned char BestPrioV = pkgCache::State::Extra;
668 for (unsigned I = 0; BinList[I] != 0; I++)
669 {
0b41e0e7
MV
670 auto_ptr<Override::Item> Itm(BOver.GetItem(BinList[I]));
671 if (Itm.get() == 0)
b2e465d6 672 continue;
b2e465d6
AL
673
674 unsigned char NewPrioV = debListParser::GetPrio(Itm->Priority);
675 if (NewPrioV < BestPrioV || BestPrio.empty() == true)
676 {
677 BestPrioV = NewPrioV;
678 BestPrio = Itm->Priority;
679 }
7524e348
MV
680
681 if (OverItem.get() == 0)
682 OverItem = Itm;
b2e465d6
AL
683 }
684 }
685
686 // If we need to do any rewriting of the header do it now..
0b41e0e7 687 if (OverItem.get() == 0)
b2e465d6
AL
688 {
689 if (NoOverride == false)
690 {
691 NewLine(1);
dc738e7a 692 ioprintf(c1out, _(" %s has no override entry\n"), Tags.FindS("Source").c_str());
b2e465d6
AL
693 }
694
0b41e0e7 695 OverItem = auto_ptr<Override::Item>(new Override::Item);
b2e465d6
AL
696 }
697
ce928105
MV
698 struct stat St;
699 if (stat(FileName.c_str(), &St) != 0)
700 return _error->Errno("fstat","Failed to stat %s",FileName.c_str());
701
0b41e0e7 702 auto_ptr<Override::Item> SOverItem(SOver.GetItem(Tags.FindS("Source")));
cde41ae8 703 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
0b41e0e7 704 if (SOverItem.get() == 0)
b2e465d6 705 {
cde41ae8 706 ioprintf(c1out, _(" %s has no source override entry\n"), Tags.FindS("Source").c_str());
0b41e0e7
MV
707 SOverItem = auto_ptr<Override::Item>(BOver.GetItem(Tags.FindS("Source")));
708 if (SOverItem.get() == 0)
709 {
cde41ae8 710 ioprintf(c1out, _(" %s has no binary override entry either\n"), Tags.FindS("Source").c_str());
0b41e0e7
MV
711 SOverItem = auto_ptr<Override::Item>(new Override::Item);
712 *SOverItem = *OverItem;
713 }
b2e465d6
AL
714 }
715
716 // Add the dsc to the files hash list
f99da908 717 string const strippedName = flNotDir(FileName);
bf99a6d3 718 std::ostringstream ostreamFiles;
3c54407f 719 if (DoMD5 == true && Tags.Exists("Files"))
ce928105 720 ostreamFiles << "\n " << Db.MD5Res.c_str() << " " << St.st_size << " "
2a19ec29 721 << strippedName << "\n " << Tags.FindS("Files");
bf99a6d3
DK
722 string const Files = ostreamFiles.str();
723
724 std::ostringstream ostreamSha1;
3c54407f 725 if (DoSHA1 == true && Tags.Exists("Checksums-Sha1"))
ce928105 726 ostreamSha1 << "\n " << string(Db.SHA1Res.c_str()) << " " << St.st_size << " "
2a19ec29 727 << strippedName << "\n " << Tags.FindS("Checksums-Sha1");
bf99a6d3
DK
728
729 std::ostringstream ostreamSha256;
3c54407f 730 if (DoSHA256 == true && Tags.Exists("Checksums-Sha256"))
ce928105 731 ostreamSha256 << "\n " << string(Db.SHA256Res.c_str()) << " " << St.st_size << " "
2a19ec29 732 << strippedName << "\n " << Tags.FindS("Checksums-Sha256");
f99da908 733
9a961efc 734 std::ostringstream ostreamSha512;
f6f06a8f 735 if (DoSHA512 == true && Tags.Exists("Checksums-Sha512"))
ce928105 736 ostreamSha512 << "\n " << string(Db.SHA512Res.c_str()) << " " << St.st_size << " "
9a961efc 737 << strippedName << "\n " << Tags.FindS("Checksums-Sha512");
9a961efc 738
b2e465d6
AL
739 // Strip the DirStrip prefix from the FileName and add the PathPrefix
740 string NewFileName;
741 if (DirStrip.empty() == false &&
742 FileName.length() > DirStrip.length() &&
8c58f506 743 stringcmp(DirStrip,OriginalPath,OriginalPath + DirStrip.length()) == 0)
b2e465d6
AL
744 NewFileName = string(OriginalPath + DirStrip.length());
745 else
746 NewFileName = OriginalPath;
747 if (PathPrefix.empty() == false)
748 NewFileName = flCombine(PathPrefix,NewFileName);
171c45bc 749
b2e465d6
AL
750 string Directory = flNotFile(OriginalPath);
751 string Package = Tags.FindS("Source");
171c45bc 752
f6f06a8f 753 // Perform operation over all of the files
b2e465d6 754 string ParseJnk;
bf99a6d3 755 const char *C = Files.c_str();
ab3846c0 756 char *RealPath = NULL;
b2e465d6
AL
757 for (;isspace(*C); C++);
758 while (*C != 0)
759 {
760 // Parse each of the elements
761 if (ParseQuoteWord(C,ParseJnk) == false ||
762 ParseQuoteWord(C,ParseJnk) == false ||
763 ParseQuoteWord(C,ParseJnk) == false)
764 return _error->Error("Error parsing file record");
f6f06a8f 765
b2e465d6 766 string OriginalPath = Directory + ParseJnk;
f6f06a8f
MV
767
768 // Add missing hashes to source files
769 if ((DoSHA1 == true && !Tags.Exists("Checksums-Sha1")) ||
770 (DoSHA256 == true && !Tags.Exists("Checksums-Sha256")) ||
771 (DoSHA512 == true && !Tags.Exists("Checksums-Sha512")))
772 {
ce928105
MV
773 if (Db.GetFileInfo(OriginalPath,
774 false, /* DoControl */
775 false, /* DoContents */
776 false, /* GenContentsOnly */
777 false, /* DoSource */
778 DoMD5, DoSHA1, DoSHA256, DoSHA512,
779 DoAlwaysStat) == false)
f6f06a8f
MV
780 {
781 return _error->Error("Error getting file info");
782 }
783
784 if (DoSHA1 == true && !Tags.Exists("Checksums-Sha1"))
785 ostreamSha1 << "\n " << string(Db.SHA1Res) << " "
786 << Db.GetFileSize() << " " << ParseJnk;
787
788 if (DoSHA256 == true && !Tags.Exists("Checksums-Sha256"))
789 ostreamSha256 << "\n " << string(Db.SHA256Res) << " "
790 << Db.GetFileSize() << " " << ParseJnk;
791
792 if (DoSHA512 == true && !Tags.Exists("Checksums-Sha512"))
793 ostreamSha512 << "\n " << string(Db.SHA512Res) << " "
794 << Db.GetFileSize() << " " << ParseJnk;
ce928105
MV
795
796 // write back the GetFileInfo() stats data
797 Db.Finish();
f6f06a8f
MV
798 }
799
800 // Perform the delinking operation
801 char Jnk[2];
802
ab3846c0
MV
803 if (readlink(OriginalPath.c_str(),Jnk,sizeof(Jnk)) != -1 &&
804 (RealPath = realpath(OriginalPath.c_str(),NULL)) != 0)
b2e465d6
AL
805 {
806 string RP = RealPath;
ab3846c0 807 free(RealPath);
cde41ae8 808 if (Delink(RP,OriginalPath.c_str(),Stats.DeLinkBytes,St.st_size) == false)
b2e465d6
AL
809 return false;
810 }
811 }
812
813 Directory = flNotFile(NewFileName);
814 if (Directory.length() > 2)
815 Directory.erase(Directory.end()-1);
171c45bc 816
f6f06a8f
MV
817 string const ChecksumsSha1 = ostreamSha1.str();
818 string const ChecksumsSha256 = ostreamSha256.str();
819 string const ChecksumsSha512 = ostreamSha512.str();
820
b2e465d6 821 // This lists all the changes to the fields we are going to make.
f99da908
DK
822 // (5 hardcoded + checksums + maintainer + end marker)
823 TFRewriteData Changes[5+2+1+SOverItem->FieldOverride.size()+1];
64177f17 824
b2e465d6 825 unsigned int End = 0;
64177f17 826 SetTFRewriteData(Changes[End++],"Source",Package.c_str(),"Package");
3c54407f
DK
827 if (Files.empty() == false)
828 SetTFRewriteData(Changes[End++],"Files",Files.c_str());
829 if (ChecksumsSha1.empty() == false)
830 SetTFRewriteData(Changes[End++],"Checksums-Sha1",ChecksumsSha1.c_str());
831 if (ChecksumsSha256.empty() == false)
832 SetTFRewriteData(Changes[End++],"Checksums-Sha256",ChecksumsSha256.c_str());
12cd178d
MV
833 if (ChecksumsSha512.empty() == false)
834 SetTFRewriteData(Changes[End++],"Checksums-Sha512",ChecksumsSha512.c_str());
171c45bc
AL
835 if (Directory != "./")
836 SetTFRewriteData(Changes[End++],"Directory",Directory.c_str());
64177f17
AL
837 SetTFRewriteData(Changes[End++],"Priority",BestPrio.c_str());
838 SetTFRewriteData(Changes[End++],"Status",0);
b2e465d6
AL
839
840 // Rewrite the maintainer field if necessary
841 bool MaintFailed;
842 string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
843 if (MaintFailed == true)
844 {
845 if (NoOverride == false)
846 {
847 NewLine(1);
dc738e7a
AL
848 ioprintf(c1out, _(" %s maintainer is %s not %s\n"), Package.c_str(),
849 Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
b2e465d6
AL
850 }
851 }
852 if (NewMaint.empty() == false)
64177f17
AL
853 SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
854
9209ec47 855 for (map<string,string>::const_iterator I = SOverItem->FieldOverride.begin();
f7f0d6c7 856 I != SOverItem->FieldOverride.end(); ++I)
64177f17
AL
857 SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
858
859 SetTFRewriteData(Changes[End++], 0, 0);
b2e465d6
AL
860
861 // Rewrite and store the fields.
862 if (TFRewrite(Output,Tags,TFRewriteSourceOrder,Changes) == false)
863 return false;
864 fprintf(Output,"\n");
865
866 Stats.Packages++;
867
ce928105 868 return true;
b2e465d6
AL
869}
870 /*}}}*/
871
872// ContentsWriter::ContentsWriter - Constructor /*{{{*/
873// ---------------------------------------------------------------------
874/* */
31981076
DK
875ContentsWriter::ContentsWriter(string const &DB, string const &Arch) :
876 FTWScanner(Arch), Db(DB), Stats(Db.Stats)
b2e465d6
AL
877
878{
31981076 879 SetExts(".deb");
b2e465d6
AL
880 Output = stdout;
881}
882 /*}}}*/
883// ContentsWriter::DoPackage - Process a single package /*{{{*/
884// ---------------------------------------------------------------------
885/* If Package is the empty string the control record will be parsed to
886 determine what the package name is. */
9209ec47 887bool ContentsWriter::DoPackage(string FileName, string Package)
b2e465d6 888{
ce928105
MV
889 if (!Db.GetFileInfo(FileName,
890 Package.empty(), /* DoControl */
891 true, /* DoContents */
892 false, /* GenContentsOnly */
893 false, /* DoSource */
894 false, /* DoMD5 */
895 false, /* DoSHA1 */
896 false, /* DoSHA256 */
897 false)) /* DoSHA512 */
cde41ae8 898 {
b2e465d6 899 return false;
cde41ae8 900 }
b2e465d6
AL
901
902 // Parse the package name
903 if (Package.empty() == true)
904 {
b2e465d6
AL
905 Package = Db.Control.Section.FindS("Package");
906 }
907
908 Db.Contents.Add(Gen,Package);
909
910 return Db.Finish();
911}
912 /*}}}*/
913// ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
914// ---------------------------------------------------------------------
915/* */
9209ec47 916bool ContentsWriter::ReadFromPkgs(string const &PkgFile,string const &PkgCompress)
b2e465d6
AL
917{
918 MultiCompress Pkgs(PkgFile,PkgCompress,0,false);
919 if (_error->PendingError() == true)
920 return false;
12d1f5b3 921
b2e465d6 922 // Open the package file
12d1f5b3
DK
923 FileFd Fd;
924 if (Pkgs.OpenOld(Fd) == false)
b2e465d6 925 return false;
12d1f5b3 926
b2e465d6
AL
927 pkgTagFile Tags(&Fd);
928 if (_error->PendingError() == true)
b2e465d6 929 return false;
12d1f5b3 930
b2e465d6
AL
931 // Parse.
932 pkgTagSection Section;
933 while (Tags.Step(Section) == true)
934 {
935 string File = flCombine(Prefix,Section.FindS("FileName"));
936 string Package = Section.FindS("Section");
937 if (Package.empty() == false && Package.end()[-1] != '/')
938 {
939 Package += '/';
940 Package += Section.FindS("Package");
941 }
942 else
943 Package += Section.FindS("Package");
944
945 DoPackage(File,Package);
946 if (_error->empty() == false)
947 {
948 _error->Error("Errors apply to file '%s'",File.c_str());
949 _error->DumpErrors();
950 }
951 }
12d1f5b3 952
b2e465d6 953 // Tidy the compressor
12d1f5b3
DK
954 Fd.Close();
955
b2e465d6
AL
956 return true;
957}
98953965 958
b2e465d6 959 /*}}}*/
98953965
AL
960
961// ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
962// ---------------------------------------------------------------------
963/* */
65512241 964ReleaseWriter::ReleaseWriter(string const &/*DB*/)
98953965 965{
3cb3fe76
DK
966 if (_config->FindB("APT::FTPArchive::Release::Default-Patterns", true) == true)
967 {
968 AddPattern("Packages");
969 AddPattern("Packages.gz");
970 AddPattern("Packages.bz2");
971 AddPattern("Packages.lzma");
b7080ced 972 AddPattern("Packages.xz");
8e3900d0 973 AddPattern("Translation-*");
3cb3fe76
DK
974 AddPattern("Sources");
975 AddPattern("Sources.gz");
976 AddPattern("Sources.bz2");
977 AddPattern("Sources.lzma");
b7080ced 978 AddPattern("Sources.xz");
3cb3fe76 979 AddPattern("Release");
0baf849d 980 AddPattern("Contents-*");
8d16c617 981 AddPattern("Index");
3cb3fe76
DK
982 AddPattern("md5sum.txt");
983 }
984 AddPatterns(_config->FindVector("APT::FTPArchive::Release::Patterns"));
187492a6 985
98953965 986 Output = stdout;
9209ec47 987 time_t const now = time(NULL);
cb12d0a6
DK
988
989 setlocale(LC_TIME, "C");
990
98953965
AL
991 char datestr[128];
992 if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S UTC",
993 gmtime(&now)) == 0)
994 {
995 datestr[0] = '\0';
996 }
997
c99e48ec 998 time_t const validuntil = now + _config->FindI("APT::FTPArchive::Release::ValidTime", 0);
cdb623ed 999 char validstr[128];
c99e48ec
DK
1000 if (now == validuntil ||
1001 strftime(validstr, sizeof(validstr), "%a, %d %b %Y %H:%M:%S UTC",
1002 gmtime(&validuntil)) == 0)
1003 {
cdb623ed 1004 validstr[0] = '\0';
c99e48ec
DK
1005 }
1006
cb12d0a6
DK
1007 setlocale(LC_TIME, "");
1008
98953965
AL
1009 map<string,string> Fields;
1010 Fields["Origin"] = "";
1011 Fields["Label"] = "";
1012 Fields["Suite"] = "";
1013 Fields["Version"] = "";
1014 Fields["Codename"] = "";
1015 Fields["Date"] = datestr;
c99e48ec 1016 Fields["Valid-Until"] = validstr;
98953965
AL
1017 Fields["Architectures"] = "";
1018 Fields["Components"] = "";
1019 Fields["Description"] = "";
1020
1021 for(map<string,string>::const_iterator I = Fields.begin();
1022 I != Fields.end();
1023 ++I)
1024 {
1025 string Config = string("APT::FTPArchive::Release::") + (*I).first;
1026 string Value = _config->Find(Config, (*I).second.c_str());
1027 if (Value == "")
1028 continue;
1029
1030 fprintf(Output, "%s: %s\n", (*I).first.c_str(), Value.c_str());
1031 }
3c54407f
DK
1032
1033 DoMD5 = _config->FindB("APT::FTPArchive::Release::MD5",DoMD5);
1034 DoSHA1 = _config->FindB("APT::FTPArchive::Release::SHA1",DoSHA1);
1035 DoSHA256 = _config->FindB("APT::FTPArchive::Release::SHA256",DoSHA256);
98953965
AL
1036}
1037 /*}}}*/
1038// ReleaseWriter::DoPackage - Process a single package /*{{{*/
1039// ---------------------------------------------------------------------
1040bool ReleaseWriter::DoPackage(string FileName)
1041{
1042 // Strip the DirStrip prefix from the FileName and add the PathPrefix
1043 string NewFileName;
1044 if (DirStrip.empty() == false &&
1045 FileName.length() > DirStrip.length() &&
1046 stringcmp(FileName.begin(),FileName.begin() + DirStrip.length(),
1047 DirStrip.begin(),DirStrip.end()) == 0)
c0eb6bc6 1048 {
98953965 1049 NewFileName = string(FileName.begin() + DirStrip.length(),FileName.end());
c0eb6bc6 1050 while (NewFileName[0] == '/')
9202409d 1051 NewFileName = string(NewFileName.begin() + 1,NewFileName.end());
c0eb6bc6 1052 }
98953965
AL
1053 else
1054 NewFileName = FileName;
c0eb6bc6 1055
98953965
AL
1056 if (PathPrefix.empty() == false)
1057 NewFileName = flCombine(PathPrefix,NewFileName);
1058
1059 FileFd fd(FileName, FileFd::ReadOnly);
1060
1061 if (!fd.IsOpen())
1062 {
1063 return false;
1064 }
1065
c0eb6bc6 1066 CheckSums[NewFileName].size = fd.Size();
f7291f62 1067
8c4e1f97 1068 Hashes hs;
109eb151 1069 hs.AddFD(fd, 0, DoMD5, DoSHA1, DoSHA256, DoSHA512);
3c54407f 1070 if (DoMD5 == true)
8c4e1f97 1071 CheckSums[NewFileName].MD5 = hs.MD5.Result();
3c54407f 1072 if (DoSHA1 == true)
8c4e1f97 1073 CheckSums[NewFileName].SHA1 = hs.SHA1.Result();
3c54407f 1074 if (DoSHA256 == true)
8c4e1f97 1075 CheckSums[NewFileName].SHA256 = hs.SHA256.Result();
9abccf4a 1076 if (DoSHA512 == true)
8c4e1f97 1077 CheckSums[NewFileName].SHA512 = hs.SHA512.Result();
98953965 1078 fd.Close();
8c4e1f97 1079
98953965
AL
1080 return true;
1081}
f7291f62
AL
1082
1083 /*}}}*/
1084// ReleaseWriter::Finish - Output the checksums /*{{{*/
1085// ---------------------------------------------------------------------
1086void ReleaseWriter::Finish()
1087{
3c54407f 1088 if (DoMD5 == true)
f7291f62 1089 {
3c54407f
DK
1090 fprintf(Output, "MD5Sum:\n");
1091 for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
1092 I != CheckSums.end(); ++I)
1093 {
650faab0 1094 fprintf(Output, " %s %16llu %s\n",
3c54407f
DK
1095 (*I).second.MD5.c_str(),
1096 (*I).second.size,
1097 (*I).first.c_str());
1098 }
f7291f62 1099 }
3c54407f 1100 if (DoSHA1 == true)
f7291f62 1101 {
3c54407f
DK
1102 fprintf(Output, "SHA1:\n");
1103 for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
1104 I != CheckSums.end(); ++I)
1105 {
650faab0 1106 fprintf(Output, " %s %16llu %s\n",
3c54407f
DK
1107 (*I).second.SHA1.c_str(),
1108 (*I).second.size,
1109 (*I).first.c_str());
1110 }
f7291f62 1111 }
3c54407f 1112 if (DoSHA256 == true)
cde41ae8 1113 {
3c54407f
DK
1114 fprintf(Output, "SHA256:\n");
1115 for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
1116 I != CheckSums.end(); ++I)
1117 {
650faab0 1118 fprintf(Output, " %s %16llu %s\n",
3c54407f
DK
1119 (*I).second.SHA256.c_str(),
1120 (*I).second.size,
1121 (*I).first.c_str());
1122 }
cde41ae8 1123 }
9a961efc
MV
1124
1125 fprintf(Output, "SHA512:\n");
1126 for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
1127 I != CheckSums.end();
1128 ++I)
1129 {
650faab0 1130 fprintf(Output, " %s %16llu %s\n",
9a961efc
MV
1131 (*I).second.SHA512.c_str(),
1132 (*I).second.size,
1133 (*I).first.c_str());
1134 }
1135
f7291f62 1136}