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