]>
git.saurik.com Git - apt.git/blob - ftparchive/writer.cc
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>
34 #include "apt-ftparchive.h"
35 #include "multicompress.h"
38 FTWScanner
*FTWScanner::Owner
;
40 // SetTFRewriteData - Helper for setting rewrite lists /*{{{*/
41 // ---------------------------------------------------------------------
43 inline void SetTFRewriteData(struct TFRewriteData
&tfrd
,
46 const char *newtag
= 0)
49 tfrd
.Rewrite
= rewrite
;
54 // FTWScanner::FTWScanner - Constructor /*{{{*/
55 // ---------------------------------------------------------------------
57 FTWScanner::FTWScanner(string
const &Arch
): Arch(Arch
)
60 NoLinkAct
= !_config
->FindB("APT::FTPArchive::DeLinkAct",true);
63 // FTWScanner::Scanner - FTW Scanner /*{{{*/
64 // ---------------------------------------------------------------------
65 /* This is the FTW scanner, it processes each directory element in the
67 int FTWScanner::ScannerFTW(const char *File
,const struct stat
*sb
,int Flag
)
72 ioprintf(c1out
, _("W: Unable to read directory %s\n"), File
);
77 ioprintf(c1out
, _("W: Unable to stat %s\n"), File
);
82 return ScannerFile(File
, true);
85 // FTWScanner::ScannerFile - File Scanner /*{{{*/
86 // ---------------------------------------------------------------------
88 int FTWScanner::ScannerFile(const char *File
, bool const &ReadLink
)
90 const char *LastComponent
= strrchr(File
, '/');
91 char *RealPath
= NULL
;
93 if (LastComponent
== NULL
)
98 vector
<string
>::const_iterator I
;
99 for(I
= Owner
->Patterns
.begin(); I
!= Owner
->Patterns
.end(); ++I
)
101 if (fnmatch((*I
).c_str(), LastComponent
, 0) == 0)
104 if (I
== Owner
->Patterns
.end())
107 /* Process it. If the file is a link then resolve it into an absolute
108 name.. This works best if the directory components the scanner are
109 given are not links themselves. */
111 Owner
->OriginalPath
= File
;
113 readlink(File
,Jnk
,sizeof(Jnk
)) != -1 &&
114 (RealPath
= realpath(File
,NULL
)) != 0)
116 Owner
->DoPackage(RealPath
);
120 Owner
->DoPackage(File
);
122 if (_error
->empty() == false)
124 // Print any errors or warnings found
126 bool SeenPath
= false;
127 while (_error
->empty() == false)
131 bool const Type
= _error
->PopMessage(Err
);
133 cerr
<< _("E: ") << Err
<< endl
;
135 cerr
<< _("W: ") << Err
<< endl
;
137 if (Err
.find(File
) != string::npos
)
141 if (SeenPath
== false)
142 cerr
<< _("E: Errors apply to file ") << "'" << File
<< "'" << endl
;
149 // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
150 // ---------------------------------------------------------------------
152 bool FTWScanner::RecursiveScan(string
const &Dir
)
154 char *RealPath
= NULL
;
155 /* If noprefix is set then jam the scan root in, so we don't generate
156 link followed paths out of control */
157 if (InternalPrefix
.empty() == true)
159 if ((RealPath
= realpath(Dir
.c_str(),NULL
)) == 0)
160 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
161 InternalPrefix
= RealPath
;
165 // Do recursive directory searching
167 int const Res
= ftw(Dir
.c_str(),ScannerFTW
,30);
169 // Error treewalking?
172 if (_error
->PendingError() == false)
173 _error
->Errno("ftw",_("Tree walking failed"));
180 // FTWScanner::LoadFileList - Load the file list from a file /*{{{*/
181 // ---------------------------------------------------------------------
182 /* This is an alternative to using FTW to locate files, it reads the list
183 of files from another file. */
184 bool FTWScanner::LoadFileList(string
const &Dir
, string
const &File
)
186 char *RealPath
= NULL
;
187 /* If noprefix is set then jam the scan root in, so we don't generate
188 link followed paths out of control */
189 if (InternalPrefix
.empty() == true)
191 if ((RealPath
= realpath(Dir
.c_str(),NULL
)) == 0)
192 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
193 InternalPrefix
= RealPath
;
198 FILE *List
= fopen(File
.c_str(),"r");
200 return _error
->Errno("fopen",_("Failed to open %s"),File
.c_str());
202 /* We are a tad tricky here.. We prefix the buffer with the directory
203 name, that way if we need a full path with just use line.. Sneaky and
207 if (Dir
.empty() == true || Dir
.end()[-1] != '/')
208 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s/",Dir
.c_str());
210 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s",Dir
.c_str());
211 while (fgets(FileStart
,sizeof(Line
) - (FileStart
- Line
),List
) != 0)
213 char *FileName
= _strstrip(FileStart
);
214 if (FileName
[0] == 0)
217 if (FileName
[0] != '/')
219 if (FileName
!= FileStart
)
220 memmove(FileStart
,FileName
,strlen(FileStart
));
227 if (stat(FileName
,&St
) != 0)
231 if (ScannerFile(FileName
, false) != 0)
239 // FTWScanner::Delink - Delink symlinks /*{{{*/
240 // ---------------------------------------------------------------------
242 bool FTWScanner::Delink(string
&FileName
,const char *OriginalPath
,
243 unsigned long &DeLinkBytes
,
244 off_t
const &FileSize
)
246 // See if this isn't an internaly prefix'd file name.
247 if (InternalPrefix
.empty() == false &&
248 InternalPrefix
.length() < FileName
.length() &&
249 stringcmp(FileName
.begin(),FileName
.begin() + InternalPrefix
.length(),
250 InternalPrefix
.begin(),InternalPrefix
.end()) != 0)
252 if (DeLinkLimit
!= 0 && DeLinkBytes
/1024 < DeLinkLimit
)
254 // Tidy up the display
255 if (DeLinkBytes
== 0)
259 ioprintf(c1out
, _(" DeLink %s [%s]\n"), (OriginalPath
+ InternalPrefix
.length()),
260 SizeToStr(FileSize
).c_str());
263 if (NoLinkAct
== false)
266 if (readlink(OriginalPath
,OldLink
,sizeof(OldLink
)) == -1)
267 _error
->Errno("readlink",_("Failed to readlink %s"),OriginalPath
);
270 if (unlink(OriginalPath
) != 0)
271 _error
->Errno("unlink",_("Failed to unlink %s"),OriginalPath
);
274 if (link(FileName
.c_str(),OriginalPath
) != 0)
276 // Panic! Restore the symlink
277 symlink(OldLink
,OriginalPath
);
278 return _error
->Errno("link",_("*** Failed to link %s to %s"),
286 DeLinkBytes
+= FileSize
;
287 if (DeLinkBytes
/1024 >= DeLinkLimit
)
288 ioprintf(c1out
, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes
).c_str());
291 FileName
= OriginalPath
;
298 // PackagesWriter::PackagesWriter - Constructor /*{{{*/
299 // ---------------------------------------------------------------------
301 PackagesWriter::PackagesWriter(string
const &DB
,string
const &Overrides
,string
const &ExtOverrides
,
302 string
const &Arch
) :
303 FTWScanner(Arch
), Db(DB
), Stats(Db
.Stats
)
306 SetExts(".deb .udeb");
309 // Process the command line options
310 DoMD5
= _config
->FindB("APT::FTPArchive::MD5",true);
311 DoSHA1
= _config
->FindB("APT::FTPArchive::SHA1",true);
312 DoSHA256
= _config
->FindB("APT::FTPArchive::SHA256",true);
313 DoAlwaysStat
= _config
->FindB("APT::FTPArchive::AlwaysStat", false);
314 DoContents
= _config
->FindB("APT::FTPArchive::Contents",true);
315 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
316 LongDescription
= _config
->FindB("APT::FTPArchive::LongDescription",true);
318 if (Db
.Loaded() == false)
321 // Read the override file
322 if (Overrides
.empty() == false && Over
.ReadOverride(Overrides
) == false)
327 if (ExtOverrides
.empty() == false)
328 Over
.ReadExtraOverride(ExtOverrides
);
330 _error
->DumpErrors();
333 // FTWScanner::SetExts - Set extensions to support /*{{{*/
334 // ---------------------------------------------------------------------
336 bool FTWScanner::SetExts(string
const &Vals
)
339 string::size_type Start
= 0;
340 while (Start
<= Vals
.length()-1)
342 string::size_type
const Space
= Vals
.find(' ',Start
);
343 string::size_type
const Length
= ((Space
== string::npos
) ? Vals
.length() : Space
) - Start
;
344 if ( Arch
.empty() == false )
346 AddPattern(string("*_") + Arch
+ Vals
.substr(Start
, Length
));
347 AddPattern(string("*_all") + Vals
.substr(Start
, Length
));
350 AddPattern(string("*") + Vals
.substr(Start
, Length
));
359 // PackagesWriter::DoPackage - Process a single package /*{{{*/
360 // ---------------------------------------------------------------------
361 /* This method takes a package and gets its control information and
362 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
363 rewritten and the path/size/hash appended. */
364 bool PackagesWriter::DoPackage(string FileName
)
366 // Pull all the data we need form the DB
367 if (Db
.GetFileInfo(FileName
, true, DoContents
, true, DoMD5
, DoSHA1
, DoSHA256
, DoAlwaysStat
)
373 off_t FileSize
= Db
.GetFileSize();
374 if (Delink(FileName
,OriginalPath
,Stats
.DeLinkBytes
,FileSize
) == false)
377 // Lookup the overide information
378 pkgTagSection
&Tags
= Db
.Control
.Section
;
379 string Package
= Tags
.FindS("Package");
381 // if we generate a Packages file for a given arch, we use it to
382 // look for overrides. if we run in "simple" mode without the
383 // "Architecures" variable in the config we use the architecure value
388 Architecture
= Tags
.FindS("Architecture");
389 auto_ptr
<Override::Item
> OverItem(Over
.GetItem(Package
,Architecture
));
391 if (Package
.empty() == true)
392 return _error
->Error(_("Archive had no package field"));
394 // If we need to do any rewriting of the header do it now..
395 if (OverItem
.get() == 0)
397 if (NoOverride
== false)
400 ioprintf(c1out
, _(" %s has no override entry\n"), Package
.c_str());
403 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
404 OverItem
->FieldOverride
["Section"] = Tags
.FindS("Section");
405 OverItem
->Priority
= Tags
.FindS("Priority");
409 sprintf(Size
,"%lu", (unsigned long) FileSize
);
411 // Strip the DirStrip prefix from the FileName and add the PathPrefix
413 if (DirStrip
.empty() == false &&
414 FileName
.length() > DirStrip
.length() &&
415 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
416 DirStrip
.begin(),DirStrip
.end()) == 0)
417 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
419 NewFileName
= FileName
;
420 if (PathPrefix
.empty() == false)
421 NewFileName
= flCombine(PathPrefix
,NewFileName
);
423 /* Configuration says we don't want to include the long Description
424 in the package file - instead we want to ship a separated file */
426 if (LongDescription
== false) {
427 desc
= Tags
.FindS("Description").append("\n");
428 OverItem
->FieldOverride
["Description"] = desc
.substr(0, desc
.find('\n')).c_str();
431 // This lists all the changes to the fields we are going to make.
432 // (7 hardcoded + maintainer + suggests + end marker)
433 TFRewriteData Changes
[6+2+OverItem
->FieldOverride
.size()+1+1];
435 unsigned int End
= 0;
436 SetTFRewriteData(Changes
[End
++], "Size", Size
);
437 SetTFRewriteData(Changes
[End
++], "MD5sum", Db
.MD5Res
.c_str());
438 SetTFRewriteData(Changes
[End
++], "SHA1", Db
.SHA1Res
.c_str());
439 SetTFRewriteData(Changes
[End
++], "SHA256", Db
.SHA256Res
.c_str());
440 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
441 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
442 SetTFRewriteData(Changes
[End
++], "Status", 0);
443 SetTFRewriteData(Changes
[End
++], "Optional", 0);
445 string DescriptionMd5
;
446 if (LongDescription
== false) {
447 MD5Summation descmd5
;
448 descmd5
.Add(desc
.c_str());
449 DescriptionMd5
= descmd5
.Result().Value();
450 SetTFRewriteData(Changes
[End
++], "Description-md5", DescriptionMd5
.c_str());
453 // Rewrite the maintainer field if necessary
455 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
456 if (MaintFailed
== true)
458 if (NoOverride
== false)
461 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
462 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
466 if (NewMaint
.empty() == false)
467 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
469 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
470 dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
471 but dpkg does this append bit. So we do the append bit, at least that way the
472 status file and package file will remain similar. There are other transforms
473 but optional is the only legacy one still in use for some lazy reason. */
474 string OptionalStr
= Tags
.FindS("Optional");
475 if (OptionalStr
.empty() == false)
477 if (Tags
.FindS("Suggests").empty() == false)
478 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
479 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
482 for (map
<string
,string
>::const_iterator I
= OverItem
->FieldOverride
.begin();
483 I
!= OverItem
->FieldOverride
.end(); I
++)
484 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
486 SetTFRewriteData(Changes
[End
++], 0, 0);
488 // Rewrite and store the fields.
489 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
491 fprintf(Output
,"\n");
497 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
498 // ---------------------------------------------------------------------
500 SourcesWriter::SourcesWriter(string
const &BOverrides
,string
const &SOverrides
,
501 string
const &ExtOverrides
)
509 // Process the command line options
510 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
512 // Read the override file
513 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
518 // WTF?? The logic above: if we can't read binary overrides, don't even try
519 // reading source overrides. if we can read binary overrides, then say there
520 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
522 if (ExtOverrides
.empty() == false)
523 SOver
.ReadExtraOverride(ExtOverrides
);
525 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
526 SOver
.ReadOverride(SOverrides
,true);
529 // SourcesWriter::DoPackage - Process a single package /*{{{*/
530 // ---------------------------------------------------------------------
532 bool SourcesWriter::DoPackage(string FileName
)
535 FileFd
F(FileName
,FileFd::ReadOnly
);
536 if (_error
->PendingError() == true)
539 // Stat the file for later
541 if (fstat(F
.Fd(),&St
) != 0)
542 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
544 if (St
.st_size
> 128*1024)
545 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
547 if (BufSize
< (unsigned)St
.st_size
+1)
549 BufSize
= St
.st_size
+1;
550 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
553 if (F
.Read(Buffer
,St
.st_size
) == false)
557 char *Start
= Buffer
;
558 char *BlkEnd
= Buffer
+ St
.st_size
;
560 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
563 SHA256Summation SHA256
;
564 SHA1
.Add((unsigned char *)Start
,BlkEnd
- Start
);
565 SHA256
.Add((unsigned char *)Start
,BlkEnd
- Start
);
567 // Add an extra \n to the end, just in case
570 /* Remove the PGP trailer. Some .dsc's have this without a blank line
572 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
573 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
575 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
582 /* Read records until we locate the Source record. This neatly skips the
583 GPG header (which is RFC822 formed) without any trouble. */
588 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
589 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
590 if (Tags
.Find("Source",Pos
) == true)
592 Start
+= Tags
.size();
597 // Lookup the overide information, finding first the best priority.
599 string Bins
= Tags
.FindS("Binary");
600 char Buffer
[Bins
.length() + 1];
601 auto_ptr
<Override::Item
> OverItem(0);
602 if (Bins
.empty() == false)
604 strcpy(Buffer
,Bins
.c_str());
606 // Ignore too-long errors.
608 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
610 // Look at all the binaries
611 unsigned char BestPrioV
= pkgCache::State::Extra
;
612 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
614 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
618 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
619 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
621 BestPrioV
= NewPrioV
;
622 BestPrio
= Itm
->Priority
;
625 if (OverItem
.get() == 0)
630 // If we need to do any rewriting of the header do it now..
631 if (OverItem
.get() == 0)
633 if (NoOverride
== false)
636 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
639 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
642 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
643 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
644 if (SOverItem
.get() == 0)
646 ioprintf(c1out
, _(" %s has no source override entry\n"), Tags
.FindS("Source").c_str());
647 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
648 if (SOverItem
.get() == 0)
650 ioprintf(c1out
, _(" %s has no binary override entry either\n"), Tags
.FindS("Source").c_str());
651 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
652 *SOverItem
= *OverItem
;
656 // Add the dsc to the files hash list
657 string
const strippedName
= flNotDir(FileName
);
659 snprintf(Files
,sizeof(Files
),"\n %s %lu %s\n %s",
660 string(MD5
.Result()).c_str(),St
.st_size
,
661 strippedName
.c_str(),
662 Tags
.FindS("Files").c_str());
664 char ChecksumsSha1
[1000];
665 snprintf(ChecksumsSha1
,sizeof(ChecksumsSha1
),"\n %s %lu %s\n %s",
666 string(SHA1
.Result()).c_str(),St
.st_size
,
667 strippedName
.c_str(),
668 Tags
.FindS("Checksums-Sha1").c_str());
670 char ChecksumsSha256
[1000];
671 snprintf(ChecksumsSha256
,sizeof(ChecksumsSha256
),"\n %s %lu %s\n %s",
672 string(SHA256
.Result()).c_str(),St
.st_size
,
673 strippedName
.c_str(),
674 Tags
.FindS("Checksums-Sha256").c_str());
676 // Strip the DirStrip prefix from the FileName and add the PathPrefix
678 if (DirStrip
.empty() == false &&
679 FileName
.length() > DirStrip
.length() &&
680 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
681 NewFileName
= string(OriginalPath
+ DirStrip
.length());
683 NewFileName
= OriginalPath
;
684 if (PathPrefix
.empty() == false)
685 NewFileName
= flCombine(PathPrefix
,NewFileName
);
687 string Directory
= flNotFile(OriginalPath
);
688 string Package
= Tags
.FindS("Source");
690 // Perform the delinking operation over all of the files
692 const char *C
= Files
;
693 char *RealPath
= NULL
;
694 for (;isspace(*C
); C
++);
697 // Parse each of the elements
698 if (ParseQuoteWord(C
,ParseJnk
) == false ||
699 ParseQuoteWord(C
,ParseJnk
) == false ||
700 ParseQuoteWord(C
,ParseJnk
) == false)
701 return _error
->Error("Error parsing file record");
704 string OriginalPath
= Directory
+ ParseJnk
;
705 if (readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
706 (RealPath
= realpath(OriginalPath
.c_str(),NULL
)) != 0)
708 string RP
= RealPath
;
710 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
715 Directory
= flNotFile(NewFileName
);
716 if (Directory
.length() > 2)
717 Directory
.erase(Directory
.end()-1);
719 // This lists all the changes to the fields we are going to make.
720 // (5 hardcoded + checksums + maintainer + end marker)
721 TFRewriteData Changes
[5+2+1+SOverItem
->FieldOverride
.size()+1];
723 unsigned int End
= 0;
724 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
725 SetTFRewriteData(Changes
[End
++],"Files",Files
);
726 SetTFRewriteData(Changes
[End
++],"Checksums-Sha1",ChecksumsSha1
);
727 SetTFRewriteData(Changes
[End
++],"Checksums-Sha256",ChecksumsSha256
);
728 if (Directory
!= "./")
729 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
730 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
731 SetTFRewriteData(Changes
[End
++],"Status",0);
733 // Rewrite the maintainer field if necessary
735 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
736 if (MaintFailed
== true)
738 if (NoOverride
== false)
741 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
742 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
745 if (NewMaint
.empty() == false)
746 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
748 for (map
<string
,string
>::const_iterator I
= SOverItem
->FieldOverride
.begin();
749 I
!= SOverItem
->FieldOverride
.end(); I
++)
750 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
752 SetTFRewriteData(Changes
[End
++], 0, 0);
754 // Rewrite and store the fields.
755 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
757 fprintf(Output
,"\n");
765 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
766 // ---------------------------------------------------------------------
768 ContentsWriter::ContentsWriter(string
const &DB
, string
const &Arch
) :
769 FTWScanner(Arch
), Db(DB
), Stats(Db
.Stats
)
776 // ContentsWriter::DoPackage - Process a single package /*{{{*/
777 // ---------------------------------------------------------------------
778 /* If Package is the empty string the control record will be parsed to
779 determine what the package name is. */
780 bool ContentsWriter::DoPackage(string FileName
, string Package
)
782 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false, false))
787 // Parse the package name
788 if (Package
.empty() == true)
790 Package
= Db
.Control
.Section
.FindS("Package");
793 Db
.Contents
.Add(Gen
,Package
);
798 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
799 // ---------------------------------------------------------------------
801 bool ContentsWriter::ReadFromPkgs(string
const &PkgFile
,string
const &PkgCompress
)
803 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
804 if (_error
->PendingError() == true)
807 // Open the package file
810 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
814 FileFd
Fd(CompFd
,false);
815 pkgTagFile
Tags(&Fd
);
816 if (_error
->PendingError() == true)
818 Pkgs
.CloseOld(CompFd
,Proc
);
823 pkgTagSection Section
;
824 while (Tags
.Step(Section
) == true)
826 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
827 string Package
= Section
.FindS("Section");
828 if (Package
.empty() == false && Package
.end()[-1] != '/')
831 Package
+= Section
.FindS("Package");
834 Package
+= Section
.FindS("Package");
836 DoPackage(File
,Package
);
837 if (_error
->empty() == false)
839 _error
->Error("Errors apply to file '%s'",File
.c_str());
840 _error
->DumpErrors();
844 // Tidy the compressor
845 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
853 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
854 // ---------------------------------------------------------------------
856 ReleaseWriter::ReleaseWriter(string
const &DB
)
858 AddPattern("Packages");
859 AddPattern("Packages.gz");
860 AddPattern("Packages.bz2");
861 AddPattern("Packages.lzma");
862 AddPattern("Sources");
863 AddPattern("Sources.gz");
864 AddPattern("Sources.bz2");
865 AddPattern("Sources.lzma");
866 AddPattern("Release");
867 AddPattern("md5sum.txt");
870 time_t const now
= time(NULL
);
872 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
878 map
<string
,string
> Fields
;
879 Fields
["Origin"] = "";
880 Fields
["Label"] = "";
881 Fields
["Suite"] = "";
882 Fields
["Version"] = "";
883 Fields
["Codename"] = "";
884 Fields
["Date"] = datestr
;
885 Fields
["Architectures"] = "";
886 Fields
["Components"] = "";
887 Fields
["Description"] = "";
889 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
893 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
894 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
898 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
902 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
903 // ---------------------------------------------------------------------
904 bool ReleaseWriter::DoPackage(string FileName
)
906 // Strip the DirStrip prefix from the FileName and add the PathPrefix
908 if (DirStrip
.empty() == false &&
909 FileName
.length() > DirStrip
.length() &&
910 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
911 DirStrip
.begin(),DirStrip
.end()) == 0)
913 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
914 while (NewFileName
[0] == '/')
915 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
918 NewFileName
= FileName
;
920 if (PathPrefix
.empty() == false)
921 NewFileName
= flCombine(PathPrefix
,NewFileName
);
923 FileFd
fd(FileName
, FileFd::ReadOnly
);
930 CheckSums
[NewFileName
].size
= fd
.Size();
933 MD5
.AddFD(fd
.Fd(), fd
.Size());
934 CheckSums
[NewFileName
].MD5
= MD5
.Result();
938 SHA1
.AddFD(fd
.Fd(), fd
.Size());
939 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
942 SHA256Summation SHA256
;
943 SHA256
.AddFD(fd
.Fd(), fd
.Size());
944 CheckSums
[NewFileName
].SHA256
= SHA256
.Result();
952 // ReleaseWriter::Finish - Output the checksums /*{{{*/
953 // ---------------------------------------------------------------------
954 void ReleaseWriter::Finish()
956 fprintf(Output
, "MD5Sum:\n");
957 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
958 I
!= CheckSums
.end();
961 fprintf(Output
, " %s %16ld %s\n",
962 (*I
).second
.MD5
.c_str(),
967 fprintf(Output
, "SHA1:\n");
968 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
969 I
!= CheckSums
.end();
972 fprintf(Output
, " %s %16ld %s\n",
973 (*I
).second
.SHA1
.c_str(),
978 fprintf(Output
, "SHA256:\n");
979 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
980 I
!= CheckSums
.end();
983 fprintf(Output
, " %s %16ld %s\n",
984 (*I
).second
.SHA256
.c_str(),