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