]>
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 /*{{{*/
15 #pragma implementation "writer.h"
21 #include <apt-pkg/strutl.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/configuration.h>
24 #include <apt-pkg/md5.h>
25 #include <apt-pkg/sha1.h>
26 #include <apt-pkg/sha256.h>
27 #include <apt-pkg/deblistparser.h>
29 #include <sys/types.h>
37 #include "apt-ftparchive.h"
38 #include "multicompress.h"
41 FTWScanner
*FTWScanner::Owner
;
43 // SetTFRewriteData - Helper for setting rewrite lists /*{{{*/
44 // ---------------------------------------------------------------------
46 inline void SetTFRewriteData(struct TFRewriteData
&tfrd
,
49 const char *newtag
= 0)
52 tfrd
.Rewrite
= rewrite
;
57 // FTWScanner::FTWScanner - Constructor /*{{{*/
58 // ---------------------------------------------------------------------
60 FTWScanner::FTWScanner()
63 NoLinkAct
= !_config
->FindB("APT::FTPArchive::DeLinkAct",true);
65 long PMax
= pathconf(".",_PC_PATH_MAX
);
67 RealPath
= new char[PMax
];
70 // FTWScanner::Scanner - FTW Scanner /*{{{*/
71 // ---------------------------------------------------------------------
72 /* This is the FTW scanner, it processes each directory element in the
74 int FTWScanner::ScannerFTW(const char *File
,const struct stat
*sb
,int Flag
)
79 ioprintf(c1out
, _("W: Unable to read directory %s\n"), File
);
84 ioprintf(c1out
, _("W: Unable to stat %s\n"), File
);
89 return ScannerFile(File
, true);
92 // FTWScanner::ScannerFile - File Scanner /*{{{*/
93 // ---------------------------------------------------------------------
95 int FTWScanner::ScannerFile(const char *File
, bool ReadLink
)
97 const char *LastComponent
= strrchr(File
, '/');
98 if (LastComponent
== NULL
)
103 vector
<string
>::iterator I
;
104 for(I
= Owner
->Patterns
.begin(); I
!= Owner
->Patterns
.end(); ++I
)
106 if (fnmatch((*I
).c_str(), LastComponent
, 0) == 0)
109 if (I
== Owner
->Patterns
.end())
112 /* Process it. If the file is a link then resolve it into an absolute
113 name.. This works best if the directory components the scanner are
114 given are not links themselves. */
116 Owner
->OriginalPath
= File
;
117 if (ReadLink
&& Owner
->RealPath
!= 0 &&
118 readlink(File
,Jnk
,sizeof(Jnk
)) != -1 &&
119 realpath(File
,Owner
->RealPath
) != 0)
120 Owner
->DoPackage(Owner
->RealPath
);
122 Owner
->DoPackage(File
);
124 if (_error
->empty() == false)
126 // Print any errors or warnings found
128 bool SeenPath
= false;
129 while (_error
->empty() == false)
133 bool Type
= _error
->PopMessage(Err
);
135 cerr
<< _("E: ") << Err
<< endl
;
137 cerr
<< _("W: ") << Err
<< endl
;
139 if (Err
.find(File
) != string::npos
)
143 if (SeenPath
== false)
144 cerr
<< _("E: Errors apply to file ") << "'" << File
<< "'" << endl
;
151 // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
152 // ---------------------------------------------------------------------
154 bool FTWScanner::RecursiveScan(string Dir
)
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(Dir
.c_str(),RealPath
) == 0)
161 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
162 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 /* If noprefix is set then jam the scan root in, so we don't generate
187 link followed paths out of control */
188 if (InternalPrefix
.empty() == true)
190 if (realpath(Dir
.c_str(),RealPath
) == 0)
191 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
192 InternalPrefix
= RealPath
;
196 FILE *List
= fopen(File
.c_str(),"r");
198 return _error
->Errno("fopen",_("Failed to open %s"),File
.c_str());
200 /* We are a tad tricky here.. We prefix the buffer with the directory
201 name, that way if we need a full path with just use line.. Sneaky and
205 if (Dir
.empty() == true || Dir
.end()[-1] != '/')
206 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s/",Dir
.c_str());
208 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s",Dir
.c_str());
209 while (fgets(FileStart
,sizeof(Line
) - (FileStart
- Line
),List
) != 0)
211 char *FileName
= _strstrip(FileStart
);
212 if (FileName
[0] == 0)
215 if (FileName
[0] != '/')
217 if (FileName
!= FileStart
)
218 memmove(FileStart
,FileName
,strlen(FileStart
));
225 if (stat(FileName
,&St
) != 0)
229 if (ScannerFile(FileName
, false) != 0)
237 // FTWScanner::Delink - Delink symlinks /*{{{*/
238 // ---------------------------------------------------------------------
240 bool FTWScanner::Delink(string
&FileName
,const char *OriginalPath
,
241 unsigned long &DeLinkBytes
,
244 // See if this isn't an internaly prefix'd file name.
245 if (InternalPrefix
.empty() == false &&
246 InternalPrefix
.length() < FileName
.length() &&
247 stringcmp(FileName
.begin(),FileName
.begin() + InternalPrefix
.length(),
248 InternalPrefix
.begin(),InternalPrefix
.end()) != 0)
250 if (DeLinkLimit
!= 0 && DeLinkBytes
/1024 < DeLinkLimit
)
252 // Tidy up the display
253 if (DeLinkBytes
== 0)
257 ioprintf(c1out
, _(" DeLink %s [%s]\n"), (OriginalPath
+ InternalPrefix
.length()),
258 SizeToStr(FileSize
).c_str());
261 if (NoLinkAct
== false)
264 if (readlink(OriginalPath
,OldLink
,sizeof(OldLink
)) == -1)
265 _error
->Errno("readlink",_("Failed to readlink %s"),OriginalPath
);
268 if (unlink(OriginalPath
) != 0)
269 _error
->Errno("unlink",_("Failed to unlink %s"),OriginalPath
);
272 if (link(FileName
.c_str(),OriginalPath
) != 0)
274 // Panic! Restore the symlink
275 symlink(OldLink
,OriginalPath
);
276 return _error
->Errno("link",_("*** Failed to link %s to %s"),
284 DeLinkBytes
+= FileSize
;
285 if (DeLinkBytes
/1024 >= DeLinkLimit
)
286 ioprintf(c1out
, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes
).c_str());
289 FileName
= OriginalPath
;
296 // PackagesWriter::PackagesWriter - Constructor /*{{{*/
297 // ---------------------------------------------------------------------
299 PackagesWriter::PackagesWriter(string DB
,string Overrides
,string ExtOverrides
,
301 Db(DB
),Stats(Db
.Stats
), Arch(aArch
)
304 SetExts(".deb .udeb .foo .bar .baz");
308 // Process the command line options
309 DoMD5
= _config
->FindB("APT::FTPArchive::MD5",true);
310 DoSHA1
= _config
->FindB("APT::FTPArchive::SHA1",true);
311 DoSHA256
= _config
->FindB("APT::FTPArchive::SHA256",true);
312 DoContents
= _config
->FindB("APT::FTPArchive::Contents",true);
313 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
315 if (Db
.Loaded() == false)
318 // Read the override file
319 if (Overrides
.empty() == false && Over
.ReadOverride(Overrides
) == false)
324 if (ExtOverrides
.empty() == false)
325 Over
.ReadExtraOverride(ExtOverrides
);
327 _error
->DumpErrors();
330 // FTWScanner::SetExts - Set extensions to support /*{{{*/
331 // ---------------------------------------------------------------------
333 bool FTWScanner::SetExts(string Vals
)
336 string::size_type Start
= 0;
337 while (Start
<= Vals
.length()-1)
339 string::size_type Space
= Vals
.find(' ',Start
);
340 string::size_type Length
;
341 if (Space
== string::npos
)
343 Length
= Vals
.length()-Start
;
347 Length
= Space
-Start
;
349 AddPattern(string("*") + Vals
.substr(Start
, Length
));
357 // PackagesWriter::DoPackage - Process a single package /*{{{*/
358 // ---------------------------------------------------------------------
359 /* This method takes a package and gets its control information and
360 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
361 rewritten and the path/size/hash appended. */
362 bool PackagesWriter::DoPackage(string FileName
)
364 // Pull all the data we need form the DB
365 if (Db
.GetFileInfo(FileName
, true, DoContents
, true, DoMD5
, DoSHA1
, DoSHA256
)
371 off_t FileSize
= Db
.GetFileSize();
372 if (Delink(FileName
,OriginalPath
,Stats
.DeLinkBytes
,FileSize
) == false)
375 // Lookup the overide information
376 pkgTagSection
&Tags
= Db
.Control
.Section
;
377 string Package
= Tags
.FindS("Package");
379 // if we generate a Packages file for a given arch, we use it to
380 // look for overrides. if we run in "simple" mode without the
381 // "Architecures" variable in the config we use the architecure value
386 Architecture
= Tags
.FindS("Architecture");
387 auto_ptr
<Override::Item
> OverItem(Over
.GetItem(Package
,Architecture
));
389 if (Package
.empty() == true)
390 return _error
->Error(_("Archive had no package field"));
392 // If we need to do any rewriting of the header do it now..
393 if (OverItem
.get() == 0)
395 if (NoOverride
== false)
398 ioprintf(c1out
, _(" %s has no override entry\n"), Package
.c_str());
401 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
402 OverItem
->FieldOverride
["Section"] = Tags
.FindS("Section");
403 OverItem
->Priority
= Tags
.FindS("Priority");
407 sprintf(Size
,"%lu", (unsigned long) FileSize
);
409 // Strip the DirStrip prefix from the FileName and add the PathPrefix
411 if (DirStrip
.empty() == false &&
412 FileName
.length() > DirStrip
.length() &&
413 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
414 DirStrip
.begin(),DirStrip
.end()) == 0)
415 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
417 NewFileName
= FileName
;
418 if (PathPrefix
.empty() == false)
419 NewFileName
= flCombine(PathPrefix
,NewFileName
);
421 // This lists all the changes to the fields we are going to make.
422 // (7 hardcoded + maintainer + suggests + end marker)
423 TFRewriteData Changes
[6+2+OverItem
->FieldOverride
.size()+1];
425 unsigned int End
= 0;
426 SetTFRewriteData(Changes
[End
++], "Size", Size
);
427 SetTFRewriteData(Changes
[End
++], "MD5sum", Db
.MD5Res
.c_str());
428 SetTFRewriteData(Changes
[End
++], "SHA1", Db
.SHA1Res
.c_str());
429 SetTFRewriteData(Changes
[End
++], "SHA256", Db
.SHA256Res
.c_str());
430 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
431 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
432 SetTFRewriteData(Changes
[End
++], "Status", 0);
433 SetTFRewriteData(Changes
[End
++], "Optional", 0);
435 // Rewrite the maintainer field if necessary
437 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
438 if (MaintFailed
== true)
440 if (NoOverride
== false)
443 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
444 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
448 if (NewMaint
.empty() == false)
449 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
451 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
452 dpkg-scanpackages does.. Well sort of. dpkg-scanpackages just does renaming
453 but dpkg does this append bit. So we do the append bit, at least that way the
454 status file and package file will remain similar. There are other transforms
455 but optional is the only legacy one still in use for some lazy reason. */
456 string OptionalStr
= Tags
.FindS("Optional");
457 if (OptionalStr
.empty() == false)
459 if (Tags
.FindS("Suggests").empty() == false)
460 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
461 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
464 for (map
<string
,string
>::iterator I
= OverItem
->FieldOverride
.begin();
465 I
!= OverItem
->FieldOverride
.end(); I
++)
466 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
468 SetTFRewriteData(Changes
[End
++], 0, 0);
470 // Rewrite and store the fields.
471 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
473 fprintf(Output
,"\n");
479 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
480 // ---------------------------------------------------------------------
482 SourcesWriter::SourcesWriter(string BOverrides
,string SOverrides
,
491 // Process the command line options
492 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
494 // Read the override file
495 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
500 // WTF?? The logic above: if we can't read binary overrides, don't even try
501 // reading source overrides. if we can read binary overrides, then say there
502 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
504 if (ExtOverrides
.empty() == false)
505 SOver
.ReadExtraOverride(ExtOverrides
);
507 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
508 SOver
.ReadOverride(SOverrides
,true);
511 // SourcesWriter::DoPackage - Process a single package /*{{{*/
512 // ---------------------------------------------------------------------
514 bool SourcesWriter::DoPackage(string FileName
)
517 FileFd
F(FileName
,FileFd::ReadOnly
);
518 if (_error
->PendingError() == true)
521 // Stat the file for later
523 if (fstat(F
.Fd(),&St
) != 0)
524 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
526 if (St
.st_size
> 128*1024)
527 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
529 if (BufSize
< (unsigned)St
.st_size
+1)
531 BufSize
= St
.st_size
+1;
532 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
535 if (F
.Read(Buffer
,St
.st_size
) == false)
539 char *Start
= Buffer
;
540 char *BlkEnd
= Buffer
+ St
.st_size
;
542 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
544 // Add an extra \n to the end, just in case
547 /* Remove the PGP trailer. Some .dsc's have this without a blank line
549 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
550 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
552 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
559 /* Read records until we locate the Source record. This neatly skips the
560 GPG header (which is RFC822 formed) without any trouble. */
565 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
566 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
567 if (Tags
.Find("Source",Pos
) == true)
569 Start
+= Tags
.size();
574 // Lookup the overide information, finding first the best priority.
576 string Bins
= Tags
.FindS("Binary");
577 char Buffer
[Bins
.length() + 1];
578 auto_ptr
<Override::Item
> OverItem(0);
579 if (Bins
.empty() == false)
581 strcpy(Buffer
,Bins
.c_str());
583 // Ignore too-long errors.
585 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
587 // Look at all the binaries
588 unsigned char BestPrioV
= pkgCache::State::Extra
;
589 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
591 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
595 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
596 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
598 BestPrioV
= NewPrioV
;
599 BestPrio
= Itm
->Priority
;
602 if (OverItem
.get() == 0)
607 // If we need to do any rewriting of the header do it now..
608 if (OverItem
.get() == 0)
610 if (NoOverride
== false)
613 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
616 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
619 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
620 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
621 if (SOverItem
.get() == 0)
623 ioprintf(c1out
, _(" %s has no source override entry\n"), Tags
.FindS("Source").c_str());
624 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
625 if (SOverItem
.get() == 0)
627 ioprintf(c1out
, _(" %s has no binary override entry either\n"), Tags
.FindS("Source").c_str());
628 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
629 *SOverItem
= *OverItem
;
633 // Add the dsc to the files hash list
635 snprintf(Files
,sizeof(Files
),"\n %s %lu %s\n %s",
636 string(MD5
.Result()).c_str(),St
.st_size
,
637 flNotDir(FileName
).c_str(),
638 Tags
.FindS("Files").c_str());
640 // Strip the DirStrip prefix from the FileName and add the PathPrefix
642 if (DirStrip
.empty() == false &&
643 FileName
.length() > DirStrip
.length() &&
644 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
645 NewFileName
= string(OriginalPath
+ DirStrip
.length());
647 NewFileName
= OriginalPath
;
648 if (PathPrefix
.empty() == false)
649 NewFileName
= flCombine(PathPrefix
,NewFileName
);
651 string Directory
= flNotFile(OriginalPath
);
652 string Package
= Tags
.FindS("Source");
654 // Perform the delinking operation over all of the files
656 const char *C
= Files
;
657 for (;isspace(*C
); C
++);
660 // Parse each of the elements
661 if (ParseQuoteWord(C
,ParseJnk
) == false ||
662 ParseQuoteWord(C
,ParseJnk
) == false ||
663 ParseQuoteWord(C
,ParseJnk
) == false)
664 return _error
->Error("Error parsing file record");
667 string OriginalPath
= Directory
+ ParseJnk
;
668 if (RealPath
!= 0 && readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
669 realpath(OriginalPath
.c_str(),RealPath
) != 0)
671 string RP
= RealPath
;
672 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
677 Directory
= flNotFile(NewFileName
);
678 if (Directory
.length() > 2)
679 Directory
.erase(Directory
.end()-1);
681 // This lists all the changes to the fields we are going to make.
682 // (5 hardcoded + maintainer + end marker)
683 TFRewriteData Changes
[5+1+SOverItem
->FieldOverride
.size()+1];
685 unsigned int End
= 0;
686 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
687 SetTFRewriteData(Changes
[End
++],"Files",Files
);
688 if (Directory
!= "./")
689 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
690 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
691 SetTFRewriteData(Changes
[End
++],"Status",0);
693 // Rewrite the maintainer field if necessary
695 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
696 if (MaintFailed
== true)
698 if (NoOverride
== false)
701 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
702 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
705 if (NewMaint
.empty() == false)
706 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
708 for (map
<string
,string
>::iterator I
= SOverItem
->FieldOverride
.begin();
709 I
!= SOverItem
->FieldOverride
.end(); I
++)
710 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
712 SetTFRewriteData(Changes
[End
++], 0, 0);
714 // Rewrite and store the fields.
715 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
717 fprintf(Output
,"\n");
725 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
726 // ---------------------------------------------------------------------
728 ContentsWriter::ContentsWriter(string DB
) :
729 Db(DB
), Stats(Db
.Stats
)
736 // ContentsWriter::DoPackage - Process a single package /*{{{*/
737 // ---------------------------------------------------------------------
738 /* If Package is the empty string the control record will be parsed to
739 determine what the package name is. */
740 bool ContentsWriter::DoPackage(string FileName
,string Package
)
742 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false))
747 // Parse the package name
748 if (Package
.empty() == true)
750 Package
= Db
.Control
.Section
.FindS("Package");
753 Db
.Contents
.Add(Gen
,Package
);
758 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
759 // ---------------------------------------------------------------------
761 bool ContentsWriter::ReadFromPkgs(string PkgFile
,string PkgCompress
)
763 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
764 if (_error
->PendingError() == true)
767 // Open the package file
770 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
774 FileFd
Fd(CompFd
,false);
775 pkgTagFile
Tags(&Fd
);
776 if (_error
->PendingError() == true)
778 Pkgs
.CloseOld(CompFd
,Proc
);
783 pkgTagSection Section
;
784 while (Tags
.Step(Section
) == true)
786 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
787 string Package
= Section
.FindS("Section");
788 if (Package
.empty() == false && Package
.end()[-1] != '/')
791 Package
+= Section
.FindS("Package");
794 Package
+= Section
.FindS("Package");
796 DoPackage(File
,Package
);
797 if (_error
->empty() == false)
799 _error
->Error("Errors apply to file '%s'",File
.c_str());
800 _error
->DumpErrors();
804 // Tidy the compressor
805 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
813 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
814 // ---------------------------------------------------------------------
816 ReleaseWriter::ReleaseWriter(string DB
)
818 AddPattern("Packages");
819 AddPattern("Packages.gz");
820 AddPattern("Packages.bz2");
821 AddPattern("Sources");
822 AddPattern("Sources.gz");
823 AddPattern("Sources.bz2");
824 AddPattern("Release");
825 AddPattern("md5sum.txt");
828 time_t now
= time(NULL
);
830 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
836 map
<string
,string
> Fields
;
837 Fields
["Origin"] = "";
838 Fields
["Label"] = "";
839 Fields
["Suite"] = "";
840 Fields
["Version"] = "";
841 Fields
["Codename"] = "";
842 Fields
["Date"] = datestr
;
843 Fields
["Architectures"] = "";
844 Fields
["Components"] = "";
845 Fields
["Description"] = "";
847 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
851 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
852 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
856 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
860 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
861 // ---------------------------------------------------------------------
862 bool ReleaseWriter::DoPackage(string FileName
)
864 // Strip the DirStrip prefix from the FileName and add the PathPrefix
866 if (DirStrip
.empty() == false &&
867 FileName
.length() > DirStrip
.length() &&
868 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
869 DirStrip
.begin(),DirStrip
.end()) == 0)
871 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
872 while (NewFileName
[0] == '/')
873 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
876 NewFileName
= FileName
;
878 if (PathPrefix
.empty() == false)
879 NewFileName
= flCombine(PathPrefix
,NewFileName
);
881 FileFd
fd(FileName
, FileFd::ReadOnly
);
888 CheckSums
[NewFileName
].size
= fd
.Size();
891 MD5
.AddFD(fd
.Fd(), fd
.Size());
892 CheckSums
[NewFileName
].MD5
= MD5
.Result();
896 SHA1
.AddFD(fd
.Fd(), fd
.Size());
897 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
900 SHA256Summation SHA256
;
901 SHA256
.AddFD(fd
.Fd(), fd
.Size());
902 CheckSums
[NewFileName
].SHA256
= SHA256
.Result();
910 // ReleaseWriter::Finish - Output the checksums /*{{{*/
911 // ---------------------------------------------------------------------
912 void ReleaseWriter::Finish()
914 fprintf(Output
, "MD5Sum:\n");
915 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
916 I
!= CheckSums
.end();
919 fprintf(Output
, " %s %16ld %s\n",
920 (*I
).second
.MD5
.c_str(),
925 fprintf(Output
, "SHA1:\n");
926 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
927 I
!= CheckSums
.end();
930 fprintf(Output
, " %s %16ld %s\n",
931 (*I
).second
.SHA1
.c_str(),
936 fprintf(Output
, "SHA256:\n");
937 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
938 I
!= CheckSums
.end();
941 fprintf(Output
, " %s %16ld %s\n",
942 (*I
).second
.SHA256
.c_str(),