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 /*{{{*/
17 #include <apt-pkg/strutl.h>
18 #include <apt-pkg/error.h>
19 #include <apt-pkg/configuration.h>
20 #include <apt-pkg/md5.h>
21 #include <apt-pkg/sha1.h>
22 #include <apt-pkg/sha256.h>
23 #include <apt-pkg/deblistparser.h>
25 #include <sys/types.h>
35 #include "apt-ftparchive.h"
36 #include "multicompress.h"
39 FTWScanner
*FTWScanner::Owner
;
41 // SetTFRewriteData - Helper for setting rewrite lists /*{{{*/
42 // ---------------------------------------------------------------------
44 inline void SetTFRewriteData(struct TFRewriteData
&tfrd
,
47 const char *newtag
= 0)
50 tfrd
.Rewrite
= rewrite
;
55 // FTWScanner::FTWScanner - Constructor /*{{{*/
56 // ---------------------------------------------------------------------
58 FTWScanner::FTWScanner(string
const &Arch
): Arch(Arch
)
61 NoLinkAct
= !_config
->FindB("APT::FTPArchive::DeLinkAct",true);
64 // FTWScanner::Scanner - FTW Scanner /*{{{*/
65 // ---------------------------------------------------------------------
66 /* This is the FTW scanner, it processes each directory element in the
68 int FTWScanner::ScannerFTW(const char *File
,const struct stat
*sb
,int Flag
)
73 ioprintf(c1out
, _("W: Unable to read directory %s\n"), File
);
78 ioprintf(c1out
, _("W: Unable to stat %s\n"), File
);
83 return ScannerFile(File
, true);
86 // FTWScanner::ScannerFile - File Scanner /*{{{*/
87 // ---------------------------------------------------------------------
89 int FTWScanner::ScannerFile(const char *File
, bool const &ReadLink
)
91 const char *LastComponent
= strrchr(File
, '/');
92 char *RealPath
= NULL
;
94 if (LastComponent
== NULL
)
99 vector
<string
>::const_iterator I
;
100 for(I
= Owner
->Patterns
.begin(); I
!= Owner
->Patterns
.end(); ++I
)
102 if (fnmatch((*I
).c_str(), LastComponent
, 0) == 0)
105 if (I
== Owner
->Patterns
.end())
108 /* Process it. If the file is a link then resolve it into an absolute
109 name.. This works best if the directory components the scanner are
110 given are not links themselves. */
112 Owner
->OriginalPath
= File
;
114 readlink(File
,Jnk
,sizeof(Jnk
)) != -1 &&
115 (RealPath
= realpath(File
,NULL
)) != 0)
117 Owner
->DoPackage(RealPath
);
121 Owner
->DoPackage(File
);
123 if (_error
->empty() == false)
125 // Print any errors or warnings found
127 bool SeenPath
= false;
128 while (_error
->empty() == false)
132 bool const Type
= _error
->PopMessage(Err
);
134 cerr
<< _("E: ") << Err
<< endl
;
136 cerr
<< _("W: ") << Err
<< endl
;
138 if (Err
.find(File
) != string::npos
)
142 if (SeenPath
== false)
143 cerr
<< _("E: Errors apply to file ") << "'" << File
<< "'" << endl
;
150 // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
151 // ---------------------------------------------------------------------
153 bool FTWScanner::RecursiveScan(string
const &Dir
)
155 char *RealPath
= NULL
;
156 /* If noprefix is set then jam the scan root in, so we don't generate
157 link followed paths out of control */
158 if (InternalPrefix
.empty() == true)
160 if ((RealPath
= realpath(Dir
.c_str(),NULL
)) == 0)
161 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
162 InternalPrefix
= RealPath
;
166 // Do recursive directory searching
168 int const Res
= ftw(Dir
.c_str(),ScannerFTW
,30);
170 // Error treewalking?
173 if (_error
->PendingError() == false)
174 _error
->Errno("ftw",_("Tree walking failed"));
181 // FTWScanner::LoadFileList - Load the file list from a file /*{{{*/
182 // ---------------------------------------------------------------------
183 /* This is an alternative to using FTW to locate files, it reads the list
184 of files from another file. */
185 bool FTWScanner::LoadFileList(string
const &Dir
, string
const &File
)
187 char *RealPath
= NULL
;
188 /* If noprefix is set then jam the scan root in, so we don't generate
189 link followed paths out of control */
190 if (InternalPrefix
.empty() == true)
192 if ((RealPath
= realpath(Dir
.c_str(),NULL
)) == 0)
193 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
194 InternalPrefix
= RealPath
;
199 FILE *List
= fopen(File
.c_str(),"r");
201 return _error
->Errno("fopen",_("Failed to open %s"),File
.c_str());
203 /* We are a tad tricky here.. We prefix the buffer with the directory
204 name, that way if we need a full path with just use line.. Sneaky and
208 if (Dir
.empty() == true || Dir
.end()[-1] != '/')
209 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s/",Dir
.c_str());
211 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s",Dir
.c_str());
212 while (fgets(FileStart
,sizeof(Line
) - (FileStart
- Line
),List
) != 0)
214 char *FileName
= _strstrip(FileStart
);
215 if (FileName
[0] == 0)
218 if (FileName
[0] != '/')
220 if (FileName
!= FileStart
)
221 memmove(FileStart
,FileName
,strlen(FileStart
));
228 if (stat(FileName
,&St
) != 0)
232 if (ScannerFile(FileName
, false) != 0)
240 // FTWScanner::Delink - Delink symlinks /*{{{*/
241 // ---------------------------------------------------------------------
243 bool FTWScanner::Delink(string
&FileName
,const char *OriginalPath
,
244 unsigned long &DeLinkBytes
,
245 off_t
const &FileSize
)
247 // See if this isn't an internaly prefix'd file name.
248 if (InternalPrefix
.empty() == false &&
249 InternalPrefix
.length() < FileName
.length() &&
250 stringcmp(FileName
.begin(),FileName
.begin() + InternalPrefix
.length(),
251 InternalPrefix
.begin(),InternalPrefix
.end()) != 0)
253 if (DeLinkLimit
!= 0 && DeLinkBytes
/1024 < DeLinkLimit
)
255 // Tidy up the display
256 if (DeLinkBytes
== 0)
260 ioprintf(c1out
, _(" DeLink %s [%s]\n"), (OriginalPath
+ InternalPrefix
.length()),
261 SizeToStr(FileSize
).c_str());
264 if (NoLinkAct
== false)
267 if (readlink(OriginalPath
,OldLink
,sizeof(OldLink
)) == -1)
268 _error
->Errno("readlink",_("Failed to readlink %s"),OriginalPath
);
271 if (unlink(OriginalPath
) != 0)
272 _error
->Errno("unlink",_("Failed to unlink %s"),OriginalPath
);
275 if (link(FileName
.c_str(),OriginalPath
) != 0)
277 // Panic! Restore the symlink
278 symlink(OldLink
,OriginalPath
);
279 return _error
->Errno("link",_("*** Failed to link %s to %s"),
287 DeLinkBytes
+= FileSize
;
288 if (DeLinkBytes
/1024 >= DeLinkLimit
)
289 ioprintf(c1out
, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes
).c_str());
292 FileName
= OriginalPath
;
299 // PackagesWriter::PackagesWriter - Constructor /*{{{*/
300 // ---------------------------------------------------------------------
302 PackagesWriter::PackagesWriter(string
const &DB
,string
const &Overrides
,string
const &ExtOverrides
,
303 string
const &Arch
) :
304 FTWScanner(Arch
), Db(DB
), Stats(Db
.Stats
), TransWriter(NULL
)
307 SetExts(".deb .udeb");
310 // Process the command line options
311 DoMD5
= _config
->FindB("APT::FTPArchive::MD5",true);
312 DoSHA1
= _config
->FindB("APT::FTPArchive::SHA1",true);
313 DoSHA256
= _config
->FindB("APT::FTPArchive::SHA256",true);
314 DoAlwaysStat
= _config
->FindB("APT::FTPArchive::AlwaysStat", false);
315 DoContents
= _config
->FindB("APT::FTPArchive::Contents",true);
316 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
317 LongDescription
= _config
->FindB("APT::FTPArchive::LongDescription",true);
319 if (Db
.Loaded() == false)
322 // Read the override file
323 if (Overrides
.empty() == false && Over
.ReadOverride(Overrides
) == false)
328 if (ExtOverrides
.empty() == false)
329 Over
.ReadExtraOverride(ExtOverrides
);
331 _error
->DumpErrors();
334 // FTWScanner::SetExts - Set extensions to support /*{{{*/
335 // ---------------------------------------------------------------------
337 bool FTWScanner::SetExts(string
const &Vals
)
340 string::size_type Start
= 0;
341 while (Start
<= Vals
.length()-1)
343 string::size_type
const Space
= Vals
.find(' ',Start
);
344 string::size_type
const Length
= ((Space
== string::npos
) ? Vals
.length() : Space
) - Start
;
345 if ( Arch
.empty() == false )
347 AddPattern(string("*_") + Arch
+ Vals
.substr(Start
, Length
));
348 AddPattern(string("*_all") + Vals
.substr(Start
, Length
));
351 AddPattern(string("*") + Vals
.substr(Start
, Length
));
360 // PackagesWriter::DoPackage - Process a single package /*{{{*/
361 // ---------------------------------------------------------------------
362 /* This method takes a package and gets its control information and
363 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
364 rewritten and the path/size/hash appended. */
365 bool PackagesWriter::DoPackage(string FileName
)
367 // Pull all the data we need form the DB
368 if (Db
.GetFileInfo(FileName
, true, DoContents
, true, DoMD5
, DoSHA1
, DoSHA256
, DoAlwaysStat
)
374 off_t FileSize
= Db
.GetFileSize();
375 if (Delink(FileName
,OriginalPath
,Stats
.DeLinkBytes
,FileSize
) == false)
378 // Lookup the overide information
379 pkgTagSection
&Tags
= Db
.Control
.Section
;
380 string Package
= Tags
.FindS("Package");
382 // if we generate a Packages file for a given arch, we use it to
383 // look for overrides. if we run in "simple" mode without the
384 // "Architecures" variable in the config we use the architecure value
389 Architecture
= Tags
.FindS("Architecture");
390 auto_ptr
<Override::Item
> OverItem(Over
.GetItem(Package
,Architecture
));
392 if (Package
.empty() == true)
393 return _error
->Error(_("Archive had no package field"));
395 // If we need to do any rewriting of the header do it now..
396 if (OverItem
.get() == 0)
398 if (NoOverride
== false)
401 ioprintf(c1out
, _(" %s has no override entry\n"), Package
.c_str());
404 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
405 OverItem
->FieldOverride
["Section"] = Tags
.FindS("Section");
406 OverItem
->Priority
= Tags
.FindS("Priority");
410 sprintf(Size
,"%lu", (unsigned long) FileSize
);
412 // Strip the DirStrip prefix from the FileName and add the PathPrefix
414 if (DirStrip
.empty() == false &&
415 FileName
.length() > DirStrip
.length() &&
416 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
417 DirStrip
.begin(),DirStrip
.end()) == 0)
418 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
420 NewFileName
= FileName
;
421 if (PathPrefix
.empty() == false)
422 NewFileName
= flCombine(PathPrefix
,NewFileName
);
424 /* Configuration says we don't want to include the long Description
425 in the package file - instead we want to ship a separated file */
427 if (LongDescription
== false) {
428 desc
= Tags
.FindS("Description").append("\n");
429 OverItem
->FieldOverride
["Description"] = desc
.substr(0, desc
.find('\n')).c_str();
432 // This lists all the changes to the fields we are going to make.
433 // (7 hardcoded + maintainer + suggests + end marker)
434 TFRewriteData Changes
[6+2+OverItem
->FieldOverride
.size()+1+1];
436 unsigned int End
= 0;
437 SetTFRewriteData(Changes
[End
++], "Size", Size
);
438 SetTFRewriteData(Changes
[End
++], "MD5sum", Db
.MD5Res
.c_str());
439 SetTFRewriteData(Changes
[End
++], "SHA1", Db
.SHA1Res
.c_str());
440 SetTFRewriteData(Changes
[End
++], "SHA256", Db
.SHA256Res
.c_str());
441 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
442 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
443 SetTFRewriteData(Changes
[End
++], "Status", 0);
444 SetTFRewriteData(Changes
[End
++], "Optional", 0);
446 string DescriptionMd5
;
447 if (LongDescription
== false) {
448 MD5Summation descmd5
;
449 descmd5
.Add(desc
.c_str());
450 DescriptionMd5
= descmd5
.Result().Value();
451 SetTFRewriteData(Changes
[End
++], "Description-md5", DescriptionMd5
.c_str());
452 if (TransWriter
!= NULL
)
453 TransWriter
->DoPackage(Package
, desc
, DescriptionMd5
);
456 // Rewrite the maintainer field if necessary
458 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
459 if (MaintFailed
== true)
461 if (NoOverride
== false)
464 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
465 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
469 if (NewMaint
.empty() == false)
470 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
472 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
473 dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
474 but dpkg does this append bit. So we do the append bit, at least that way the
475 status file and package file will remain similar. There are other transforms
476 but optional is the only legacy one still in use for some lazy reason. */
477 string OptionalStr
= Tags
.FindS("Optional");
478 if (OptionalStr
.empty() == false)
480 if (Tags
.FindS("Suggests").empty() == false)
481 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
482 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
485 for (map
<string
,string
>::const_iterator I
= OverItem
->FieldOverride
.begin();
486 I
!= OverItem
->FieldOverride
.end(); I
++)
487 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
489 SetTFRewriteData(Changes
[End
++], 0, 0);
491 // Rewrite and store the fields.
492 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
494 fprintf(Output
,"\n");
500 // TranslationWriter::TranslationWriter - Constructor /*{{{*/
501 // ---------------------------------------------------------------------
502 /* Create a Translation-Master file for this Packages file */
503 TranslationWriter::TranslationWriter(string
const &File
, string
const &TransCompress
,
504 mode_t
const &Permissions
) : Output(NULL
),
507 if (File
.empty() == true)
510 Comp
= new MultiCompress(File
, TransCompress
, Permissions
);
511 Output
= Comp
->Input
;
514 // TranslationWriter::DoPackage - Process a single package /*{{{*/
515 // ---------------------------------------------------------------------
516 /* Create a Translation-Master file for this Packages file */
517 bool TranslationWriter::DoPackage(string
const &Pkg
, string
const &Desc
,
523 // Different archs can include different versions and therefore
524 // different descriptions - so we need to check for both name and md5.
525 string
const Record
= Pkg
+ ":" + MD5
;
527 if (Included
.find(Record
) != Included
.end())
530 fprintf(Output
, "Package: %s\nDescription-md5: %s\nDescription-en: %s\n",
531 Pkg
.c_str(), MD5
.c_str(), Desc
.c_str());
533 Included
.insert(Record
);
537 // TranslationWriter::~TranslationWriter - Destructor /*{{{*/
538 // ---------------------------------------------------------------------
540 TranslationWriter::~TranslationWriter()
549 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
550 // ---------------------------------------------------------------------
552 SourcesWriter::SourcesWriter(string
const &BOverrides
,string
const &SOverrides
,
553 string
const &ExtOverrides
)
561 // Process the command line options
562 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
564 // Read the override file
565 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
570 // WTF?? The logic above: if we can't read binary overrides, don't even try
571 // reading source overrides. if we can read binary overrides, then say there
572 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
574 if (ExtOverrides
.empty() == false)
575 SOver
.ReadExtraOverride(ExtOverrides
);
577 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
578 SOver
.ReadOverride(SOverrides
,true);
581 // SourcesWriter::DoPackage - Process a single package /*{{{*/
582 // ---------------------------------------------------------------------
584 bool SourcesWriter::DoPackage(string FileName
)
587 FileFd
F(FileName
,FileFd::ReadOnly
);
588 if (_error
->PendingError() == true)
591 // Stat the file for later
593 if (fstat(F
.Fd(),&St
) != 0)
594 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
596 if (St
.st_size
> 128*1024)
597 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
599 if (BufSize
< (unsigned)St
.st_size
+1)
601 BufSize
= St
.st_size
+1;
602 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
605 if (F
.Read(Buffer
,St
.st_size
) == false)
609 char *Start
= Buffer
;
610 char *BlkEnd
= Buffer
+ St
.st_size
;
612 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
615 SHA256Summation SHA256
;
616 SHA1
.Add((unsigned char *)Start
,BlkEnd
- Start
);
617 SHA256
.Add((unsigned char *)Start
,BlkEnd
- Start
);
619 // Add an extra \n to the end, just in case
622 /* Remove the PGP trailer. Some .dsc's have this without a blank line
624 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
625 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
627 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
634 /* Read records until we locate the Source record. This neatly skips the
635 GPG header (which is RFC822 formed) without any trouble. */
640 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
641 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
642 if (Tags
.Find("Source",Pos
) == true)
644 Start
+= Tags
.size();
649 // Lookup the overide information, finding first the best priority.
651 string Bins
= Tags
.FindS("Binary");
652 char Buffer
[Bins
.length() + 1];
653 auto_ptr
<Override::Item
> OverItem(0);
654 if (Bins
.empty() == false)
656 strcpy(Buffer
,Bins
.c_str());
658 // Ignore too-long errors.
660 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
662 // Look at all the binaries
663 unsigned char BestPrioV
= pkgCache::State::Extra
;
664 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
666 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
670 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
671 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
673 BestPrioV
= NewPrioV
;
674 BestPrio
= Itm
->Priority
;
677 if (OverItem
.get() == 0)
682 // If we need to do any rewriting of the header do it now..
683 if (OverItem
.get() == 0)
685 if (NoOverride
== false)
688 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
691 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
694 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
695 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
696 if (SOverItem
.get() == 0)
698 ioprintf(c1out
, _(" %s has no source override entry\n"), Tags
.FindS("Source").c_str());
699 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
700 if (SOverItem
.get() == 0)
702 ioprintf(c1out
, _(" %s has no binary override entry either\n"), Tags
.FindS("Source").c_str());
703 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
704 *SOverItem
= *OverItem
;
708 // Add the dsc to the files hash list
709 string
const strippedName
= flNotDir(FileName
);
710 std::ostringstream ostreamFiles
;
711 ostreamFiles
<< "\n " << string(MD5
.Result()) << " " << St
.st_size
<< " "
712 << strippedName
<< "\n " << Tags
.FindS("Files");
713 string
const Files
= ostreamFiles
.str();
715 std::ostringstream ostreamSha1
;
716 ostreamSha1
<< "\n " << string(SHA1
.Result()) << " " << St
.st_size
<< " "
717 << strippedName
<< "\n " << Tags
.FindS("Checksums-Sha1");
718 string
const ChecksumsSha1
= ostreamSha1
.str();
720 std::ostringstream ostreamSha256
;
721 ostreamSha256
<< "\n " << string(SHA256
.Result()) << " " << St
.st_size
<< " "
722 << strippedName
<< "\n " << Tags
.FindS("Checksums-Sha256");
723 string
const ChecksumsSha256
= ostreamSha256
.str();
725 // Strip the DirStrip prefix from the FileName and add the PathPrefix
727 if (DirStrip
.empty() == false &&
728 FileName
.length() > DirStrip
.length() &&
729 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
730 NewFileName
= string(OriginalPath
+ DirStrip
.length());
732 NewFileName
= OriginalPath
;
733 if (PathPrefix
.empty() == false)
734 NewFileName
= flCombine(PathPrefix
,NewFileName
);
736 string Directory
= flNotFile(OriginalPath
);
737 string Package
= Tags
.FindS("Source");
739 // Perform the delinking operation over all of the files
741 const char *C
= Files
.c_str();
742 char *RealPath
= NULL
;
743 for (;isspace(*C
); C
++);
746 // Parse each of the elements
747 if (ParseQuoteWord(C
,ParseJnk
) == false ||
748 ParseQuoteWord(C
,ParseJnk
) == false ||
749 ParseQuoteWord(C
,ParseJnk
) == false)
750 return _error
->Error("Error parsing file record");
753 string OriginalPath
= Directory
+ ParseJnk
;
754 if (readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
755 (RealPath
= realpath(OriginalPath
.c_str(),NULL
)) != 0)
757 string RP
= RealPath
;
759 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
764 Directory
= flNotFile(NewFileName
);
765 if (Directory
.length() > 2)
766 Directory
.erase(Directory
.end()-1);
768 // This lists all the changes to the fields we are going to make.
769 // (5 hardcoded + checksums + maintainer + end marker)
770 TFRewriteData Changes
[5+2+1+SOverItem
->FieldOverride
.size()+1];
772 unsigned int End
= 0;
773 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
774 SetTFRewriteData(Changes
[End
++],"Files",Files
.c_str());
775 SetTFRewriteData(Changes
[End
++],"Checksums-Sha1",ChecksumsSha1
.c_str());
776 SetTFRewriteData(Changes
[End
++],"Checksums-Sha256",ChecksumsSha256
.c_str());
777 if (Directory
!= "./")
778 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
779 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
780 SetTFRewriteData(Changes
[End
++],"Status",0);
782 // Rewrite the maintainer field if necessary
784 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
785 if (MaintFailed
== true)
787 if (NoOverride
== false)
790 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
791 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
794 if (NewMaint
.empty() == false)
795 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
797 for (map
<string
,string
>::const_iterator I
= SOverItem
->FieldOverride
.begin();
798 I
!= SOverItem
->FieldOverride
.end(); I
++)
799 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
801 SetTFRewriteData(Changes
[End
++], 0, 0);
803 // Rewrite and store the fields.
804 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
806 fprintf(Output
,"\n");
814 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
815 // ---------------------------------------------------------------------
817 ContentsWriter::ContentsWriter(string
const &DB
, string
const &Arch
) :
818 FTWScanner(Arch
), Db(DB
), Stats(Db
.Stats
)
825 // ContentsWriter::DoPackage - Process a single package /*{{{*/
826 // ---------------------------------------------------------------------
827 /* If Package is the empty string the control record will be parsed to
828 determine what the package name is. */
829 bool ContentsWriter::DoPackage(string FileName
, string Package
)
831 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false, false))
836 // Parse the package name
837 if (Package
.empty() == true)
839 Package
= Db
.Control
.Section
.FindS("Package");
842 Db
.Contents
.Add(Gen
,Package
);
847 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
848 // ---------------------------------------------------------------------
850 bool ContentsWriter::ReadFromPkgs(string
const &PkgFile
,string
const &PkgCompress
)
852 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
853 if (_error
->PendingError() == true)
856 // Open the package file
859 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
863 FileFd
Fd(CompFd
,false);
864 pkgTagFile
Tags(&Fd
);
865 if (_error
->PendingError() == true)
867 Pkgs
.CloseOld(CompFd
,Proc
);
872 pkgTagSection Section
;
873 while (Tags
.Step(Section
) == true)
875 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
876 string Package
= Section
.FindS("Section");
877 if (Package
.empty() == false && Package
.end()[-1] != '/')
880 Package
+= Section
.FindS("Package");
883 Package
+= Section
.FindS("Package");
885 DoPackage(File
,Package
);
886 if (_error
->empty() == false)
888 _error
->Error("Errors apply to file '%s'",File
.c_str());
889 _error
->DumpErrors();
893 // Tidy the compressor
894 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
902 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
903 // ---------------------------------------------------------------------
905 ReleaseWriter::ReleaseWriter(string
const &DB
)
907 AddPattern("Packages");
908 AddPattern("Packages.gz");
909 AddPattern("Packages.bz2");
910 AddPattern("Packages.lzma");
911 AddPattern("Sources");
912 AddPattern("Sources.gz");
913 AddPattern("Sources.bz2");
914 AddPattern("Sources.lzma");
915 AddPattern("Release");
916 AddPattern("md5sum.txt");
919 time_t const now
= time(NULL
);
921 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
927 time_t const validuntil
= now
+ _config
->FindI("APT::FTPArchive::Release::ValidTime", 0);
928 char validstr
[128] = "";
929 if (now
== validuntil
||
930 strftime(validstr
, sizeof(validstr
), "%a, %d %b %Y %H:%M:%S UTC",
931 gmtime(&validuntil
)) == 0)
936 map
<string
,string
> Fields
;
937 Fields
["Origin"] = "";
938 Fields
["Label"] = "";
939 Fields
["Suite"] = "";
940 Fields
["Version"] = "";
941 Fields
["Codename"] = "";
942 Fields
["Date"] = datestr
;
943 Fields
["Valid-Until"] = validstr
;
944 Fields
["Architectures"] = "";
945 Fields
["Components"] = "";
946 Fields
["Description"] = "";
948 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
952 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
953 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
957 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
961 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
962 // ---------------------------------------------------------------------
963 bool ReleaseWriter::DoPackage(string FileName
)
965 // Strip the DirStrip prefix from the FileName and add the PathPrefix
967 if (DirStrip
.empty() == false &&
968 FileName
.length() > DirStrip
.length() &&
969 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
970 DirStrip
.begin(),DirStrip
.end()) == 0)
972 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
973 while (NewFileName
[0] == '/')
974 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
977 NewFileName
= FileName
;
979 if (PathPrefix
.empty() == false)
980 NewFileName
= flCombine(PathPrefix
,NewFileName
);
982 FileFd
fd(FileName
, FileFd::ReadOnly
);
989 CheckSums
[NewFileName
].size
= fd
.Size();
992 MD5
.AddFD(fd
.Fd(), fd
.Size());
993 CheckSums
[NewFileName
].MD5
= MD5
.Result();
997 SHA1
.AddFD(fd
.Fd(), fd
.Size());
998 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
1001 SHA256Summation SHA256
;
1002 SHA256
.AddFD(fd
.Fd(), fd
.Size());
1003 CheckSums
[NewFileName
].SHA256
= SHA256
.Result();
1011 // ReleaseWriter::Finish - Output the checksums /*{{{*/
1012 // ---------------------------------------------------------------------
1013 void ReleaseWriter::Finish()
1015 fprintf(Output
, "MD5Sum:\n");
1016 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1017 I
!= CheckSums
.end();
1020 fprintf(Output
, " %s %16ld %s\n",
1021 (*I
).second
.MD5
.c_str(),
1023 (*I
).first
.c_str());
1026 fprintf(Output
, "SHA1:\n");
1027 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1028 I
!= CheckSums
.end();
1031 fprintf(Output
, " %s %16ld %s\n",
1032 (*I
).second
.SHA1
.c_str(),
1034 (*I
).first
.c_str());
1037 fprintf(Output
, "SHA256:\n");
1038 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1039 I
!= CheckSums
.end();
1042 fprintf(Output
, " %s %16ld %s\n",
1043 (*I
).second
.SHA256
.c_str(),
1045 (*I
).first
.c_str());