]>
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()
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 &aArch
) :
303 Db(DB
),Stats(Db
.Stats
), Arch(aArch
)
306 SetExts(".deb .udeb .foo .bar .baz");
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 Space
= Vals
.find(' ',Start
);
344 string::size_type Length
;
345 if (Space
== string::npos
)
347 Length
= Vals
.length()-Start
;
351 Length
= Space
-Start
;
353 AddPattern(string("*") + Vals
.substr(Start
, Length
));
361 // PackagesWriter::DoPackage - Process a single package /*{{{*/
362 // ---------------------------------------------------------------------
363 /* This method takes a package and gets its control information and
364 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
365 rewritten and the path/size/hash appended. */
366 bool PackagesWriter::DoPackage(string FileName
)
368 // Pull all the data we need form the DB
369 if (Db
.GetFileInfo(FileName
, true, DoContents
, true, DoMD5
, DoSHA1
, DoSHA256
, DoAlwaysStat
)
375 off_t FileSize
= Db
.GetFileSize();
376 if (Delink(FileName
,OriginalPath
,Stats
.DeLinkBytes
,FileSize
) == false)
379 // Lookup the overide information
380 pkgTagSection
&Tags
= Db
.Control
.Section
;
381 string Package
= Tags
.FindS("Package");
383 // if we generate a Packages file for a given arch, we use it to
384 // look for overrides. if we run in "simple" mode without the
385 // "Architecures" variable in the config we use the architecure value
390 Architecture
= Tags
.FindS("Architecture");
391 auto_ptr
<Override::Item
> OverItem(Over
.GetItem(Package
,Architecture
));
393 if (Package
.empty() == true)
394 return _error
->Error(_("Archive had no package field"));
396 // If we need to do any rewriting of the header do it now..
397 if (OverItem
.get() == 0)
399 if (NoOverride
== false)
402 ioprintf(c1out
, _(" %s has no override entry\n"), Package
.c_str());
405 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
406 OverItem
->FieldOverride
["Section"] = Tags
.FindS("Section");
407 OverItem
->Priority
= Tags
.FindS("Priority");
411 sprintf(Size
,"%lu", (unsigned long) FileSize
);
413 // Strip the DirStrip prefix from the FileName and add the PathPrefix
415 if (DirStrip
.empty() == false &&
416 FileName
.length() > DirStrip
.length() &&
417 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
418 DirStrip
.begin(),DirStrip
.end()) == 0)
419 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
421 NewFileName
= FileName
;
422 if (PathPrefix
.empty() == false)
423 NewFileName
= flCombine(PathPrefix
,NewFileName
);
425 /* Configuration says we don't want to include the long Description
426 in the package file - instead we want to ship a separated file */
428 if (LongDescription
== false) {
429 desc
= Tags
.FindS("Description").append("\n");
430 OverItem
->FieldOverride
["Description"] = desc
.substr(0, desc
.find('\n')).c_str();
433 // This lists all the changes to the fields we are going to make.
434 // (7 hardcoded + maintainer + suggests + end marker)
435 TFRewriteData Changes
[6+2+OverItem
->FieldOverride
.size()+1+1];
437 unsigned int End
= 0;
438 SetTFRewriteData(Changes
[End
++], "Size", Size
);
439 SetTFRewriteData(Changes
[End
++], "MD5sum", Db
.MD5Res
.c_str());
440 SetTFRewriteData(Changes
[End
++], "SHA1", Db
.SHA1Res
.c_str());
441 SetTFRewriteData(Changes
[End
++], "SHA256", Db
.SHA256Res
.c_str());
442 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
443 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
444 SetTFRewriteData(Changes
[End
++], "Status", 0);
445 SetTFRewriteData(Changes
[End
++], "Optional", 0);
447 string DescriptionMd5
;
448 if (LongDescription
== false) {
449 MD5Summation descmd5
;
450 descmd5
.Add(desc
.c_str());
451 DescriptionMd5
= descmd5
.Result().Value();
452 SetTFRewriteData(Changes
[End
++], "Description-md5", DescriptionMd5
.c_str());
455 // Rewrite the maintainer field if necessary
457 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
458 if (MaintFailed
== true)
460 if (NoOverride
== false)
463 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
464 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
468 if (NewMaint
.empty() == false)
469 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
471 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
472 dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
473 but dpkg does this append bit. So we do the append bit, at least that way the
474 status file and package file will remain similar. There are other transforms
475 but optional is the only legacy one still in use for some lazy reason. */
476 string OptionalStr
= Tags
.FindS("Optional");
477 if (OptionalStr
.empty() == false)
479 if (Tags
.FindS("Suggests").empty() == false)
480 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
481 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
484 for (map
<string
,string
>::const_iterator I
= OverItem
->FieldOverride
.begin();
485 I
!= OverItem
->FieldOverride
.end(); I
++)
486 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
488 SetTFRewriteData(Changes
[End
++], 0, 0);
490 // Rewrite and store the fields.
491 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
493 fprintf(Output
,"\n");
499 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
500 // ---------------------------------------------------------------------
502 SourcesWriter::SourcesWriter(string
const &BOverrides
,string
const &SOverrides
,
503 string
const &ExtOverrides
)
511 // Process the command line options
512 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
514 // Read the override file
515 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
520 // WTF?? The logic above: if we can't read binary overrides, don't even try
521 // reading source overrides. if we can read binary overrides, then say there
522 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
524 if (ExtOverrides
.empty() == false)
525 SOver
.ReadExtraOverride(ExtOverrides
);
527 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
528 SOver
.ReadOverride(SOverrides
,true);
531 // SourcesWriter::DoPackage - Process a single package /*{{{*/
532 // ---------------------------------------------------------------------
534 bool SourcesWriter::DoPackage(string FileName
)
537 FileFd
F(FileName
,FileFd::ReadOnly
);
538 if (_error
->PendingError() == true)
541 // Stat the file for later
543 if (fstat(F
.Fd(),&St
) != 0)
544 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
546 if (St
.st_size
> 128*1024)
547 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
549 if (BufSize
< (unsigned)St
.st_size
+1)
551 BufSize
= St
.st_size
+1;
552 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
555 if (F
.Read(Buffer
,St
.st_size
) == false)
559 char *Start
= Buffer
;
560 char *BlkEnd
= Buffer
+ St
.st_size
;
562 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
565 SHA256Summation SHA256
;
566 SHA1
.Add((unsigned char *)Start
,BlkEnd
- Start
);
567 SHA256
.Add((unsigned char *)Start
,BlkEnd
- Start
);
569 // Add an extra \n to the end, just in case
572 /* Remove the PGP trailer. Some .dsc's have this without a blank line
574 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
575 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
577 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
584 /* Read records until we locate the Source record. This neatly skips the
585 GPG header (which is RFC822 formed) without any trouble. */
590 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
591 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
592 if (Tags
.Find("Source",Pos
) == true)
594 Start
+= Tags
.size();
599 // Lookup the overide information, finding first the best priority.
601 string Bins
= Tags
.FindS("Binary");
602 char Buffer
[Bins
.length() + 1];
603 auto_ptr
<Override::Item
> OverItem(0);
604 if (Bins
.empty() == false)
606 strcpy(Buffer
,Bins
.c_str());
608 // Ignore too-long errors.
610 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
612 // Look at all the binaries
613 unsigned char BestPrioV
= pkgCache::State::Extra
;
614 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
616 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
620 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
621 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
623 BestPrioV
= NewPrioV
;
624 BestPrio
= Itm
->Priority
;
627 if (OverItem
.get() == 0)
632 // If we need to do any rewriting of the header do it now..
633 if (OverItem
.get() == 0)
635 if (NoOverride
== false)
638 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
641 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
644 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
645 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
646 if (SOverItem
.get() == 0)
648 ioprintf(c1out
, _(" %s has no source override entry\n"), Tags
.FindS("Source").c_str());
649 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
650 if (SOverItem
.get() == 0)
652 ioprintf(c1out
, _(" %s has no binary override entry either\n"), Tags
.FindS("Source").c_str());
653 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
654 *SOverItem
= *OverItem
;
658 // Add the dsc to the files hash list
659 string
const strippedName
= flNotDir(FileName
);
661 snprintf(Files
,sizeof(Files
),"\n %s %lu %s\n %s",
662 string(MD5
.Result()).c_str(),St
.st_size
,
663 strippedName
.c_str(),
664 Tags
.FindS("Files").c_str());
666 char ChecksumsSha1
[1000];
667 snprintf(ChecksumsSha1
,sizeof(ChecksumsSha1
),"\n %s %lu %s\n %s",
668 string(SHA1
.Result()).c_str(),St
.st_size
,
669 strippedName
.c_str(),
670 Tags
.FindS("Checksums-Sha1").c_str());
672 char ChecksumsSha256
[1000];
673 snprintf(ChecksumsSha256
,sizeof(ChecksumsSha256
),"\n %s %lu %s\n %s",
674 string(SHA256
.Result()).c_str(),St
.st_size
,
675 strippedName
.c_str(),
676 Tags
.FindS("Checksums-Sha256").c_str());
678 // Strip the DirStrip prefix from the FileName and add the PathPrefix
680 if (DirStrip
.empty() == false &&
681 FileName
.length() > DirStrip
.length() &&
682 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
683 NewFileName
= string(OriginalPath
+ DirStrip
.length());
685 NewFileName
= OriginalPath
;
686 if (PathPrefix
.empty() == false)
687 NewFileName
= flCombine(PathPrefix
,NewFileName
);
689 string Directory
= flNotFile(OriginalPath
);
690 string Package
= Tags
.FindS("Source");
692 // Perform the delinking operation over all of the files
694 const char *C
= Files
;
695 char *RealPath
= NULL
;
696 for (;isspace(*C
); C
++);
699 // Parse each of the elements
700 if (ParseQuoteWord(C
,ParseJnk
) == false ||
701 ParseQuoteWord(C
,ParseJnk
) == false ||
702 ParseQuoteWord(C
,ParseJnk
) == false)
703 return _error
->Error("Error parsing file record");
706 string OriginalPath
= Directory
+ ParseJnk
;
707 if (readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
708 (RealPath
= realpath(OriginalPath
.c_str(),NULL
)) != 0)
710 string RP
= RealPath
;
712 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
717 Directory
= flNotFile(NewFileName
);
718 if (Directory
.length() > 2)
719 Directory
.erase(Directory
.end()-1);
721 // This lists all the changes to the fields we are going to make.
722 // (5 hardcoded + checksums + maintainer + end marker)
723 TFRewriteData Changes
[5+2+1+SOverItem
->FieldOverride
.size()+1];
725 unsigned int End
= 0;
726 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
727 SetTFRewriteData(Changes
[End
++],"Files",Files
);
728 SetTFRewriteData(Changes
[End
++],"Checksums-Sha1",ChecksumsSha1
);
729 SetTFRewriteData(Changes
[End
++],"Checksums-Sha256",ChecksumsSha256
);
730 if (Directory
!= "./")
731 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
732 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
733 SetTFRewriteData(Changes
[End
++],"Status",0);
735 // Rewrite the maintainer field if necessary
737 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
738 if (MaintFailed
== true)
740 if (NoOverride
== false)
743 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
744 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
747 if (NewMaint
.empty() == false)
748 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
750 for (map
<string
,string
>::const_iterator I
= SOverItem
->FieldOverride
.begin();
751 I
!= SOverItem
->FieldOverride
.end(); I
++)
752 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
754 SetTFRewriteData(Changes
[End
++], 0, 0);
756 // Rewrite and store the fields.
757 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
759 fprintf(Output
,"\n");
767 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
768 // ---------------------------------------------------------------------
770 ContentsWriter::ContentsWriter(string
const &DB
) :
771 Db(DB
), Stats(Db
.Stats
)
778 // ContentsWriter::DoPackage - Process a single package /*{{{*/
779 // ---------------------------------------------------------------------
780 /* If Package is the empty string the control record will be parsed to
781 determine what the package name is. */
782 bool ContentsWriter::DoPackage(string FileName
, string Package
)
784 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false, false))
789 // Parse the package name
790 if (Package
.empty() == true)
792 Package
= Db
.Control
.Section
.FindS("Package");
795 Db
.Contents
.Add(Gen
,Package
);
800 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
801 // ---------------------------------------------------------------------
803 bool ContentsWriter::ReadFromPkgs(string
const &PkgFile
,string
const &PkgCompress
)
805 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
806 if (_error
->PendingError() == true)
809 // Open the package file
812 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
816 FileFd
Fd(CompFd
,false);
817 pkgTagFile
Tags(&Fd
);
818 if (_error
->PendingError() == true)
820 Pkgs
.CloseOld(CompFd
,Proc
);
825 pkgTagSection Section
;
826 while (Tags
.Step(Section
) == true)
828 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
829 string Package
= Section
.FindS("Section");
830 if (Package
.empty() == false && Package
.end()[-1] != '/')
833 Package
+= Section
.FindS("Package");
836 Package
+= Section
.FindS("Package");
838 DoPackage(File
,Package
);
839 if (_error
->empty() == false)
841 _error
->Error("Errors apply to file '%s'",File
.c_str());
842 _error
->DumpErrors();
846 // Tidy the compressor
847 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
855 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
856 // ---------------------------------------------------------------------
858 ReleaseWriter::ReleaseWriter(string
const &DB
)
860 AddPattern("Packages");
861 AddPattern("Packages.gz");
862 AddPattern("Packages.bz2");
863 AddPattern("Packages.lzma");
864 AddPattern("Sources");
865 AddPattern("Sources.gz");
866 AddPattern("Sources.bz2");
867 AddPattern("Sources.lzma");
868 AddPattern("Release");
869 AddPattern("md5sum.txt");
872 time_t const now
= time(NULL
);
874 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
880 map
<string
,string
> Fields
;
881 Fields
["Origin"] = "";
882 Fields
["Label"] = "";
883 Fields
["Suite"] = "";
884 Fields
["Version"] = "";
885 Fields
["Codename"] = "";
886 Fields
["Date"] = datestr
;
887 Fields
["Architectures"] = "";
888 Fields
["Components"] = "";
889 Fields
["Description"] = "";
891 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
895 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
896 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
900 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
904 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
905 // ---------------------------------------------------------------------
906 bool ReleaseWriter::DoPackage(string FileName
)
908 // Strip the DirStrip prefix from the FileName and add the PathPrefix
910 if (DirStrip
.empty() == false &&
911 FileName
.length() > DirStrip
.length() &&
912 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
913 DirStrip
.begin(),DirStrip
.end()) == 0)
915 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
916 while (NewFileName
[0] == '/')
917 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
920 NewFileName
= FileName
;
922 if (PathPrefix
.empty() == false)
923 NewFileName
= flCombine(PathPrefix
,NewFileName
);
925 FileFd
fd(FileName
, FileFd::ReadOnly
);
932 CheckSums
[NewFileName
].size
= fd
.Size();
935 MD5
.AddFD(fd
.Fd(), fd
.Size());
936 CheckSums
[NewFileName
].MD5
= MD5
.Result();
940 SHA1
.AddFD(fd
.Fd(), fd
.Size());
941 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
944 SHA256Summation SHA256
;
945 SHA256
.AddFD(fd
.Fd(), fd
.Size());
946 CheckSums
[NewFileName
].SHA256
= SHA256
.Result();
954 // ReleaseWriter::Finish - Output the checksums /*{{{*/
955 // ---------------------------------------------------------------------
956 void ReleaseWriter::Finish()
958 fprintf(Output
, "MD5Sum:\n");
959 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
960 I
!= CheckSums
.end();
963 fprintf(Output
, " %s %16ld %s\n",
964 (*I
).second
.MD5
.c_str(),
969 fprintf(Output
, "SHA1:\n");
970 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
971 I
!= CheckSums
.end();
974 fprintf(Output
, " %s %16ld %s\n",
975 (*I
).second
.SHA1
.c_str(),
980 fprintf(Output
, "SHA256:\n");
981 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
982 I
!= CheckSums
.end();
985 fprintf(Output
, " %s %16ld %s\n",
986 (*I
).second
.SHA256
.c_str(),