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/aptconfiguration.h>
21 #include <apt-pkg/md5.h>
22 #include <apt-pkg/sha1.h>
23 #include <apt-pkg/sha256.h>
24 #include <apt-pkg/deblistparser.h>
26 #include <sys/types.h>
36 #include "apt-ftparchive.h"
37 #include "multicompress.h"
40 FTWScanner
*FTWScanner::Owner
;
42 // SetTFRewriteData - Helper for setting rewrite lists /*{{{*/
43 // ---------------------------------------------------------------------
45 inline void SetTFRewriteData(struct TFRewriteData
&tfrd
,
48 const char *newtag
= 0)
51 tfrd
.Rewrite
= rewrite
;
56 // FTWScanner::FTWScanner - Constructor /*{{{*/
57 // ---------------------------------------------------------------------
59 FTWScanner::FTWScanner(string
const &Arch
): Arch(Arch
)
62 NoLinkAct
= !_config
->FindB("APT::FTPArchive::DeLinkAct",true);
64 DoMD5
= _config
->FindB("APT::FTPArchive::MD5",true);
65 DoSHA1
= _config
->FindB("APT::FTPArchive::SHA1",true);
66 DoSHA256
= _config
->FindB("APT::FTPArchive::SHA256",true);
69 // FTWScanner::Scanner - FTW Scanner /*{{{*/
70 // ---------------------------------------------------------------------
71 /* This is the FTW scanner, it processes each directory element in the
73 int FTWScanner::ScannerFTW(const char *File
,const struct stat
*sb
,int Flag
)
78 ioprintf(c1out
, _("W: Unable to read directory %s\n"), File
);
83 ioprintf(c1out
, _("W: Unable to stat %s\n"), File
);
88 return ScannerFile(File
, true);
91 // FTWScanner::ScannerFile - File Scanner /*{{{*/
92 // ---------------------------------------------------------------------
94 int FTWScanner::ScannerFile(const char *File
, bool const &ReadLink
)
96 const char *LastComponent
= strrchr(File
, '/');
97 char *RealPath
= NULL
;
99 if (LastComponent
== NULL
)
100 LastComponent
= File
;
104 vector
<string
>::const_iterator I
;
105 for(I
= Owner
->Patterns
.begin(); I
!= Owner
->Patterns
.end(); ++I
)
107 if (fnmatch((*I
).c_str(), LastComponent
, 0) == 0)
110 if (I
== Owner
->Patterns
.end())
113 /* Process it. If the file is a link then resolve it into an absolute
114 name.. This works best if the directory components the scanner are
115 given are not links themselves. */
117 Owner
->OriginalPath
= File
;
119 readlink(File
,Jnk
,sizeof(Jnk
)) != -1 &&
120 (RealPath
= realpath(File
,NULL
)) != 0)
122 Owner
->DoPackage(RealPath
);
126 Owner
->DoPackage(File
);
128 if (_error
->empty() == false)
130 // Print any errors or warnings found
132 bool SeenPath
= false;
133 while (_error
->empty() == false)
137 bool const Type
= _error
->PopMessage(Err
);
139 cerr
<< _("E: ") << Err
<< endl
;
141 cerr
<< _("W: ") << Err
<< endl
;
143 if (Err
.find(File
) != string::npos
)
147 if (SeenPath
== false)
148 cerr
<< _("E: Errors apply to file ") << "'" << File
<< "'" << endl
;
155 // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
156 // ---------------------------------------------------------------------
158 bool FTWScanner::RecursiveScan(string
const &Dir
)
160 char *RealPath
= NULL
;
161 /* If noprefix is set then jam the scan root in, so we don't generate
162 link followed paths out of control */
163 if (InternalPrefix
.empty() == true)
165 if ((RealPath
= realpath(Dir
.c_str(),NULL
)) == 0)
166 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
167 InternalPrefix
= RealPath
;
171 // Do recursive directory searching
173 int const Res
= ftw(Dir
.c_str(),ScannerFTW
,30);
175 // Error treewalking?
178 if (_error
->PendingError() == false)
179 _error
->Errno("ftw",_("Tree walking failed"));
186 // FTWScanner::LoadFileList - Load the file list from a file /*{{{*/
187 // ---------------------------------------------------------------------
188 /* This is an alternative to using FTW to locate files, it reads the list
189 of files from another file. */
190 bool FTWScanner::LoadFileList(string
const &Dir
, string
const &File
)
192 char *RealPath
= NULL
;
193 /* If noprefix is set then jam the scan root in, so we don't generate
194 link followed paths out of control */
195 if (InternalPrefix
.empty() == true)
197 if ((RealPath
= realpath(Dir
.c_str(),NULL
)) == 0)
198 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
199 InternalPrefix
= RealPath
;
204 FILE *List
= fopen(File
.c_str(),"r");
206 return _error
->Errno("fopen",_("Failed to open %s"),File
.c_str());
208 /* We are a tad tricky here.. We prefix the buffer with the directory
209 name, that way if we need a full path with just use line.. Sneaky and
213 if (Dir
.empty() == true || Dir
.end()[-1] != '/')
214 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s/",Dir
.c_str());
216 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s",Dir
.c_str());
217 while (fgets(FileStart
,sizeof(Line
) - (FileStart
- Line
),List
) != 0)
219 char *FileName
= _strstrip(FileStart
);
220 if (FileName
[0] == 0)
223 if (FileName
[0] != '/')
225 if (FileName
!= FileStart
)
226 memmove(FileStart
,FileName
,strlen(FileStart
));
233 if (stat(FileName
,&St
) != 0)
237 if (ScannerFile(FileName
, false) != 0)
245 // FTWScanner::Delink - Delink symlinks /*{{{*/
246 // ---------------------------------------------------------------------
248 bool FTWScanner::Delink(string
&FileName
,const char *OriginalPath
,
249 unsigned long &DeLinkBytes
,
250 off_t
const &FileSize
)
252 // See if this isn't an internaly prefix'd file name.
253 if (InternalPrefix
.empty() == false &&
254 InternalPrefix
.length() < FileName
.length() &&
255 stringcmp(FileName
.begin(),FileName
.begin() + InternalPrefix
.length(),
256 InternalPrefix
.begin(),InternalPrefix
.end()) != 0)
258 if (DeLinkLimit
!= 0 && DeLinkBytes
/1024 < DeLinkLimit
)
260 // Tidy up the display
261 if (DeLinkBytes
== 0)
265 ioprintf(c1out
, _(" DeLink %s [%s]\n"), (OriginalPath
+ InternalPrefix
.length()),
266 SizeToStr(FileSize
).c_str());
269 if (NoLinkAct
== false)
272 if (readlink(OriginalPath
,OldLink
,sizeof(OldLink
)) == -1)
273 _error
->Errno("readlink",_("Failed to readlink %s"),OriginalPath
);
276 if (unlink(OriginalPath
) != 0)
277 _error
->Errno("unlink",_("Failed to unlink %s"),OriginalPath
);
280 if (link(FileName
.c_str(),OriginalPath
) != 0)
282 // Panic! Restore the symlink
283 symlink(OldLink
,OriginalPath
);
284 return _error
->Errno("link",_("*** Failed to link %s to %s"),
292 DeLinkBytes
+= FileSize
;
293 if (DeLinkBytes
/1024 >= DeLinkLimit
)
294 ioprintf(c1out
, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes
).c_str());
297 FileName
= OriginalPath
;
304 // PackagesWriter::PackagesWriter - Constructor /*{{{*/
305 // ---------------------------------------------------------------------
307 PackagesWriter::PackagesWriter(string
const &DB
,string
const &Overrides
,string
const &ExtOverrides
,
308 string
const &Arch
) :
309 FTWScanner(Arch
), Db(DB
), Stats(Db
.Stats
), TransWriter(NULL
)
312 SetExts(".deb .udeb");
315 // Process the command line options
316 DoMD5
= _config
->FindB("APT::FTPArchive::Packages::MD5",DoMD5
);
317 DoSHA1
= _config
->FindB("APT::FTPArchive::Packages::SHA1",DoSHA1
);
318 DoSHA256
= _config
->FindB("APT::FTPArchive::Packages::SHA256",DoSHA256
);
319 DoAlwaysStat
= _config
->FindB("APT::FTPArchive::AlwaysStat", false);
320 DoContents
= _config
->FindB("APT::FTPArchive::Contents",true);
321 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
322 LongDescription
= _config
->FindB("APT::FTPArchive::LongDescription",true);
324 if (Db
.Loaded() == false)
327 // Read the override file
328 if (Overrides
.empty() == false && Over
.ReadOverride(Overrides
) == false)
333 if (ExtOverrides
.empty() == false)
334 Over
.ReadExtraOverride(ExtOverrides
);
336 _error
->DumpErrors();
339 // FTWScanner::SetExts - Set extensions to support /*{{{*/
340 // ---------------------------------------------------------------------
342 bool FTWScanner::SetExts(string
const &Vals
)
345 string::size_type Start
= 0;
346 while (Start
<= Vals
.length()-1)
348 string::size_type
const Space
= Vals
.find(' ',Start
);
349 string::size_type
const Length
= ((Space
== string::npos
) ? Vals
.length() : Space
) - Start
;
350 if ( Arch
.empty() == false )
352 AddPattern(string("*_") + Arch
+ Vals
.substr(Start
, Length
));
353 AddPattern(string("*_all") + Vals
.substr(Start
, Length
));
356 AddPattern(string("*") + Vals
.substr(Start
, Length
));
365 // PackagesWriter::DoPackage - Process a single package /*{{{*/
366 // ---------------------------------------------------------------------
367 /* This method takes a package and gets its control information and
368 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
369 rewritten and the path/size/hash appended. */
370 bool PackagesWriter::DoPackage(string FileName
)
372 // Pull all the data we need form the DB
373 if (Db
.GetFileInfo(FileName
, true, DoContents
, true, DoMD5
, DoSHA1
, DoSHA256
, DoAlwaysStat
)
379 off_t FileSize
= Db
.GetFileSize();
380 if (Delink(FileName
,OriginalPath
,Stats
.DeLinkBytes
,FileSize
) == false)
383 // Lookup the overide information
384 pkgTagSection
&Tags
= Db
.Control
.Section
;
385 string Package
= Tags
.FindS("Package");
387 // if we generate a Packages file for a given arch, we use it to
388 // look for overrides. if we run in "simple" mode without the
389 // "Architecures" variable in the config we use the architecure value
394 Architecture
= Tags
.FindS("Architecture");
395 auto_ptr
<Override::Item
> OverItem(Over
.GetItem(Package
,Architecture
));
397 if (Package
.empty() == true)
398 return _error
->Error(_("Archive had no package field"));
400 // If we need to do any rewriting of the header do it now..
401 if (OverItem
.get() == 0)
403 if (NoOverride
== false)
406 ioprintf(c1out
, _(" %s has no override entry\n"), Package
.c_str());
409 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
410 OverItem
->FieldOverride
["Section"] = Tags
.FindS("Section");
411 OverItem
->Priority
= Tags
.FindS("Priority");
415 sprintf(Size
,"%lu", (unsigned long) FileSize
);
417 // Strip the DirStrip prefix from the FileName and add the PathPrefix
419 if (DirStrip
.empty() == false &&
420 FileName
.length() > DirStrip
.length() &&
421 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
422 DirStrip
.begin(),DirStrip
.end()) == 0)
423 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
425 NewFileName
= FileName
;
426 if (PathPrefix
.empty() == false)
427 NewFileName
= flCombine(PathPrefix
,NewFileName
);
429 /* Configuration says we don't want to include the long Description
430 in the package file - instead we want to ship a separated file */
432 if (LongDescription
== false) {
433 desc
= Tags
.FindS("Description").append("\n");
434 OverItem
->FieldOverride
["Description"] = desc
.substr(0, desc
.find('\n')).c_str();
437 // This lists all the changes to the fields we are going to make.
438 // (7 hardcoded + maintainer + suggests + end marker)
439 TFRewriteData Changes
[6+2+OverItem
->FieldOverride
.size()+1+1];
441 unsigned int End
= 0;
442 SetTFRewriteData(Changes
[End
++], "Size", Size
);
444 SetTFRewriteData(Changes
[End
++], "MD5sum", Db
.MD5Res
.c_str());
446 SetTFRewriteData(Changes
[End
++], "SHA1", Db
.SHA1Res
.c_str());
447 if (DoSHA256
== true)
448 SetTFRewriteData(Changes
[End
++], "SHA256", Db
.SHA256Res
.c_str());
449 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
450 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
451 SetTFRewriteData(Changes
[End
++], "Status", 0);
452 SetTFRewriteData(Changes
[End
++], "Optional", 0);
454 string DescriptionMd5
;
455 if (LongDescription
== false) {
456 MD5Summation descmd5
;
457 descmd5
.Add(desc
.c_str());
458 DescriptionMd5
= descmd5
.Result().Value();
459 SetTFRewriteData(Changes
[End
++], "Description-md5", DescriptionMd5
.c_str());
460 if (TransWriter
!= NULL
)
461 TransWriter
->DoPackage(Package
, desc
, DescriptionMd5
);
464 // Rewrite the maintainer field if necessary
466 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
467 if (MaintFailed
== true)
469 if (NoOverride
== false)
472 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
473 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
477 if (NewMaint
.empty() == false)
478 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
480 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
481 dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
482 but dpkg does this append bit. So we do the append bit, at least that way the
483 status file and package file will remain similar. There are other transforms
484 but optional is the only legacy one still in use for some lazy reason. */
485 string OptionalStr
= Tags
.FindS("Optional");
486 if (OptionalStr
.empty() == false)
488 if (Tags
.FindS("Suggests").empty() == false)
489 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
490 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
493 for (map
<string
,string
>::const_iterator I
= OverItem
->FieldOverride
.begin();
494 I
!= OverItem
->FieldOverride
.end(); I
++)
495 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
497 SetTFRewriteData(Changes
[End
++], 0, 0);
499 // Rewrite and store the fields.
500 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
502 fprintf(Output
,"\n");
508 // TranslationWriter::TranslationWriter - Constructor /*{{{*/
509 // ---------------------------------------------------------------------
510 /* Create a Translation-Master file for this Packages file */
511 TranslationWriter::TranslationWriter(string
const &File
, string
const &TransCompress
,
512 mode_t
const &Permissions
) : Output(NULL
),
515 if (File
.empty() == true)
518 Comp
= new MultiCompress(File
, TransCompress
, Permissions
);
519 Output
= Comp
->Input
;
522 // TranslationWriter::DoPackage - Process a single package /*{{{*/
523 // ---------------------------------------------------------------------
524 /* Create a Translation-Master file for this Packages file */
525 bool TranslationWriter::DoPackage(string
const &Pkg
, string
const &Desc
,
531 // Different archs can include different versions and therefore
532 // different descriptions - so we need to check for both name and md5.
533 string
const Record
= Pkg
+ ":" + MD5
;
535 if (Included
.find(Record
) != Included
.end())
538 fprintf(Output
, "Package: %s\nDescription-md5: %s\nDescription-en: %s\n",
539 Pkg
.c_str(), MD5
.c_str(), Desc
.c_str());
541 Included
.insert(Record
);
545 // TranslationWriter::~TranslationWriter - Destructor /*{{{*/
546 // ---------------------------------------------------------------------
548 TranslationWriter::~TranslationWriter()
557 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
558 // ---------------------------------------------------------------------
560 SourcesWriter::SourcesWriter(string
const &BOverrides
,string
const &SOverrides
,
561 string
const &ExtOverrides
)
569 // Process the command line options
570 DoMD5
= _config
->FindB("APT::FTPArchive::Sources::MD5",DoMD5
);
571 DoSHA1
= _config
->FindB("APT::FTPArchive::Sources::SHA1",DoSHA1
);
572 DoSHA256
= _config
->FindB("APT::FTPArchive::Sources::SHA256",DoSHA256
);
573 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
575 // Read the override file
576 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
581 // WTF?? The logic above: if we can't read binary overrides, don't even try
582 // reading source overrides. if we can read binary overrides, then say there
583 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
585 if (ExtOverrides
.empty() == false)
586 SOver
.ReadExtraOverride(ExtOverrides
);
588 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
589 SOver
.ReadOverride(SOverrides
,true);
592 // SourcesWriter::DoPackage - Process a single package /*{{{*/
593 // ---------------------------------------------------------------------
595 bool SourcesWriter::DoPackage(string FileName
)
598 FileFd
F(FileName
,FileFd::ReadOnly
);
599 if (_error
->PendingError() == true)
602 // Stat the file for later
604 if (fstat(F
.Fd(),&St
) != 0)
605 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
607 if (St
.st_size
> 128*1024)
608 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
610 if (BufSize
< (unsigned)St
.st_size
+1)
612 BufSize
= St
.st_size
+1;
613 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
616 if (F
.Read(Buffer
,St
.st_size
) == false)
620 char *Start
= Buffer
;
621 char *BlkEnd
= Buffer
+ St
.st_size
;
625 SHA256Summation SHA256
;
628 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
630 SHA1
.Add((unsigned char *)Start
,BlkEnd
- Start
);
631 if (DoSHA256
== true)
632 SHA256
.Add((unsigned char *)Start
,BlkEnd
- Start
);
634 // Add an extra \n to the end, just in case
637 /* Remove the PGP trailer. Some .dsc's have this without a blank line
639 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
640 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
642 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
649 /* Read records until we locate the Source record. This neatly skips the
650 GPG header (which is RFC822 formed) without any trouble. */
655 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
656 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
657 if (Tags
.Find("Source",Pos
) == true)
659 Start
+= Tags
.size();
664 // Lookup the overide information, finding first the best priority.
666 string Bins
= Tags
.FindS("Binary");
667 char Buffer
[Bins
.length() + 1];
668 auto_ptr
<Override::Item
> OverItem(0);
669 if (Bins
.empty() == false)
671 strcpy(Buffer
,Bins
.c_str());
673 // Ignore too-long errors.
675 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
677 // Look at all the binaries
678 unsigned char BestPrioV
= pkgCache::State::Extra
;
679 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
681 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
685 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
686 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
688 BestPrioV
= NewPrioV
;
689 BestPrio
= Itm
->Priority
;
692 if (OverItem
.get() == 0)
697 // If we need to do any rewriting of the header do it now..
698 if (OverItem
.get() == 0)
700 if (NoOverride
== false)
703 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
706 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
709 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
710 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
711 if (SOverItem
.get() == 0)
713 ioprintf(c1out
, _(" %s has no source override entry\n"), Tags
.FindS("Source").c_str());
714 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
715 if (SOverItem
.get() == 0)
717 ioprintf(c1out
, _(" %s has no binary override entry either\n"), Tags
.FindS("Source").c_str());
718 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
719 *SOverItem
= *OverItem
;
723 // Add the dsc to the files hash list
724 string
const strippedName
= flNotDir(FileName
);
725 std::ostringstream ostreamFiles
;
726 if (DoMD5
== true && Tags
.Exists("Files"))
727 ostreamFiles
<< "\n " << string(MD5
.Result()) << " " << St
.st_size
<< " "
728 << strippedName
<< "\n " << Tags
.FindS("Files");
729 string
const Files
= ostreamFiles
.str();
731 std::ostringstream ostreamSha1
;
732 if (DoSHA1
== true && Tags
.Exists("Checksums-Sha1"))
733 ostreamSha1
<< "\n " << string(SHA1
.Result()) << " " << St
.st_size
<< " "
734 << strippedName
<< "\n " << Tags
.FindS("Checksums-Sha1");
735 string
const ChecksumsSha1
= ostreamSha1
.str();
737 std::ostringstream ostreamSha256
;
738 if (DoSHA256
== true && Tags
.Exists("Checksums-Sha256"))
739 ostreamSha256
<< "\n " << string(SHA256
.Result()) << " " << St
.st_size
<< " "
740 << strippedName
<< "\n " << Tags
.FindS("Checksums-Sha256");
741 string
const ChecksumsSha256
= ostreamSha256
.str();
743 // Strip the DirStrip prefix from the FileName and add the PathPrefix
745 if (DirStrip
.empty() == false &&
746 FileName
.length() > DirStrip
.length() &&
747 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
748 NewFileName
= string(OriginalPath
+ DirStrip
.length());
750 NewFileName
= OriginalPath
;
751 if (PathPrefix
.empty() == false)
752 NewFileName
= flCombine(PathPrefix
,NewFileName
);
754 string Directory
= flNotFile(OriginalPath
);
755 string Package
= Tags
.FindS("Source");
757 // Perform the delinking operation over all of the files
759 const char *C
= Files
.c_str();
760 char *RealPath
= NULL
;
761 for (;isspace(*C
); C
++);
764 // Parse each of the elements
765 if (ParseQuoteWord(C
,ParseJnk
) == false ||
766 ParseQuoteWord(C
,ParseJnk
) == false ||
767 ParseQuoteWord(C
,ParseJnk
) == false)
768 return _error
->Error("Error parsing file record");
771 string OriginalPath
= Directory
+ ParseJnk
;
772 if (readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
773 (RealPath
= realpath(OriginalPath
.c_str(),NULL
)) != 0)
775 string RP
= RealPath
;
777 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
782 Directory
= flNotFile(NewFileName
);
783 if (Directory
.length() > 2)
784 Directory
.erase(Directory
.end()-1);
786 // This lists all the changes to the fields we are going to make.
787 // (5 hardcoded + checksums + maintainer + end marker)
788 TFRewriteData Changes
[5+2+1+SOverItem
->FieldOverride
.size()+1];
790 unsigned int End
= 0;
791 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
792 if (Files
.empty() == false)
793 SetTFRewriteData(Changes
[End
++],"Files",Files
.c_str());
794 if (ChecksumsSha1
.empty() == false)
795 SetTFRewriteData(Changes
[End
++],"Checksums-Sha1",ChecksumsSha1
.c_str());
796 if (ChecksumsSha256
.empty() == false)
797 SetTFRewriteData(Changes
[End
++],"Checksums-Sha256",ChecksumsSha256
.c_str());
798 if (Directory
!= "./")
799 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
800 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
801 SetTFRewriteData(Changes
[End
++],"Status",0);
803 // Rewrite the maintainer field if necessary
805 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
806 if (MaintFailed
== true)
808 if (NoOverride
== false)
811 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
812 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
815 if (NewMaint
.empty() == false)
816 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
818 for (map
<string
,string
>::const_iterator I
= SOverItem
->FieldOverride
.begin();
819 I
!= SOverItem
->FieldOverride
.end(); I
++)
820 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
822 SetTFRewriteData(Changes
[End
++], 0, 0);
824 // Rewrite and store the fields.
825 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
827 fprintf(Output
,"\n");
835 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
836 // ---------------------------------------------------------------------
838 ContentsWriter::ContentsWriter(string
const &DB
, string
const &Arch
) :
839 FTWScanner(Arch
), Db(DB
), Stats(Db
.Stats
)
846 // ContentsWriter::DoPackage - Process a single package /*{{{*/
847 // ---------------------------------------------------------------------
848 /* If Package is the empty string the control record will be parsed to
849 determine what the package name is. */
850 bool ContentsWriter::DoPackage(string FileName
, string Package
)
852 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false, false))
857 // Parse the package name
858 if (Package
.empty() == true)
860 Package
= Db
.Control
.Section
.FindS("Package");
863 Db
.Contents
.Add(Gen
,Package
);
868 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
869 // ---------------------------------------------------------------------
871 bool ContentsWriter::ReadFromPkgs(string
const &PkgFile
,string
const &PkgCompress
)
873 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
874 if (_error
->PendingError() == true)
877 // Open the package file
880 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
884 FileFd
Fd(CompFd
,false);
885 pkgTagFile
Tags(&Fd
);
886 if (_error
->PendingError() == true)
888 Pkgs
.CloseOld(CompFd
,Proc
);
893 pkgTagSection Section
;
894 while (Tags
.Step(Section
) == true)
896 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
897 string Package
= Section
.FindS("Section");
898 if (Package
.empty() == false && Package
.end()[-1] != '/')
901 Package
+= Section
.FindS("Package");
904 Package
+= Section
.FindS("Package");
906 DoPackage(File
,Package
);
907 if (_error
->empty() == false)
909 _error
->Error("Errors apply to file '%s'",File
.c_str());
910 _error
->DumpErrors();
914 // Tidy the compressor
915 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
923 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
924 // ---------------------------------------------------------------------
926 ReleaseWriter::ReleaseWriter(string
const &DB
)
928 if (_config
->FindB("APT::FTPArchive::Release::Default-Patterns", true) == true)
930 AddPattern("Packages");
931 AddPattern("Packages.gz");
932 AddPattern("Packages.bz2");
933 AddPattern("Packages.lzma");
934 AddPattern("Packages.xz");
935 AddPattern("Sources");
936 AddPattern("Sources.gz");
937 AddPattern("Sources.bz2");
938 AddPattern("Sources.lzma");
939 AddPattern("Sources.xz");
940 AddPattern("Release");
942 AddPattern("md5sum.txt");
944 AddPatterns(_config
->FindVector("APT::FTPArchive::Release::Patterns"));
947 time_t const now
= time(NULL
);
949 setlocale(LC_TIME
, "C");
952 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
958 time_t const validuntil
= now
+ _config
->FindI("APT::FTPArchive::Release::ValidTime", 0);
960 if (now
== validuntil
||
961 strftime(validstr
, sizeof(validstr
), "%a, %d %b %Y %H:%M:%S UTC",
962 gmtime(&validuntil
)) == 0)
967 setlocale(LC_TIME
, "");
969 map
<string
,string
> Fields
;
970 Fields
["Origin"] = "";
971 Fields
["Label"] = "";
972 Fields
["Suite"] = "";
973 Fields
["Version"] = "";
974 Fields
["Codename"] = "";
975 Fields
["Date"] = datestr
;
976 Fields
["Valid-Until"] = validstr
;
977 Fields
["Architectures"] = "";
978 Fields
["Components"] = "";
979 Fields
["Description"] = "";
981 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
985 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
986 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
990 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
993 DoMD5
= _config
->FindB("APT::FTPArchive::Release::MD5",DoMD5
);
994 DoSHA1
= _config
->FindB("APT::FTPArchive::Release::SHA1",DoSHA1
);
995 DoSHA256
= _config
->FindB("APT::FTPArchive::Release::SHA256",DoSHA256
);
998 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
999 // ---------------------------------------------------------------------
1000 bool ReleaseWriter::DoPackage(string FileName
)
1002 // Strip the DirStrip prefix from the FileName and add the PathPrefix
1004 if (DirStrip
.empty() == false &&
1005 FileName
.length() > DirStrip
.length() &&
1006 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
1007 DirStrip
.begin(),DirStrip
.end()) == 0)
1009 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
1010 while (NewFileName
[0] == '/')
1011 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
1014 NewFileName
= FileName
;
1016 if (PathPrefix
.empty() == false)
1017 NewFileName
= flCombine(PathPrefix
,NewFileName
);
1019 FileFd
fd(FileName
, FileFd::ReadOnly
);
1026 CheckSums
[NewFileName
].size
= fd
.Size();
1031 MD5
.AddFD(fd
.Fd(), fd
.Size());
1032 CheckSums
[NewFileName
].MD5
= MD5
.Result();
1038 SHA1
.AddFD(fd
.Fd(), fd
.Size());
1039 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
1042 if (DoSHA256
== true)
1044 SHA256Summation SHA256
;
1045 SHA256
.AddFD(fd
.Fd(), fd
.Size());
1046 CheckSums
[NewFileName
].SHA256
= SHA256
.Result();
1055 // ReleaseWriter::Finish - Output the checksums /*{{{*/
1056 // ---------------------------------------------------------------------
1057 void ReleaseWriter::Finish()
1061 fprintf(Output
, "MD5Sum:\n");
1062 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1063 I
!= CheckSums
.end(); ++I
)
1065 fprintf(Output
, " %s %16ld %s\n",
1066 (*I
).second
.MD5
.c_str(),
1068 (*I
).first
.c_str());
1073 fprintf(Output
, "SHA1:\n");
1074 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1075 I
!= CheckSums
.end(); ++I
)
1077 fprintf(Output
, " %s %16ld %s\n",
1078 (*I
).second
.SHA1
.c_str(),
1080 (*I
).first
.c_str());
1083 if (DoSHA256
== true)
1085 fprintf(Output
, "SHA256:\n");
1086 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1087 I
!= CheckSums
.end(); ++I
)
1089 fprintf(Output
, " %s %16ld %s\n",
1090 (*I
).second
.SHA256
.c_str(),
1092 (*I
).first
.c_str());