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 if (Tags
.Exists("Files"))
712 ostreamFiles
<< "\n " << string(MD5
.Result()) << " " << St
.st_size
<< " "
713 << strippedName
<< "\n " << Tags
.FindS("Files");
714 string
const Files
= ostreamFiles
.str();
716 std::ostringstream ostreamSha1
;
717 if (Tags
.Exists("Checksums-Sha1"))
718 ostreamSha1
<< "\n " << string(SHA1
.Result()) << " " << St
.st_size
<< " "
719 << strippedName
<< "\n " << Tags
.FindS("Checksums-Sha1");
720 string
const ChecksumsSha1
= ostreamSha1
.str();
722 std::ostringstream ostreamSha256
;
723 if (Tags
.Exists("Checksums-Sha256"))
724 ostreamSha256
<< "\n " << string(SHA256
.Result()) << " " << St
.st_size
<< " "
725 << strippedName
<< "\n " << Tags
.FindS("Checksums-Sha256");
726 string
const ChecksumsSha256
= ostreamSha256
.str();
728 // Strip the DirStrip prefix from the FileName and add the PathPrefix
730 if (DirStrip
.empty() == false &&
731 FileName
.length() > DirStrip
.length() &&
732 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
733 NewFileName
= string(OriginalPath
+ DirStrip
.length());
735 NewFileName
= OriginalPath
;
736 if (PathPrefix
.empty() == false)
737 NewFileName
= flCombine(PathPrefix
,NewFileName
);
739 string Directory
= flNotFile(OriginalPath
);
740 string Package
= Tags
.FindS("Source");
742 // Perform the delinking operation over all of the files
744 const char *C
= Files
.c_str();
745 char *RealPath
= NULL
;
746 for (;isspace(*C
); C
++);
749 // Parse each of the elements
750 if (ParseQuoteWord(C
,ParseJnk
) == false ||
751 ParseQuoteWord(C
,ParseJnk
) == false ||
752 ParseQuoteWord(C
,ParseJnk
) == false)
753 return _error
->Error("Error parsing file record");
756 string OriginalPath
= Directory
+ ParseJnk
;
757 if (readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
758 (RealPath
= realpath(OriginalPath
.c_str(),NULL
)) != 0)
760 string RP
= RealPath
;
762 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
767 Directory
= flNotFile(NewFileName
);
768 if (Directory
.length() > 2)
769 Directory
.erase(Directory
.end()-1);
771 // This lists all the changes to the fields we are going to make.
772 // (5 hardcoded + checksums + maintainer + end marker)
773 TFRewriteData Changes
[5+2+1+SOverItem
->FieldOverride
.size()+1];
775 unsigned int End
= 0;
776 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
777 SetTFRewriteData(Changes
[End
++],"Files",Files
.c_str());
778 SetTFRewriteData(Changes
[End
++],"Checksums-Sha1",ChecksumsSha1
.c_str());
779 SetTFRewriteData(Changes
[End
++],"Checksums-Sha256",ChecksumsSha256
.c_str());
780 if (Directory
!= "./")
781 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
782 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
783 SetTFRewriteData(Changes
[End
++],"Status",0);
785 // Rewrite the maintainer field if necessary
787 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
788 if (MaintFailed
== true)
790 if (NoOverride
== false)
793 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
794 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
797 if (NewMaint
.empty() == false)
798 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
800 for (map
<string
,string
>::const_iterator I
= SOverItem
->FieldOverride
.begin();
801 I
!= SOverItem
->FieldOverride
.end(); I
++)
802 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
804 SetTFRewriteData(Changes
[End
++], 0, 0);
806 // Rewrite and store the fields.
807 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
809 fprintf(Output
,"\n");
817 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
818 // ---------------------------------------------------------------------
820 ContentsWriter::ContentsWriter(string
const &DB
, string
const &Arch
) :
821 FTWScanner(Arch
), Db(DB
), Stats(Db
.Stats
)
828 // ContentsWriter::DoPackage - Process a single package /*{{{*/
829 // ---------------------------------------------------------------------
830 /* If Package is the empty string the control record will be parsed to
831 determine what the package name is. */
832 bool ContentsWriter::DoPackage(string FileName
, string Package
)
834 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false, false))
839 // Parse the package name
840 if (Package
.empty() == true)
842 Package
= Db
.Control
.Section
.FindS("Package");
845 Db
.Contents
.Add(Gen
,Package
);
850 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
851 // ---------------------------------------------------------------------
853 bool ContentsWriter::ReadFromPkgs(string
const &PkgFile
,string
const &PkgCompress
)
855 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
856 if (_error
->PendingError() == true)
859 // Open the package file
862 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
866 FileFd
Fd(CompFd
,false);
867 pkgTagFile
Tags(&Fd
);
868 if (_error
->PendingError() == true)
870 Pkgs
.CloseOld(CompFd
,Proc
);
875 pkgTagSection Section
;
876 while (Tags
.Step(Section
) == true)
878 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
879 string Package
= Section
.FindS("Section");
880 if (Package
.empty() == false && Package
.end()[-1] != '/')
883 Package
+= Section
.FindS("Package");
886 Package
+= Section
.FindS("Package");
888 DoPackage(File
,Package
);
889 if (_error
->empty() == false)
891 _error
->Error("Errors apply to file '%s'",File
.c_str());
892 _error
->DumpErrors();
896 // Tidy the compressor
897 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
905 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
906 // ---------------------------------------------------------------------
908 ReleaseWriter::ReleaseWriter(string
const &DB
)
910 if (_config
->FindB("APT::FTPArchive::Release::Default-Patterns", true) == true)
912 AddPattern("Packages");
913 AddPattern("Packages.gz");
914 AddPattern("Packages.bz2");
915 AddPattern("Packages.lzma");
916 AddPattern("Sources");
917 AddPattern("Sources.gz");
918 AddPattern("Sources.bz2");
919 AddPattern("Sources.lzma");
920 AddPattern("Release");
922 AddPattern("md5sum.txt");
924 AddPatterns(_config
->FindVector("APT::FTPArchive::Release::Patterns"));
927 time_t const now
= time(NULL
);
929 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
935 time_t const validuntil
= now
+ _config
->FindI("APT::FTPArchive::Release::ValidTime", 0);
937 if (now
== validuntil
||
938 strftime(validstr
, sizeof(validstr
), "%a, %d %b %Y %H:%M:%S UTC",
939 gmtime(&validuntil
)) == 0)
944 map
<string
,string
> Fields
;
945 Fields
["Origin"] = "";
946 Fields
["Label"] = "";
947 Fields
["Suite"] = "";
948 Fields
["Version"] = "";
949 Fields
["Codename"] = "";
950 Fields
["Date"] = datestr
;
951 Fields
["Valid-Until"] = validstr
;
952 Fields
["Architectures"] = "";
953 Fields
["Components"] = "";
954 Fields
["Description"] = "";
956 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
960 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
961 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
965 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
969 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
970 // ---------------------------------------------------------------------
971 bool ReleaseWriter::DoPackage(string FileName
)
973 // Strip the DirStrip prefix from the FileName and add the PathPrefix
975 if (DirStrip
.empty() == false &&
976 FileName
.length() > DirStrip
.length() &&
977 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
978 DirStrip
.begin(),DirStrip
.end()) == 0)
980 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
981 while (NewFileName
[0] == '/')
982 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
985 NewFileName
= FileName
;
987 if (PathPrefix
.empty() == false)
988 NewFileName
= flCombine(PathPrefix
,NewFileName
);
990 FileFd
fd(FileName
, FileFd::ReadOnly
);
997 CheckSums
[NewFileName
].size
= fd
.Size();
1000 MD5
.AddFD(fd
.Fd(), fd
.Size());
1001 CheckSums
[NewFileName
].MD5
= MD5
.Result();
1005 SHA1
.AddFD(fd
.Fd(), fd
.Size());
1006 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
1009 SHA256Summation SHA256
;
1010 SHA256
.AddFD(fd
.Fd(), fd
.Size());
1011 CheckSums
[NewFileName
].SHA256
= SHA256
.Result();
1019 // ReleaseWriter::Finish - Output the checksums /*{{{*/
1020 // ---------------------------------------------------------------------
1021 void ReleaseWriter::Finish()
1023 fprintf(Output
, "MD5Sum:\n");
1024 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1025 I
!= CheckSums
.end();
1028 fprintf(Output
, " %s %16ld %s\n",
1029 (*I
).second
.MD5
.c_str(),
1031 (*I
).first
.c_str());
1034 fprintf(Output
, "SHA1:\n");
1035 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1036 I
!= CheckSums
.end();
1039 fprintf(Output
, " %s %16ld %s\n",
1040 (*I
).second
.SHA1
.c_str(),
1042 (*I
).first
.c_str());
1045 fprintf(Output
, "SHA256:\n");
1046 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1047 I
!= CheckSums
.end();
1050 fprintf(Output
, " %s %16ld %s\n",
1051 (*I
).second
.SHA256
.c_str(),
1053 (*I
).first
.c_str());