1 // -*- mode: cpp; mode: fold -*-
3 // $Id: writer.cc,v 1.14 2004/03/24 01:40:43 mdz Exp $
4 /* ######################################################################
8 The file writer classes. These write various types of output, sources,
11 ##################################################################### */
13 // Include Files /*{{{*/
16 #include <apt-pkg/configuration.h>
17 #include <apt-pkg/deblistparser.h>
18 #include <apt-pkg/error.h>
19 #include <apt-pkg/fileutl.h>
20 #include <apt-pkg/gpgv.h>
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>
36 #include <sys/types.h>
44 #include "apt-ftparchive.h"
47 #include "multicompress.h"
52 FTWScanner
*FTWScanner::Owner
;
54 // SetTFRewriteData - Helper for setting rewrite lists /*{{{*/
55 // ---------------------------------------------------------------------
57 inline void SetTFRewriteData(struct TFRewriteData
&tfrd
,
60 const char *newtag
= 0)
63 tfrd
.Rewrite
= rewrite
;
68 // FTWScanner::FTWScanner - Constructor /*{{{*/
69 // ---------------------------------------------------------------------
71 FTWScanner::FTWScanner(string
const &Arch
): Arch(Arch
)
74 NoLinkAct
= !_config
->FindB("APT::FTPArchive::DeLinkAct",true);
76 DoMD5
= _config
->FindB("APT::FTPArchive::MD5",true);
77 DoSHA1
= _config
->FindB("APT::FTPArchive::SHA1",true);
78 DoSHA256
= _config
->FindB("APT::FTPArchive::SHA256",true);
79 DoSHA512
= _config
->FindB("APT::FTPArchive::SHA512",true);
82 // FTWScanner::Scanner - FTW Scanner /*{{{*/
83 // ---------------------------------------------------------------------
84 /* This is the FTW scanner, it processes each directory element in the
86 int FTWScanner::ScannerFTW(const char *File
,const struct stat
* /*sb*/,int Flag
)
91 ioprintf(c1out
, _("W: Unable to read directory %s\n"), File
);
96 ioprintf(c1out
, _("W: Unable to stat %s\n"), File
);
101 return ScannerFile(File
, true);
104 // FTWScanner::ScannerFile - File Scanner /*{{{*/
105 // ---------------------------------------------------------------------
107 int FTWScanner::ScannerFile(const char *File
, bool const &ReadLink
)
109 const char *LastComponent
= strrchr(File
, '/');
110 char *RealPath
= NULL
;
112 if (LastComponent
== NULL
)
113 LastComponent
= File
;
117 vector
<string
>::const_iterator I
;
118 for(I
= Owner
->Patterns
.begin(); I
!= Owner
->Patterns
.end(); ++I
)
120 if (fnmatch((*I
).c_str(), LastComponent
, 0) == 0)
123 if (I
== Owner
->Patterns
.end())
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. */
130 Owner
->OriginalPath
= File
;
132 readlink(File
,Jnk
,sizeof(Jnk
)) != -1 &&
133 (RealPath
= realpath(File
,NULL
)) != 0)
135 Owner
->DoPackage(RealPath
);
139 Owner
->DoPackage(File
);
141 if (_error
->empty() == false)
143 // Print any errors or warnings found
145 bool SeenPath
= false;
146 while (_error
->empty() == false)
150 bool const Type
= _error
->PopMessage(Err
);
152 cerr
<< _("E: ") << Err
<< endl
;
154 cerr
<< _("W: ") << Err
<< endl
;
156 if (Err
.find(File
) != string::npos
)
160 if (SeenPath
== false)
161 cerr
<< _("E: Errors apply to file ") << "'" << File
<< "'" << endl
;
168 // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
169 // ---------------------------------------------------------------------
171 bool FTWScanner::RecursiveScan(string
const &Dir
)
173 char *RealPath
= NULL
;
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)
178 if ((RealPath
= realpath(Dir
.c_str(),NULL
)) == 0)
179 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
180 InternalPrefix
= RealPath
;
184 // Do recursive directory searching
186 int const Res
= ftw(Dir
.c_str(),ScannerFTW
,30);
188 // Error treewalking?
191 if (_error
->PendingError() == false)
192 _error
->Errno("ftw",_("Tree walking failed"));
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. */
203 bool FTWScanner::LoadFileList(string
const &Dir
, string
const &File
)
205 char *RealPath
= NULL
;
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)
210 if ((RealPath
= realpath(Dir
.c_str(),NULL
)) == 0)
211 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
212 InternalPrefix
= RealPath
;
217 FILE *List
= fopen(File
.c_str(),"r");
219 return _error
->Errno("fopen",_("Failed to open %s"),File
.c_str());
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
226 if (Dir
.empty() == true || Dir
.end()[-1] != '/')
227 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s/",Dir
.c_str());
229 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s",Dir
.c_str());
230 while (fgets(FileStart
,sizeof(Line
) - (FileStart
- Line
),List
) != 0)
232 char *FileName
= _strstrip(FileStart
);
233 if (FileName
[0] == 0)
236 if (FileName
[0] != '/')
238 if (FileName
!= FileStart
)
239 memmove(FileStart
,FileName
,strlen(FileStart
));
246 if (stat(FileName
,&St
) != 0)
250 if (ScannerFile(FileName
, false) != 0)
258 // FTWScanner::Delink - Delink symlinks /*{{{*/
259 // ---------------------------------------------------------------------
261 bool FTWScanner::Delink(string
&FileName
,const char *OriginalPath
,
262 unsigned long long &DeLinkBytes
,
263 unsigned long long const &FileSize
)
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)
271 if (DeLinkLimit
!= 0 && DeLinkBytes
/1024 < DeLinkLimit
)
273 // Tidy up the display
274 if (DeLinkBytes
== 0)
278 ioprintf(c1out
, _(" DeLink %s [%s]\n"), (OriginalPath
+ InternalPrefix
.length()),
279 SizeToStr(FileSize
).c_str());
282 if (NoLinkAct
== false)
285 if (readlink(OriginalPath
,OldLink
,sizeof(OldLink
)) == -1)
286 _error
->Errno("readlink",_("Failed to readlink %s"),OriginalPath
);
289 if (unlink(OriginalPath
) != 0)
290 _error
->Errno("unlink",_("Failed to unlink %s"),OriginalPath
);
293 if (link(FileName
.c_str(),OriginalPath
) != 0)
295 // Panic! Restore the symlink
296 if (symlink(OldLink
,OriginalPath
) != 0)
297 _error
->Errno("symlink", "failed to restore symlink");
298 return _error
->Errno("link",_("*** Failed to link %s to %s"),
306 DeLinkBytes
+= FileSize
;
307 if (DeLinkBytes
/1024 >= DeLinkLimit
)
308 ioprintf(c1out
, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes
).c_str());
311 FileName
= OriginalPath
;
318 // PackagesWriter::PackagesWriter - Constructor /*{{{*/
319 // ---------------------------------------------------------------------
321 PackagesWriter::PackagesWriter(string
const &DB
,string
const &Overrides
,string
const &ExtOverrides
,
322 string
const &Arch
) :
323 FTWScanner(Arch
), Db(DB
), Stats(Db
.Stats
), TransWriter(NULL
)
326 SetExts(".deb .udeb");
329 // Process the command line options
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
);
333 DoSHA512
= _config
->FindB("APT::FTPArchive::Packages::SHA512",DoSHA512
);
334 DoAlwaysStat
= _config
->FindB("APT::FTPArchive::AlwaysStat", false);
335 DoContents
= _config
->FindB("APT::FTPArchive::Contents",true);
336 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
337 LongDescription
= _config
->FindB("APT::FTPArchive::LongDescription",true);
339 if (Db
.Loaded() == false)
342 // Read the override file
343 if (Overrides
.empty() == false && Over
.ReadOverride(Overrides
) == false)
348 if (ExtOverrides
.empty() == false)
349 Over
.ReadExtraOverride(ExtOverrides
);
351 _error
->DumpErrors();
354 // FTWScanner::SetExts - Set extensions to support /*{{{*/
355 // ---------------------------------------------------------------------
357 bool FTWScanner::SetExts(string
const &Vals
)
360 string::size_type Start
= 0;
361 while (Start
<= Vals
.length()-1)
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 )
367 AddPattern(string("*_") + Arch
+ Vals
.substr(Start
, Length
));
368 AddPattern(string("*_all") + Vals
.substr(Start
, Length
));
371 AddPattern(string("*") + Vals
.substr(Start
, Length
));
380 // PackagesWriter::DoPackage - Process a single package /*{{{*/
381 // ---------------------------------------------------------------------
382 /* This method takes a package and gets its control information and
383 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
384 rewritten and the path/size/hash appended. */
385 bool PackagesWriter::DoPackage(string FileName
)
387 // Pull all the data we need form the DB
388 if (Db
.GetFileInfo(FileName
, true, DoContents
, true, DoMD5
, DoSHA1
, DoSHA256
, DoSHA512
, DoAlwaysStat
)
394 unsigned long long FileSize
= Db
.GetFileSize();
395 if (Delink(FileName
,OriginalPath
,Stats
.DeLinkBytes
,FileSize
) == false)
398 // Lookup the overide information
399 pkgTagSection
&Tags
= Db
.Control
.Section
;
400 string Package
= Tags
.FindS("Package");
402 // if we generate a Packages file for a given arch, we use it to
403 // look for overrides. if we run in "simple" mode without the
404 // "Architecures" variable in the config we use the architecure value
409 Architecture
= Tags
.FindS("Architecture");
410 auto_ptr
<Override::Item
> OverItem(Over
.GetItem(Package
,Architecture
));
412 if (Package
.empty() == true)
413 return _error
->Error(_("Archive had no package field"));
415 // If we need to do any rewriting of the header do it now..
416 if (OverItem
.get() == 0)
418 if (NoOverride
== false)
421 ioprintf(c1out
, _(" %s has no override entry\n"), Package
.c_str());
424 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
425 OverItem
->FieldOverride
["Section"] = Tags
.FindS("Section");
426 OverItem
->Priority
= Tags
.FindS("Priority");
430 sprintf(Size
,"%llu", (unsigned long long) FileSize
);
432 // Strip the DirStrip prefix from the FileName and add the PathPrefix
434 if (DirStrip
.empty() == false &&
435 FileName
.length() > DirStrip
.length() &&
436 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
437 DirStrip
.begin(),DirStrip
.end()) == 0)
438 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
440 NewFileName
= FileName
;
441 if (PathPrefix
.empty() == false)
442 NewFileName
= flCombine(PathPrefix
,NewFileName
);
444 /* Configuration says we don't want to include the long Description
445 in the package file - instead we want to ship a separated file */
447 if (LongDescription
== false) {
448 desc
= Tags
.FindS("Description").append("\n");
449 OverItem
->FieldOverride
["Description"] = desc
.substr(0, desc
.find('\n')).c_str();
452 // This lists all the changes to the fields we are going to make.
453 // (7 hardcoded + maintainer + suggests + end marker)
454 TFRewriteData Changes
[6+2+OverItem
->FieldOverride
.size()+1+1];
456 unsigned int End
= 0;
457 SetTFRewriteData(Changes
[End
++], "Size", Size
);
459 SetTFRewriteData(Changes
[End
++], "MD5sum", Db
.MD5Res
.c_str());
461 SetTFRewriteData(Changes
[End
++], "SHA1", Db
.SHA1Res
.c_str());
462 if (DoSHA256
== true)
463 SetTFRewriteData(Changes
[End
++], "SHA256", Db
.SHA256Res
.c_str());
464 if (DoSHA512
== true)
465 SetTFRewriteData(Changes
[End
++], "SHA512", Db
.SHA512Res
.c_str());
466 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
467 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
468 SetTFRewriteData(Changes
[End
++], "Status", 0);
469 SetTFRewriteData(Changes
[End
++], "Optional", 0);
471 string DescriptionMd5
;
472 if (LongDescription
== false) {
473 MD5Summation descmd5
;
474 descmd5
.Add(desc
.c_str());
475 DescriptionMd5
= descmd5
.Result().Value();
476 SetTFRewriteData(Changes
[End
++], "Description-md5", DescriptionMd5
.c_str());
477 if (TransWriter
!= NULL
)
478 TransWriter
->DoPackage(Package
, desc
, DescriptionMd5
);
481 // Rewrite the maintainer field if necessary
483 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
484 if (MaintFailed
== true)
486 if (NoOverride
== false)
489 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
490 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
494 if (NewMaint
.empty() == false)
495 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
497 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
498 dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
499 but dpkg does this append bit. So we do the append bit, at least that way the
500 status file and package file will remain similar. There are other transforms
501 but optional is the only legacy one still in use for some lazy reason. */
502 string OptionalStr
= Tags
.FindS("Optional");
503 if (OptionalStr
.empty() == false)
505 if (Tags
.FindS("Suggests").empty() == false)
506 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
507 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
510 for (map
<string
,string
>::const_iterator I
= OverItem
->FieldOverride
.begin();
511 I
!= OverItem
->FieldOverride
.end(); ++I
)
512 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
514 SetTFRewriteData(Changes
[End
++], 0, 0);
516 // Rewrite and store the fields.
517 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
519 fprintf(Output
,"\n");
525 // TranslationWriter::TranslationWriter - Constructor /*{{{*/
526 // ---------------------------------------------------------------------
527 /* Create a Translation-Master file for this Packages file */
528 TranslationWriter::TranslationWriter(string
const &File
, string
const &TransCompress
,
529 mode_t
const &Permissions
) : Output(NULL
),
532 if (File
.empty() == true)
535 Comp
= new MultiCompress(File
, TransCompress
, Permissions
);
536 Output
= Comp
->Input
;
539 // TranslationWriter::DoPackage - Process a single package /*{{{*/
540 // ---------------------------------------------------------------------
541 /* Create a Translation-Master file for this Packages file */
542 bool TranslationWriter::DoPackage(string
const &Pkg
, string
const &Desc
,
548 // Different archs can include different versions and therefore
549 // different descriptions - so we need to check for both name and md5.
550 string
const Record
= Pkg
+ ":" + MD5
;
552 if (Included
.find(Record
) != Included
.end())
555 fprintf(Output
, "Package: %s\nDescription-md5: %s\nDescription-en: %s\n",
556 Pkg
.c_str(), MD5
.c_str(), Desc
.c_str());
558 Included
.insert(Record
);
562 // TranslationWriter::~TranslationWriter - Destructor /*{{{*/
563 // ---------------------------------------------------------------------
565 TranslationWriter::~TranslationWriter()
574 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
575 // ---------------------------------------------------------------------
577 SourcesWriter::SourcesWriter(string
const &DB
, string
const &BOverrides
,string
const &SOverrides
,
578 string
const &ExtOverrides
) :
579 Db(DB
), Stats(Db
.Stats
)
587 // Process the command line options
588 DoMD5
= _config
->FindB("APT::FTPArchive::Sources::MD5",DoMD5
);
589 DoSHA1
= _config
->FindB("APT::FTPArchive::Sources::SHA1",DoSHA1
);
590 DoSHA256
= _config
->FindB("APT::FTPArchive::Sources::SHA256",DoSHA256
);
591 DoSHA512
= _config
->FindB("APT::FTPArchive::Sources::SHA512",DoSHA512
);
592 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
593 DoAlwaysStat
= _config
->FindB("APT::FTPArchive::AlwaysStat", false);
595 // Read the override file
596 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
601 // WTF?? The logic above: if we can't read binary overrides, don't even try
602 // reading source overrides. if we can read binary overrides, then say there
603 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
605 if (ExtOverrides
.empty() == false)
606 SOver
.ReadExtraOverride(ExtOverrides
);
608 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
609 SOver
.ReadOverride(SOverrides
,true);
612 // SourcesWriter::DoPackage - Process a single package /*{{{*/
613 // ---------------------------------------------------------------------
615 bool SourcesWriter::DoPackage(string FileName
)
619 if (OpenMaybeClearSignedFile(FileName
, F
) == false)
622 unsigned long long const FSize
= F
.FileSize();
623 //FIXME: do we really need to enforce a maximum size of the dsc file?
624 if (FSize
> 128*1024)
625 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
627 if (BufSize
< FSize
+ 2)
630 Buffer
= (char *)realloc(Buffer
, BufSize
);
633 if (F
.Read(Buffer
, FSize
) == false)
636 // Stat the file for later (F might be clearsigned, so not F.FileSize())
638 if (stat(FileName
.c_str(), &St
) != 0)
639 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
642 char *Start
= Buffer
;
643 char *BlkEnd
= Buffer
+ FSize
;
646 if (FSize
== (unsigned long long) St
.st_size
)
649 DscHashes
.MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
651 DscHashes
.SHA1
.Add((unsigned char *)Start
,BlkEnd
- Start
);
652 if (DoSHA256
== true)
653 DscHashes
.SHA256
.Add((unsigned char *)Start
,BlkEnd
- Start
);
654 if (DoSHA512
== true)
655 DscHashes
.SHA512
.Add((unsigned char *)Start
,BlkEnd
- Start
);
659 FileFd
DscFile(FileName
, FileFd::ReadOnly
);
660 DscHashes
.AddFD(DscFile
, St
.st_size
, DoMD5
, DoSHA1
, DoSHA256
, DoSHA512
);
663 // Add extra \n to the end, just in case (as in clearsigned they are missing)
668 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false || Tags
.Exists("Source") == false)
669 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
672 // Lookup the overide information, finding first the best priority.
674 string Bins
= Tags
.FindS("Binary");
675 char Buffer
[Bins
.length() + 1];
676 auto_ptr
<Override::Item
> OverItem(0);
677 if (Bins
.empty() == false)
679 strcpy(Buffer
,Bins
.c_str());
681 // Ignore too-long errors.
683 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
685 // Look at all the binaries
686 unsigned char BestPrioV
= pkgCache::State::Extra
;
687 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
689 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
693 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
694 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
696 BestPrioV
= NewPrioV
;
697 BestPrio
= Itm
->Priority
;
700 if (OverItem
.get() == 0)
705 // If we need to do any rewriting of the header do it now..
706 if (OverItem
.get() == 0)
708 if (NoOverride
== false)
711 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
714 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
717 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
718 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
719 if (SOverItem
.get() == 0)
721 ioprintf(c1out
, _(" %s has no source override entry\n"), Tags
.FindS("Source").c_str());
722 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
723 if (SOverItem
.get() == 0)
725 ioprintf(c1out
, _(" %s has no binary override entry either\n"), Tags
.FindS("Source").c_str());
726 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
727 *SOverItem
= *OverItem
;
731 // Add the dsc to the files hash list
732 string
const strippedName
= flNotDir(FileName
);
733 std::ostringstream ostreamFiles
;
734 if (DoMD5
== true && Tags
.Exists("Files"))
735 ostreamFiles
<< "\n " << string(DscHashes
.MD5
.Result()) << " " << St
.st_size
<< " "
736 << strippedName
<< "\n " << Tags
.FindS("Files");
737 string
const Files
= ostreamFiles
.str();
739 std::ostringstream ostreamSha1
;
740 if (DoSHA1
== true && Tags
.Exists("Checksums-Sha1"))
741 ostreamSha1
<< "\n " << string(DscHashes
.SHA1
.Result()) << " " << St
.st_size
<< " "
742 << strippedName
<< "\n " << Tags
.FindS("Checksums-Sha1");
744 std::ostringstream ostreamSha256
;
745 if (DoSHA256
== true && Tags
.Exists("Checksums-Sha256"))
746 ostreamSha256
<< "\n " << string(DscHashes
.SHA256
.Result()) << " " << St
.st_size
<< " "
747 << strippedName
<< "\n " << Tags
.FindS("Checksums-Sha256");
749 std::ostringstream ostreamSha512
;
750 if (DoSHA512
== true && Tags
.Exists("Checksums-Sha512"))
751 ostreamSha512
<< "\n " << string(DscHashes
.SHA512
.Result()) << " " << St
.st_size
<< " "
752 << strippedName
<< "\n " << Tags
.FindS("Checksums-Sha512");
754 // Strip the DirStrip prefix from the FileName and add the PathPrefix
756 if (DirStrip
.empty() == false &&
757 FileName
.length() > DirStrip
.length() &&
758 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
759 NewFileName
= string(OriginalPath
+ DirStrip
.length());
761 NewFileName
= OriginalPath
;
762 if (PathPrefix
.empty() == false)
763 NewFileName
= flCombine(PathPrefix
,NewFileName
);
765 string Directory
= flNotFile(OriginalPath
);
766 string Package
= Tags
.FindS("Source");
768 // Perform operation over all of the files
770 const char *C
= Files
.c_str();
771 char *RealPath
= NULL
;
772 for (;isspace(*C
); C
++);
775 // Parse each of the elements
776 if (ParseQuoteWord(C
,ParseJnk
) == false ||
777 ParseQuoteWord(C
,ParseJnk
) == false ||
778 ParseQuoteWord(C
,ParseJnk
) == false)
779 return _error
->Error("Error parsing file record");
781 string OriginalPath
= Directory
+ ParseJnk
;
783 // Add missing hashes to source files
784 if ((DoSHA1
== true && !Tags
.Exists("Checksums-Sha1")) ||
785 (DoSHA256
== true && !Tags
.Exists("Checksums-Sha256")) ||
786 (DoSHA512
== true && !Tags
.Exists("Checksums-Sha512")))
788 if (Db
.GetFileInfo(OriginalPath
, false, false, false, DoMD5
, DoSHA1
, DoSHA256
, DoSHA512
, DoAlwaysStat
)
791 return _error
->Error("Error getting file info");
794 if (DoSHA1
== true && !Tags
.Exists("Checksums-Sha1"))
795 ostreamSha1
<< "\n " << string(Db
.SHA1Res
) << " "
796 << Db
.GetFileSize() << " " << ParseJnk
;
798 if (DoSHA256
== true && !Tags
.Exists("Checksums-Sha256"))
799 ostreamSha256
<< "\n " << string(Db
.SHA256Res
) << " "
800 << Db
.GetFileSize() << " " << ParseJnk
;
802 if (DoSHA512
== true && !Tags
.Exists("Checksums-Sha512"))
803 ostreamSha512
<< "\n " << string(Db
.SHA512Res
) << " "
804 << Db
.GetFileSize() << " " << ParseJnk
;
807 // Perform the delinking operation
810 if (readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
811 (RealPath
= realpath(OriginalPath
.c_str(),NULL
)) != 0)
813 string RP
= RealPath
;
815 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
820 Directory
= flNotFile(NewFileName
);
821 if (Directory
.length() > 2)
822 Directory
.erase(Directory
.end()-1);
824 string
const ChecksumsSha1
= ostreamSha1
.str();
825 string
const ChecksumsSha256
= ostreamSha256
.str();
826 string
const ChecksumsSha512
= ostreamSha512
.str();
828 // This lists all the changes to the fields we are going to make.
829 // (5 hardcoded + checksums + maintainer + end marker)
830 TFRewriteData Changes
[5+2+1+SOverItem
->FieldOverride
.size()+1];
832 unsigned int End
= 0;
833 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
834 if (Files
.empty() == false)
835 SetTFRewriteData(Changes
[End
++],"Files",Files
.c_str());
836 if (ChecksumsSha1
.empty() == false)
837 SetTFRewriteData(Changes
[End
++],"Checksums-Sha1",ChecksumsSha1
.c_str());
838 if (ChecksumsSha256
.empty() == false)
839 SetTFRewriteData(Changes
[End
++],"Checksums-Sha256",ChecksumsSha256
.c_str());
840 if (ChecksumsSha512
.empty() == false)
841 SetTFRewriteData(Changes
[End
++],"Checksums-Sha512",ChecksumsSha512
.c_str());
842 if (Directory
!= "./")
843 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
844 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
845 SetTFRewriteData(Changes
[End
++],"Status",0);
847 // Rewrite the maintainer field if necessary
849 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
850 if (MaintFailed
== true)
852 if (NoOverride
== false)
855 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
856 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
859 if (NewMaint
.empty() == false)
860 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
862 for (map
<string
,string
>::const_iterator I
= SOverItem
->FieldOverride
.begin();
863 I
!= SOverItem
->FieldOverride
.end(); ++I
)
864 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
866 SetTFRewriteData(Changes
[End
++], 0, 0);
868 // Rewrite and store the fields.
869 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
871 fprintf(Output
,"\n");
879 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
880 // ---------------------------------------------------------------------
882 ContentsWriter::ContentsWriter(string
const &DB
, string
const &Arch
) :
883 FTWScanner(Arch
), Db(DB
), Stats(Db
.Stats
)
890 // ContentsWriter::DoPackage - Process a single package /*{{{*/
891 // ---------------------------------------------------------------------
892 /* If Package is the empty string the control record will be parsed to
893 determine what the package name is. */
894 bool ContentsWriter::DoPackage(string FileName
, string Package
)
896 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false, false))
901 // Parse the package name
902 if (Package
.empty() == true)
904 Package
= Db
.Control
.Section
.FindS("Package");
907 Db
.Contents
.Add(Gen
,Package
);
912 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
913 // ---------------------------------------------------------------------
915 bool ContentsWriter::ReadFromPkgs(string
const &PkgFile
,string
const &PkgCompress
)
917 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
918 if (_error
->PendingError() == true)
921 // Open the package file
923 if (Pkgs
.OpenOld(Fd
) == false)
926 pkgTagFile
Tags(&Fd
);
927 if (_error
->PendingError() == true)
931 pkgTagSection Section
;
932 while (Tags
.Step(Section
) == true)
934 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
935 string Package
= Section
.FindS("Section");
936 if (Package
.empty() == false && Package
.end()[-1] != '/')
939 Package
+= Section
.FindS("Package");
942 Package
+= Section
.FindS("Package");
944 DoPackage(File
,Package
);
945 if (_error
->empty() == false)
947 _error
->Error("Errors apply to file '%s'",File
.c_str());
948 _error
->DumpErrors();
952 // Tidy the compressor
960 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
961 // ---------------------------------------------------------------------
963 ReleaseWriter::ReleaseWriter(string
const &/*DB*/)
965 if (_config
->FindB("APT::FTPArchive::Release::Default-Patterns", true) == true)
967 AddPattern("Packages");
968 AddPattern("Packages.gz");
969 AddPattern("Packages.bz2");
970 AddPattern("Packages.lzma");
971 AddPattern("Packages.xz");
972 AddPattern("Translation-*");
973 AddPattern("Sources");
974 AddPattern("Sources.gz");
975 AddPattern("Sources.bz2");
976 AddPattern("Sources.lzma");
977 AddPattern("Sources.xz");
978 AddPattern("Release");
979 AddPattern("Contents-*");
981 AddPattern("md5sum.txt");
983 AddPatterns(_config
->FindVector("APT::FTPArchive::Release::Patterns"));
986 time_t const now
= time(NULL
);
988 setlocale(LC_TIME
, "C");
991 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
997 time_t const validuntil
= now
+ _config
->FindI("APT::FTPArchive::Release::ValidTime", 0);
999 if (now
== validuntil
||
1000 strftime(validstr
, sizeof(validstr
), "%a, %d %b %Y %H:%M:%S UTC",
1001 gmtime(&validuntil
)) == 0)
1006 setlocale(LC_TIME
, "");
1008 map
<string
,string
> Fields
;
1009 Fields
["Origin"] = "";
1010 Fields
["Label"] = "";
1011 Fields
["Suite"] = "";
1012 Fields
["Version"] = "";
1013 Fields
["Codename"] = "";
1014 Fields
["Date"] = datestr
;
1015 Fields
["Valid-Until"] = validstr
;
1016 Fields
["Architectures"] = "";
1017 Fields
["Components"] = "";
1018 Fields
["Description"] = "";
1020 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
1024 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
1025 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
1029 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
1032 DoMD5
= _config
->FindB("APT::FTPArchive::Release::MD5",DoMD5
);
1033 DoSHA1
= _config
->FindB("APT::FTPArchive::Release::SHA1",DoSHA1
);
1034 DoSHA256
= _config
->FindB("APT::FTPArchive::Release::SHA256",DoSHA256
);
1037 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
1038 // ---------------------------------------------------------------------
1039 bool ReleaseWriter::DoPackage(string FileName
)
1041 // Strip the DirStrip prefix from the FileName and add the PathPrefix
1043 if (DirStrip
.empty() == false &&
1044 FileName
.length() > DirStrip
.length() &&
1045 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
1046 DirStrip
.begin(),DirStrip
.end()) == 0)
1048 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
1049 while (NewFileName
[0] == '/')
1050 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
1053 NewFileName
= FileName
;
1055 if (PathPrefix
.empty() == false)
1056 NewFileName
= flCombine(PathPrefix
,NewFileName
);
1058 FileFd
fd(FileName
, FileFd::ReadOnly
);
1065 CheckSums
[NewFileName
].size
= fd
.Size();
1068 hs
.AddFD(fd
, 0, DoMD5
, DoSHA1
, DoSHA256
, DoSHA512
);
1070 CheckSums
[NewFileName
].MD5
= hs
.MD5
.Result();
1072 CheckSums
[NewFileName
].SHA1
= hs
.SHA1
.Result();
1073 if (DoSHA256
== true)
1074 CheckSums
[NewFileName
].SHA256
= hs
.SHA256
.Result();
1075 if (DoSHA512
== true)
1076 CheckSums
[NewFileName
].SHA512
= hs
.SHA512
.Result();
1083 // ReleaseWriter::Finish - Output the checksums /*{{{*/
1084 // ---------------------------------------------------------------------
1085 void ReleaseWriter::Finish()
1089 fprintf(Output
, "MD5Sum:\n");
1090 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1091 I
!= CheckSums
.end(); ++I
)
1093 fprintf(Output
, " %s %16llu %s\n",
1094 (*I
).second
.MD5
.c_str(),
1096 (*I
).first
.c_str());
1101 fprintf(Output
, "SHA1:\n");
1102 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1103 I
!= CheckSums
.end(); ++I
)
1105 fprintf(Output
, " %s %16llu %s\n",
1106 (*I
).second
.SHA1
.c_str(),
1108 (*I
).first
.c_str());
1111 if (DoSHA256
== true)
1113 fprintf(Output
, "SHA256:\n");
1114 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1115 I
!= CheckSums
.end(); ++I
)
1117 fprintf(Output
, " %s %16llu %s\n",
1118 (*I
).second
.SHA256
.c_str(),
1120 (*I
).first
.c_str());
1124 fprintf(Output
, "SHA512:\n");
1125 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1126 I
!= CheckSums
.end();
1129 fprintf(Output
, " %s %16llu %s\n",
1130 (*I
).second
.SHA512
.c_str(),
1132 (*I
).first
.c_str());