]>
git.saurik.com Git - apt-legacy.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 ReadLink
)
90 const char *LastComponent
= strrchr(File
, '/');
91 char *RealPath
= NULL
;
93 if (LastComponent
== NULL
)
98 vector
<string
>::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 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 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 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 Dir
,string 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
,
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 DB
,string Overrides
,string ExtOverrides
,
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 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 Vals
)
339 string::size_type Start
= 0;
340 while (Start
<= Vals
.length()-1)
342 string::size_type Space
= Vals
.find(' ',Start
);
343 string::size_type Length
;
344 if (Space
== string::npos
)
346 Length
= Vals
.length()-Start
;
350 Length
= Space
-Start
;
352 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
)
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());
454 // Rewrite the maintainer field if necessary
456 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
457 if (MaintFailed
== true)
459 if (NoOverride
== false)
462 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
463 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
467 if (NewMaint
.empty() == false)
468 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
470 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
471 dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
472 but dpkg does this append bit. So we do the append bit, at least that way the
473 status file and package file will remain similar. There are other transforms
474 but optional is the only legacy one still in use for some lazy reason. */
475 string OptionalStr
= Tags
.FindS("Optional");
476 if (OptionalStr
.empty() == false)
478 if (Tags
.FindS("Suggests").empty() == false)
479 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
480 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
483 for (map
<string
,string
>::iterator I
= OverItem
->FieldOverride
.begin();
484 I
!= OverItem
->FieldOverride
.end(); I
++)
485 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
487 SetTFRewriteData(Changes
[End
++], 0, 0);
489 // Rewrite and store the fields.
490 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
492 fprintf(Output
,"\n");
498 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
499 // ---------------------------------------------------------------------
501 SourcesWriter::SourcesWriter(string BOverrides
,string SOverrides
,
510 // Process the command line options
511 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
513 // Read the override file
514 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
519 // WTF?? The logic above: if we can't read binary overrides, don't even try
520 // reading source overrides. if we can read binary overrides, then say there
521 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
523 if (ExtOverrides
.empty() == false)
524 SOver
.ReadExtraOverride(ExtOverrides
);
526 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
527 SOver
.ReadOverride(SOverrides
,true);
530 // SourcesWriter::DoPackage - Process a single package /*{{{*/
531 // ---------------------------------------------------------------------
533 bool SourcesWriter::DoPackage(string FileName
)
536 FileFd
F(FileName
,FileFd::ReadOnly
);
537 if (_error
->PendingError() == true)
540 // Stat the file for later
542 if (fstat(F
.Fd(),&St
) != 0)
543 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
545 if (St
.st_size
> 128*1024)
546 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
548 if (BufSize
< (unsigned)St
.st_size
+1)
550 BufSize
= St
.st_size
+1;
551 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
554 if (F
.Read(Buffer
,St
.st_size
) == false)
558 char *Start
= Buffer
;
559 char *BlkEnd
= Buffer
+ St
.st_size
;
561 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
564 SHA256Summation SHA256
;
565 SHA1
.Add((unsigned char *)Start
,BlkEnd
- Start
);
566 SHA256
.Add((unsigned char *)Start
,BlkEnd
- Start
);
568 // Add an extra \n to the end, just in case
571 /* Remove the PGP trailer. Some .dsc's have this without a blank line
573 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
574 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
576 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
583 /* Read records until we locate the Source record. This neatly skips the
584 GPG header (which is RFC822 formed) without any trouble. */
589 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
590 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
591 if (Tags
.Find("Source",Pos
) == true)
593 Start
+= Tags
.size();
598 // Lookup the overide information, finding first the best priority.
600 string Bins
= Tags
.FindS("Binary");
601 char Buffer
[Bins
.length() + 1];
602 auto_ptr
<Override::Item
> OverItem(0);
603 if (Bins
.empty() == false)
605 strcpy(Buffer
,Bins
.c_str());
607 // Ignore too-long errors.
609 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
611 // Look at all the binaries
612 unsigned char BestPrioV
= pkgCache::State::Extra
;
613 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
615 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
619 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
620 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
622 BestPrioV
= NewPrioV
;
623 BestPrio
= Itm
->Priority
;
626 if (OverItem
.get() == 0)
631 // If we need to do any rewriting of the header do it now..
632 if (OverItem
.get() == 0)
634 if (NoOverride
== false)
637 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
640 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
643 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
644 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
645 if (SOverItem
.get() == 0)
647 ioprintf(c1out
, _(" %s has no source override entry\n"), Tags
.FindS("Source").c_str());
648 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
649 if (SOverItem
.get() == 0)
651 ioprintf(c1out
, _(" %s has no binary override entry either\n"), Tags
.FindS("Source").c_str());
652 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
653 *SOverItem
= *OverItem
;
657 // Add the dsc to the files hash list
658 string
const strippedName
= flNotDir(FileName
);
660 snprintf(Files
,sizeof(Files
),"\n %s %llu %s\n %s",
661 string(MD5
.Result()).c_str(),St
.st_size
,
662 strippedName
.c_str(),
663 Tags
.FindS("Files").c_str());
665 char ChecksumsSha1
[1000];
666 snprintf(ChecksumsSha1
,sizeof(ChecksumsSha1
),"\n %s %lu %s\n %s",
667 string(SHA1
.Result()).c_str(),St
.st_size
,
668 strippedName
.c_str(),
669 Tags
.FindS("Checksums-Sha1").c_str());
671 char ChecksumsSha256
[1000];
672 snprintf(ChecksumsSha256
,sizeof(ChecksumsSha256
),"\n %s %lu %s\n %s",
673 string(SHA256
.Result()).c_str(),St
.st_size
,
674 strippedName
.c_str(),
675 Tags
.FindS("Checksums-Sha256").c_str());
677 // Strip the DirStrip prefix from the FileName and add the PathPrefix
679 if (DirStrip
.empty() == false &&
680 FileName
.length() > DirStrip
.length() &&
681 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
682 NewFileName
= string(OriginalPath
+ DirStrip
.length());
684 NewFileName
= OriginalPath
;
685 if (PathPrefix
.empty() == false)
686 NewFileName
= flCombine(PathPrefix
,NewFileName
);
688 string Directory
= flNotFile(OriginalPath
);
689 string Package
= Tags
.FindS("Source");
691 // Perform the delinking operation over all of the files
693 const char *C
= Files
;
694 char *RealPath
= NULL
;
695 for (;isspace(*C
); C
++);
698 // Parse each of the elements
699 if (ParseQuoteWord(C
,ParseJnk
) == false ||
700 ParseQuoteWord(C
,ParseJnk
) == false ||
701 ParseQuoteWord(C
,ParseJnk
) == false)
702 return _error
->Error("Error parsing file record");
705 string OriginalPath
= Directory
+ ParseJnk
;
706 if (readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
707 (RealPath
= realpath(OriginalPath
.c_str(),NULL
)) != 0)
709 string RP
= RealPath
;
711 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
716 Directory
= flNotFile(NewFileName
);
717 if (Directory
.length() > 2)
718 Directory
.erase(Directory
.end()-1);
720 // This lists all the changes to the fields we are going to make.
721 // (5 hardcoded + checksums + maintainer + end marker)
722 TFRewriteData Changes
[5+2+1+SOverItem
->FieldOverride
.size()+1];
724 unsigned int End
= 0;
725 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
726 SetTFRewriteData(Changes
[End
++],"Files",Files
);
727 SetTFRewriteData(Changes
[End
++],"Checksums-Sha1",ChecksumsSha1
);
728 SetTFRewriteData(Changes
[End
++],"Checksums-Sha256",ChecksumsSha256
);
729 if (Directory
!= "./")
730 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
731 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
732 SetTFRewriteData(Changes
[End
++],"Status",0);
734 // Rewrite the maintainer field if necessary
736 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
737 if (MaintFailed
== true)
739 if (NoOverride
== false)
742 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
743 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
746 if (NewMaint
.empty() == false)
747 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
749 for (map
<string
,string
>::iterator I
= SOverItem
->FieldOverride
.begin();
750 I
!= SOverItem
->FieldOverride
.end(); I
++)
751 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
753 SetTFRewriteData(Changes
[End
++], 0, 0);
755 // Rewrite and store the fields.
756 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
758 fprintf(Output
,"\n");
766 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
767 // ---------------------------------------------------------------------
769 ContentsWriter::ContentsWriter(string DB
) :
770 Db(DB
), Stats(Db
.Stats
)
777 // ContentsWriter::DoPackage - Process a single package /*{{{*/
778 // ---------------------------------------------------------------------
779 /* If Package is the empty string the control record will be parsed to
780 determine what the package name is. */
781 bool ContentsWriter::DoPackage(string FileName
,string Package
)
783 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false))
788 // Parse the package name
789 if (Package
.empty() == true)
791 Package
= Db
.Control
.Section
.FindS("Package");
794 Db
.Contents
.Add(Gen
,Package
);
799 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
800 // ---------------------------------------------------------------------
802 bool ContentsWriter::ReadFromPkgs(string PkgFile
,string PkgCompress
)
804 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
805 if (_error
->PendingError() == true)
808 // Open the package file
811 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
815 FileFd
Fd(CompFd
,false);
816 pkgTagFile
Tags(&Fd
);
817 if (_error
->PendingError() == true)
819 Pkgs
.CloseOld(CompFd
,Proc
);
824 pkgTagSection Section
;
825 while (Tags
.Step(Section
) == true)
827 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
828 string Package
= Section
.FindS("Section");
829 if (Package
.empty() == false && Package
.end()[-1] != '/')
832 Package
+= Section
.FindS("Package");
835 Package
+= Section
.FindS("Package");
837 DoPackage(File
,Package
);
838 if (_error
->empty() == false)
840 _error
->Error("Errors apply to file '%s'",File
.c_str());
841 _error
->DumpErrors();
845 // Tidy the compressor
846 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
854 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
855 // ---------------------------------------------------------------------
857 ReleaseWriter::ReleaseWriter(string DB
)
859 AddPattern("Packages");
860 AddPattern("Packages.gz");
861 AddPattern("Packages.bz2");
862 AddPattern("Packages.lzma");
863 AddPattern("Sources");
864 AddPattern("Sources.gz");
865 AddPattern("Sources.bz2");
866 AddPattern("Sources.lzma");
867 AddPattern("Release");
868 AddPattern("md5sum.txt");
871 time_t now
= time(NULL
);
873 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
879 map
<string
,string
> Fields
;
880 Fields
["Origin"] = "";
881 Fields
["Label"] = "";
882 Fields
["Suite"] = "";
883 Fields
["Version"] = "";
884 Fields
["Codename"] = "";
885 Fields
["Date"] = datestr
;
886 Fields
["Architectures"] = "";
887 Fields
["Components"] = "";
888 Fields
["Description"] = "";
890 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
894 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
895 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
899 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
903 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
904 // ---------------------------------------------------------------------
905 bool ReleaseWriter::DoPackage(string FileName
)
907 // Strip the DirStrip prefix from the FileName and add the PathPrefix
909 if (DirStrip
.empty() == false &&
910 FileName
.length() > DirStrip
.length() &&
911 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
912 DirStrip
.begin(),DirStrip
.end()) == 0)
914 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
915 while (NewFileName
[0] == '/')
916 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
919 NewFileName
= FileName
;
921 if (PathPrefix
.empty() == false)
922 NewFileName
= flCombine(PathPrefix
,NewFileName
);
924 FileFd
fd(FileName
, FileFd::ReadOnly
);
931 CheckSums
[NewFileName
].size
= fd
.Size();
934 MD5
.AddFD(fd
.Fd(), fd
.Size());
935 CheckSums
[NewFileName
].MD5
= MD5
.Result();
939 SHA1
.AddFD(fd
.Fd(), fd
.Size());
940 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
943 SHA256Summation SHA256
;
944 SHA256
.AddFD(fd
.Fd(), fd
.Size());
945 CheckSums
[NewFileName
].SHA256
= SHA256
.Result();
953 // ReleaseWriter::Finish - Output the checksums /*{{{*/
954 // ---------------------------------------------------------------------
955 void ReleaseWriter::Finish()
957 fprintf(Output
, "MD5Sum:\n");
958 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
959 I
!= CheckSums
.end();
962 fprintf(Output
, " %s %16ld %s\n",
963 (*I
).second
.MD5
.c_str(),
968 fprintf(Output
, "SHA1:\n");
969 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
970 I
!= CheckSums
.end();
973 fprintf(Output
, " %s %16ld %s\n",
974 (*I
).second
.SHA1
.c_str(),
979 fprintf(Output
, "SHA256:\n");
980 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
981 I
!= CheckSums
.end();
984 fprintf(Output
, " %s %16ld %s\n",
985 (*I
).second
.SHA256
.c_str(),