128 KiB DSC files ought to be enough for everyone
[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 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
f1828b69 637 pkgTagSection Tags;
31be38d2 638 if (Tags.Scan(Db.Dsc.Data.c_str(), Db.Dsc.Data.length()) == false)
f1828b69 639 return _error->Error("Could not find a record in the DSC '%s'",FileName.c_str());
31be38d2 640
ce928105
MV
641 if (Tags.Exists("Source") == false)
642 return _error->Error("Could not find a Source entry in the DSC '%s'",FileName.c_str());
b2e465d6 643 Tags.Trim();
f1828b69 644
b2e465d6
AL
645 // Lookup the overide information, finding first the best priority.
646 string BestPrio;
b2e465d6 647 string Bins = Tags.FindS("Binary");
5200ec6f 648 char Buffer[Bins.length() + 1];
0b41e0e7 649 auto_ptr<Override::Item> OverItem(0);
5200ec6f 650 if (Bins.empty() == false)
b2e465d6
AL
651 {
652 strcpy(Buffer,Bins.c_str());
653
654 // Ignore too-long errors.
655 char *BinList[400];
656 TokSplitString(',',Buffer,BinList,sizeof(BinList)/sizeof(BinList[0]));
657
658 // Look at all the binaries
659 unsigned char BestPrioV = pkgCache::State::Extra;
660 for (unsigned I = 0; BinList[I] != 0; I++)
661 {
0b41e0e7
MV
662 auto_ptr<Override::Item> Itm(BOver.GetItem(BinList[I]));
663 if (Itm.get() == 0)
b2e465d6 664 continue;
b2e465d6
AL
665
666 unsigned char NewPrioV = debListParser::GetPrio(Itm->Priority);
667 if (NewPrioV < BestPrioV || BestPrio.empty() == true)
668 {
669 BestPrioV = NewPrioV;
670 BestPrio = Itm->Priority;
671 }
7524e348
MV
672
673 if (OverItem.get() == 0)
674 OverItem = Itm;
b2e465d6
AL
675 }
676 }
677
678 // If we need to do any rewriting of the header do it now..
0b41e0e7 679 if (OverItem.get() == 0)
b2e465d6
AL
680 {
681 if (NoOverride == false)
682 {
683 NewLine(1);
dc738e7a 684 ioprintf(c1out, _(" %s has no override entry\n"), Tags.FindS("Source").c_str());
b2e465d6
AL
685 }
686
0b41e0e7 687 OverItem = auto_ptr<Override::Item>(new Override::Item);
b2e465d6
AL
688 }
689
ce928105
MV
690 struct stat St;
691 if (stat(FileName.c_str(), &St) != 0)
692 return _error->Errno("fstat","Failed to stat %s",FileName.c_str());
693
0b41e0e7 694 auto_ptr<Override::Item> SOverItem(SOver.GetItem(Tags.FindS("Source")));
cde41ae8 695 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
0b41e0e7 696 if (SOverItem.get() == 0)
b2e465d6 697 {
cde41ae8 698 ioprintf(c1out, _(" %s has no source override entry\n"), Tags.FindS("Source").c_str());
0b41e0e7
MV
699 SOverItem = auto_ptr<Override::Item>(BOver.GetItem(Tags.FindS("Source")));
700 if (SOverItem.get() == 0)
701 {
cde41ae8 702 ioprintf(c1out, _(" %s has no binary override entry either\n"), Tags.FindS("Source").c_str());
0b41e0e7
MV
703 SOverItem = auto_ptr<Override::Item>(new Override::Item);
704 *SOverItem = *OverItem;
705 }
b2e465d6
AL
706 }
707
708 // Add the dsc to the files hash list
f99da908 709 string const strippedName = flNotDir(FileName);
bf99a6d3 710 std::ostringstream ostreamFiles;
3c54407f 711 if (DoMD5 == true && Tags.Exists("Files"))
ce928105 712 ostreamFiles << "\n " << Db.MD5Res.c_str() << " " << St.st_size << " "
2a19ec29 713 << strippedName << "\n " << Tags.FindS("Files");
bf99a6d3
DK
714 string const Files = ostreamFiles.str();
715
716 std::ostringstream ostreamSha1;
3c54407f 717 if (DoSHA1 == true && Tags.Exists("Checksums-Sha1"))
ce928105 718 ostreamSha1 << "\n " << string(Db.SHA1Res.c_str()) << " " << St.st_size << " "
2a19ec29 719 << strippedName << "\n " << Tags.FindS("Checksums-Sha1");
bf99a6d3
DK
720
721 std::ostringstream ostreamSha256;
3c54407f 722 if (DoSHA256 == true && Tags.Exists("Checksums-Sha256"))
ce928105 723 ostreamSha256 << "\n " << string(Db.SHA256Res.c_str()) << " " << St.st_size << " "
2a19ec29 724 << strippedName << "\n " << Tags.FindS("Checksums-Sha256");
f99da908 725
9a961efc 726 std::ostringstream ostreamSha512;
f6f06a8f 727 if (DoSHA512 == true && Tags.Exists("Checksums-Sha512"))
ce928105 728 ostreamSha512 << "\n " << string(Db.SHA512Res.c_str()) << " " << St.st_size << " "
9a961efc 729 << strippedName << "\n " << Tags.FindS("Checksums-Sha512");
9a961efc 730
b2e465d6
AL
731 // Strip the DirStrip prefix from the FileName and add the PathPrefix
732 string NewFileName;
733 if (DirStrip.empty() == false &&
734 FileName.length() > DirStrip.length() &&
8c58f506 735 stringcmp(DirStrip,OriginalPath,OriginalPath + DirStrip.length()) == 0)
b2e465d6
AL
736 NewFileName = string(OriginalPath + DirStrip.length());
737 else
738 NewFileName = OriginalPath;
739 if (PathPrefix.empty() == false)
740 NewFileName = flCombine(PathPrefix,NewFileName);
171c45bc 741
b2e465d6
AL
742 string Directory = flNotFile(OriginalPath);
743 string Package = Tags.FindS("Source");
171c45bc 744
f6f06a8f 745 // Perform operation over all of the files
b2e465d6 746 string ParseJnk;
bf99a6d3 747 const char *C = Files.c_str();
ab3846c0 748 char *RealPath = NULL;
b2e465d6
AL
749 for (;isspace(*C); C++);
750 while (*C != 0)
751 {
752 // Parse each of the elements
753 if (ParseQuoteWord(C,ParseJnk) == false ||
754 ParseQuoteWord(C,ParseJnk) == false ||
755 ParseQuoteWord(C,ParseJnk) == false)
756 return _error->Error("Error parsing file record");
f6f06a8f 757
b2e465d6 758 string OriginalPath = Directory + ParseJnk;
f6f06a8f
MV
759
760 // Add missing hashes to source files
761 if ((DoSHA1 == true && !Tags.Exists("Checksums-Sha1")) ||
762 (DoSHA256 == true && !Tags.Exists("Checksums-Sha256")) ||
763 (DoSHA512 == true && !Tags.Exists("Checksums-Sha512")))
764 {
ce928105
MV
765 if (Db.GetFileInfo(OriginalPath,
766 false, /* DoControl */
767 false, /* DoContents */
768 false, /* GenContentsOnly */
769 false, /* DoSource */
770 DoMD5, DoSHA1, DoSHA256, DoSHA512,
771 DoAlwaysStat) == false)
f6f06a8f
MV
772 {
773 return _error->Error("Error getting file info");
774 }
775
776 if (DoSHA1 == true && !Tags.Exists("Checksums-Sha1"))
777 ostreamSha1 << "\n " << string(Db.SHA1Res) << " "
778 << Db.GetFileSize() << " " << ParseJnk;
779
780 if (DoSHA256 == true && !Tags.Exists("Checksums-Sha256"))
781 ostreamSha256 << "\n " << string(Db.SHA256Res) << " "
782 << Db.GetFileSize() << " " << ParseJnk;
783
784 if (DoSHA512 == true && !Tags.Exists("Checksums-Sha512"))
785 ostreamSha512 << "\n " << string(Db.SHA512Res) << " "
786 << Db.GetFileSize() << " " << ParseJnk;
ce928105
MV
787
788 // write back the GetFileInfo() stats data
789 Db.Finish();
f6f06a8f
MV
790 }
791
792 // Perform the delinking operation
793 char Jnk[2];
794
ab3846c0
MV
795 if (readlink(OriginalPath.c_str(),Jnk,sizeof(Jnk)) != -1 &&
796 (RealPath = realpath(OriginalPath.c_str(),NULL)) != 0)
b2e465d6
AL
797 {
798 string RP = RealPath;
ab3846c0 799 free(RealPath);
cde41ae8 800 if (Delink(RP,OriginalPath.c_str(),Stats.DeLinkBytes,St.st_size) == false)
b2e465d6
AL
801 return false;
802 }
803 }
804
805 Directory = flNotFile(NewFileName);
806 if (Directory.length() > 2)
807 Directory.erase(Directory.end()-1);
171c45bc 808
f6f06a8f
MV
809 string const ChecksumsSha1 = ostreamSha1.str();
810 string const ChecksumsSha256 = ostreamSha256.str();
811 string const ChecksumsSha512 = ostreamSha512.str();
812
b2e465d6 813 // This lists all the changes to the fields we are going to make.
f99da908
DK
814 // (5 hardcoded + checksums + maintainer + end marker)
815 TFRewriteData Changes[5+2+1+SOverItem->FieldOverride.size()+1];
64177f17 816
b2e465d6 817 unsigned int End = 0;
64177f17 818 SetTFRewriteData(Changes[End++],"Source",Package.c_str(),"Package");
3c54407f
DK
819 if (Files.empty() == false)
820 SetTFRewriteData(Changes[End++],"Files",Files.c_str());
821 if (ChecksumsSha1.empty() == false)
822 SetTFRewriteData(Changes[End++],"Checksums-Sha1",ChecksumsSha1.c_str());
823 if (ChecksumsSha256.empty() == false)
824 SetTFRewriteData(Changes[End++],"Checksums-Sha256",ChecksumsSha256.c_str());
12cd178d
MV
825 if (ChecksumsSha512.empty() == false)
826 SetTFRewriteData(Changes[End++],"Checksums-Sha512",ChecksumsSha512.c_str());
171c45bc
AL
827 if (Directory != "./")
828 SetTFRewriteData(Changes[End++],"Directory",Directory.c_str());
64177f17
AL
829 SetTFRewriteData(Changes[End++],"Priority",BestPrio.c_str());
830 SetTFRewriteData(Changes[End++],"Status",0);
b2e465d6
AL
831
832 // Rewrite the maintainer field if necessary
833 bool MaintFailed;
834 string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
835 if (MaintFailed == true)
836 {
837 if (NoOverride == false)
838 {
839 NewLine(1);
dc738e7a
AL
840 ioprintf(c1out, _(" %s maintainer is %s not %s\n"), Package.c_str(),
841 Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
b2e465d6
AL
842 }
843 }
844 if (NewMaint.empty() == false)
64177f17
AL
845 SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
846
9209ec47 847 for (map<string,string>::const_iterator I = SOverItem->FieldOverride.begin();
f7f0d6c7 848 I != SOverItem->FieldOverride.end(); ++I)
64177f17
AL
849 SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
850
851 SetTFRewriteData(Changes[End++], 0, 0);
b2e465d6
AL
852
853 // Rewrite and store the fields.
854 if (TFRewrite(Output,Tags,TFRewriteSourceOrder,Changes) == false)
855 return false;
856 fprintf(Output,"\n");
857
858 Stats.Packages++;
859
ce928105 860 return true;
b2e465d6
AL
861}
862 /*}}}*/
863
864// ContentsWriter::ContentsWriter - Constructor /*{{{*/
865// ---------------------------------------------------------------------
866/* */
31981076
DK
867ContentsWriter::ContentsWriter(string const &DB, string const &Arch) :
868 FTWScanner(Arch), Db(DB), Stats(Db.Stats)
b2e465d6
AL
869
870{
31981076 871 SetExts(".deb");
b2e465d6
AL
872 Output = stdout;
873}
874 /*}}}*/
875// ContentsWriter::DoPackage - Process a single package /*{{{*/
876// ---------------------------------------------------------------------
877/* If Package is the empty string the control record will be parsed to
878 determine what the package name is. */
9209ec47 879bool ContentsWriter::DoPackage(string FileName, string Package)
b2e465d6 880{
ce928105
MV
881 if (!Db.GetFileInfo(FileName,
882 Package.empty(), /* DoControl */
883 true, /* DoContents */
884 false, /* GenContentsOnly */
885 false, /* DoSource */
886 false, /* DoMD5 */
887 false, /* DoSHA1 */
888 false, /* DoSHA256 */
889 false)) /* DoSHA512 */
cde41ae8 890 {
b2e465d6 891 return false;
cde41ae8 892 }
b2e465d6
AL
893
894 // Parse the package name
895 if (Package.empty() == true)
896 {
b2e465d6
AL
897 Package = Db.Control.Section.FindS("Package");
898 }
899
900 Db.Contents.Add(Gen,Package);
901
902 return Db.Finish();
903}
904 /*}}}*/
905// ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
906// ---------------------------------------------------------------------
907/* */
9209ec47 908bool ContentsWriter::ReadFromPkgs(string const &PkgFile,string const &PkgCompress)
b2e465d6
AL
909{
910 MultiCompress Pkgs(PkgFile,PkgCompress,0,false);
911 if (_error->PendingError() == true)
912 return false;
12d1f5b3 913
b2e465d6 914 // Open the package file
12d1f5b3
DK
915 FileFd Fd;
916 if (Pkgs.OpenOld(Fd) == false)
b2e465d6 917 return false;
12d1f5b3 918
b2e465d6
AL
919 pkgTagFile Tags(&Fd);
920 if (_error->PendingError() == true)
b2e465d6 921 return false;
12d1f5b3 922
b2e465d6
AL
923 // Parse.
924 pkgTagSection Section;
925 while (Tags.Step(Section) == true)
926 {
927 string File = flCombine(Prefix,Section.FindS("FileName"));
928 string Package = Section.FindS("Section");
929 if (Package.empty() == false && Package.end()[-1] != '/')
930 {
931 Package += '/';
932 Package += Section.FindS("Package");
933 }
934 else
935 Package += Section.FindS("Package");
936
937 DoPackage(File,Package);
938 if (_error->empty() == false)
939 {
940 _error->Error("Errors apply to file '%s'",File.c_str());
941 _error->DumpErrors();
942 }
943 }
12d1f5b3 944
b2e465d6 945 // Tidy the compressor
12d1f5b3
DK
946 Fd.Close();
947
b2e465d6
AL
948 return true;
949}
98953965 950
b2e465d6 951 /*}}}*/
98953965
AL
952
953// ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
954// ---------------------------------------------------------------------
955/* */
65512241 956ReleaseWriter::ReleaseWriter(string const &/*DB*/)
98953965 957{
3cb3fe76
DK
958 if (_config->FindB("APT::FTPArchive::Release::Default-Patterns", true) == true)
959 {
960 AddPattern("Packages");
961 AddPattern("Packages.gz");
962 AddPattern("Packages.bz2");
963 AddPattern("Packages.lzma");
b7080ced 964 AddPattern("Packages.xz");
8e3900d0 965 AddPattern("Translation-*");
3cb3fe76
DK
966 AddPattern("Sources");
967 AddPattern("Sources.gz");
968 AddPattern("Sources.bz2");
969 AddPattern("Sources.lzma");
b7080ced 970 AddPattern("Sources.xz");
3cb3fe76 971 AddPattern("Release");
0baf849d 972 AddPattern("Contents-*");
8d16c617 973 AddPattern("Index");
3cb3fe76
DK
974 AddPattern("md5sum.txt");
975 }
976 AddPatterns(_config->FindVector("APT::FTPArchive::Release::Patterns"));
187492a6 977
98953965 978 Output = stdout;
9209ec47 979 time_t const now = time(NULL);
cb12d0a6
DK
980
981 setlocale(LC_TIME, "C");
982
98953965
AL
983 char datestr[128];
984 if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S UTC",
985 gmtime(&now)) == 0)
986 {
987 datestr[0] = '\0';
988 }
989
c99e48ec 990 time_t const validuntil = now + _config->FindI("APT::FTPArchive::Release::ValidTime", 0);
cdb623ed 991 char validstr[128];
c99e48ec
DK
992 if (now == validuntil ||
993 strftime(validstr, sizeof(validstr), "%a, %d %b %Y %H:%M:%S UTC",
994 gmtime(&validuntil)) == 0)
995 {
cdb623ed 996 validstr[0] = '\0';
c99e48ec
DK
997 }
998
cb12d0a6
DK
999 setlocale(LC_TIME, "");
1000
98953965
AL
1001 map<string,string> Fields;
1002 Fields["Origin"] = "";
1003 Fields["Label"] = "";
1004 Fields["Suite"] = "";
1005 Fields["Version"] = "";
1006 Fields["Codename"] = "";
1007 Fields["Date"] = datestr;
c99e48ec 1008 Fields["Valid-Until"] = validstr;
98953965
AL
1009 Fields["Architectures"] = "";
1010 Fields["Components"] = "";
1011 Fields["Description"] = "";
1012
1013 for(map<string,string>::const_iterator I = Fields.begin();
1014 I != Fields.end();
1015 ++I)
1016 {
1017 string Config = string("APT::FTPArchive::Release::") + (*I).first;
1018 string Value = _config->Find(Config, (*I).second.c_str());
1019 if (Value == "")
1020 continue;
1021
1022 fprintf(Output, "%s: %s\n", (*I).first.c_str(), Value.c_str());
1023 }
3c54407f
DK
1024
1025 DoMD5 = _config->FindB("APT::FTPArchive::Release::MD5",DoMD5);
1026 DoSHA1 = _config->FindB("APT::FTPArchive::Release::SHA1",DoSHA1);
1027 DoSHA256 = _config->FindB("APT::FTPArchive::Release::SHA256",DoSHA256);
98953965
AL
1028}
1029 /*}}}*/
1030// ReleaseWriter::DoPackage - Process a single package /*{{{*/
1031// ---------------------------------------------------------------------
1032bool ReleaseWriter::DoPackage(string FileName)
1033{
1034 // Strip the DirStrip prefix from the FileName and add the PathPrefix
1035 string NewFileName;
1036 if (DirStrip.empty() == false &&
1037 FileName.length() > DirStrip.length() &&
1038 stringcmp(FileName.begin(),FileName.begin() + DirStrip.length(),
1039 DirStrip.begin(),DirStrip.end()) == 0)
c0eb6bc6 1040 {
98953965 1041 NewFileName = string(FileName.begin() + DirStrip.length(),FileName.end());
c0eb6bc6 1042 while (NewFileName[0] == '/')
9202409d 1043 NewFileName = string(NewFileName.begin() + 1,NewFileName.end());
c0eb6bc6 1044 }
98953965
AL
1045 else
1046 NewFileName = FileName;
c0eb6bc6 1047
98953965
AL
1048 if (PathPrefix.empty() == false)
1049 NewFileName = flCombine(PathPrefix,NewFileName);
1050
1051 FileFd fd(FileName, FileFd::ReadOnly);
1052
1053 if (!fd.IsOpen())
1054 {
1055 return false;
1056 }
1057
c0eb6bc6 1058 CheckSums[NewFileName].size = fd.Size();
f7291f62 1059
8c4e1f97 1060 Hashes hs;
109eb151 1061 hs.AddFD(fd, 0, DoMD5, DoSHA1, DoSHA256, DoSHA512);
3c54407f 1062 if (DoMD5 == true)
8c4e1f97 1063 CheckSums[NewFileName].MD5 = hs.MD5.Result();
3c54407f 1064 if (DoSHA1 == true)
8c4e1f97 1065 CheckSums[NewFileName].SHA1 = hs.SHA1.Result();
3c54407f 1066 if (DoSHA256 == true)
8c4e1f97 1067 CheckSums[NewFileName].SHA256 = hs.SHA256.Result();
9abccf4a 1068 if (DoSHA512 == true)
8c4e1f97 1069 CheckSums[NewFileName].SHA512 = hs.SHA512.Result();
98953965 1070 fd.Close();
8c4e1f97 1071
98953965
AL
1072 return true;
1073}
f7291f62
AL
1074
1075 /*}}}*/
1076// ReleaseWriter::Finish - Output the checksums /*{{{*/
1077// ---------------------------------------------------------------------
1078void ReleaseWriter::Finish()
1079{
3c54407f 1080 if (DoMD5 == true)
f7291f62 1081 {
3c54407f
DK
1082 fprintf(Output, "MD5Sum:\n");
1083 for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
1084 I != CheckSums.end(); ++I)
1085 {
650faab0 1086 fprintf(Output, " %s %16llu %s\n",
3c54407f
DK
1087 (*I).second.MD5.c_str(),
1088 (*I).second.size,
1089 (*I).first.c_str());
1090 }
f7291f62 1091 }
3c54407f 1092 if (DoSHA1 == true)
f7291f62 1093 {
3c54407f
DK
1094 fprintf(Output, "SHA1:\n");
1095 for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
1096 I != CheckSums.end(); ++I)
1097 {
650faab0 1098 fprintf(Output, " %s %16llu %s\n",
3c54407f
DK
1099 (*I).second.SHA1.c_str(),
1100 (*I).second.size,
1101 (*I).first.c_str());
1102 }
f7291f62 1103 }
3c54407f 1104 if (DoSHA256 == true)
cde41ae8 1105 {
3c54407f
DK
1106 fprintf(Output, "SHA256:\n");
1107 for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
1108 I != CheckSums.end(); ++I)
1109 {
650faab0 1110 fprintf(Output, " %s %16llu %s\n",
3c54407f
DK
1111 (*I).second.SHA256.c_str(),
1112 (*I).second.size,
1113 (*I).first.c_str());
1114 }
cde41ae8 1115 }
9a961efc
MV
1116
1117 fprintf(Output, "SHA512:\n");
1118 for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
1119 I != CheckSums.end();
1120 ++I)
1121 {
650faab0 1122 fprintf(Output, " %s %16llu %s\n",
9a961efc
MV
1123 (*I).second.SHA512.c_str(),
1124 (*I).second.size,
1125 (*I).first.c_str());
1126 }
1127
f7291f62 1128}