]>
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);
62 long PMax
= pathconf(".",_PC_PATH_MAX
);
64 RealPath
= new char[PMax
];
67 // FTWScanner::Scanner - FTW Scanner /*{{{*/
68 // ---------------------------------------------------------------------
69 /* This is the FTW scanner, it processes each directory element in the
71 int FTWScanner::ScannerFTW(const char *File
,const struct stat
*sb
,int Flag
)
76 ioprintf(c1out
, _("W: Unable to read directory %s\n"), File
);
81 ioprintf(c1out
, _("W: Unable to stat %s\n"), File
);
86 return ScannerFile(File
, true);
89 // FTWScanner::ScannerFile - File Scanner /*{{{*/
90 // ---------------------------------------------------------------------
92 int FTWScanner::ScannerFile(const char *File
, bool ReadLink
)
94 const char *LastComponent
= strrchr(File
, '/');
95 if (LastComponent
== NULL
)
100 vector
<string
>::iterator I
;
101 for(I
= Owner
->Patterns
.begin(); I
!= Owner
->Patterns
.end(); ++I
)
103 if (fnmatch((*I
).c_str(), LastComponent
, 0) == 0)
106 if (I
== Owner
->Patterns
.end())
109 /* Process it. If the file is a link then resolve it into an absolute
110 name.. This works best if the directory components the scanner are
111 given are not links themselves. */
113 Owner
->OriginalPath
= File
;
114 if (ReadLink
&& Owner
->RealPath
!= 0 &&
115 readlink(File
,Jnk
,sizeof(Jnk
)) != -1 &&
116 realpath(File
,Owner
->RealPath
) != 0)
117 Owner
->DoPackage(Owner
->RealPath
);
119 Owner
->DoPackage(File
);
121 if (_error
->empty() == false)
123 // Print any errors or warnings found
125 bool SeenPath
= false;
126 while (_error
->empty() == false)
130 bool Type
= _error
->PopMessage(Err
);
132 cerr
<< _("E: ") << Err
<< endl
;
134 cerr
<< _("W: ") << Err
<< endl
;
136 if (Err
.find(File
) != string::npos
)
140 if (SeenPath
== false)
141 cerr
<< _("E: Errors apply to file ") << "'" << File
<< "'" << endl
;
148 // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
149 // ---------------------------------------------------------------------
151 bool FTWScanner::RecursiveScan(string Dir
)
153 /* If noprefix is set then jam the scan root in, so we don't generate
154 link followed paths out of control */
155 if (InternalPrefix
.empty() == true)
157 if (realpath(Dir
.c_str(),RealPath
) == 0)
158 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
159 InternalPrefix
= RealPath
;
162 // Do recursive directory searching
164 int Res
= ftw(Dir
.c_str(),ScannerFTW
,30);
166 // Error treewalking?
169 if (_error
->PendingError() == false)
170 _error
->Errno("ftw",_("Tree walking failed"));
177 // FTWScanner::LoadFileList - Load the file list from a file /*{{{*/
178 // ---------------------------------------------------------------------
179 /* This is an alternative to using FTW to locate files, it reads the list
180 of files from another file. */
181 bool FTWScanner::LoadFileList(string Dir
,string File
)
183 /* If noprefix is set then jam the scan root in, so we don't generate
184 link followed paths out of control */
185 if (InternalPrefix
.empty() == true)
187 if (realpath(Dir
.c_str(),RealPath
) == 0)
188 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
189 InternalPrefix
= RealPath
;
193 FILE *List
= fopen(File
.c_str(),"r");
195 return _error
->Errno("fopen",_("Failed to open %s"),File
.c_str());
197 /* We are a tad tricky here.. We prefix the buffer with the directory
198 name, that way if we need a full path with just use line.. Sneaky and
202 if (Dir
.empty() == true || Dir
.end()[-1] != '/')
203 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s/",Dir
.c_str());
205 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s",Dir
.c_str());
206 while (fgets(FileStart
,sizeof(Line
) - (FileStart
- Line
),List
) != 0)
208 char *FileName
= _strstrip(FileStart
);
209 if (FileName
[0] == 0)
212 if (FileName
[0] != '/')
214 if (FileName
!= FileStart
)
215 memmove(FileStart
,FileName
,strlen(FileStart
));
222 if (stat(FileName
,&St
) != 0)
226 if (ScannerFile(FileName
, false) != 0)
234 // FTWScanner::Delink - Delink symlinks /*{{{*/
235 // ---------------------------------------------------------------------
237 bool FTWScanner::Delink(string
&FileName
,const char *OriginalPath
,
238 unsigned long &DeLinkBytes
,
241 // See if this isn't an internaly prefix'd file name.
242 if (InternalPrefix
.empty() == false &&
243 InternalPrefix
.length() < FileName
.length() &&
244 stringcmp(FileName
.begin(),FileName
.begin() + InternalPrefix
.length(),
245 InternalPrefix
.begin(),InternalPrefix
.end()) != 0)
247 if (DeLinkLimit
!= 0 && DeLinkBytes
/1024 < DeLinkLimit
)
249 // Tidy up the display
250 if (DeLinkBytes
== 0)
254 ioprintf(c1out
, _(" DeLink %s [%s]\n"), (OriginalPath
+ InternalPrefix
.length()),
255 SizeToStr(FileSize
).c_str());
258 if (NoLinkAct
== false)
261 if (readlink(OriginalPath
,OldLink
,sizeof(OldLink
)) == -1)
262 _error
->Errno("readlink",_("Failed to readlink %s"),OriginalPath
);
265 if (unlink(OriginalPath
) != 0)
266 _error
->Errno("unlink",_("Failed to unlink %s"),OriginalPath
);
269 if (link(FileName
.c_str(),OriginalPath
) != 0)
271 // Panic! Restore the symlink
272 symlink(OldLink
,OriginalPath
);
273 return _error
->Errno("link",_("*** Failed to link %s to %s"),
281 DeLinkBytes
+= FileSize
;
282 if (DeLinkBytes
/1024 >= DeLinkLimit
)
283 ioprintf(c1out
, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes
).c_str());
286 FileName
= OriginalPath
;
293 // PackagesWriter::PackagesWriter - Constructor /*{{{*/
294 // ---------------------------------------------------------------------
296 PackagesWriter::PackagesWriter(string DB
,string Overrides
,string ExtOverrides
,
298 Db(DB
),Stats(Db
.Stats
), Arch(aArch
)
301 SetExts(".deb .udeb .foo .bar .baz");
305 // Process the command line options
306 DoMD5
= _config
->FindB("APT::FTPArchive::MD5",true);
307 DoSHA1
= _config
->FindB("APT::FTPArchive::SHA1",true);
308 DoSHA256
= _config
->FindB("APT::FTPArchive::SHA256",true);
309 DoContents
= _config
->FindB("APT::FTPArchive::Contents",true);
310 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
312 if (Db
.Loaded() == false)
315 // Read the override file
316 if (Overrides
.empty() == false && Over
.ReadOverride(Overrides
) == false)
321 if (ExtOverrides
.empty() == false)
322 Over
.ReadExtraOverride(ExtOverrides
);
324 _error
->DumpErrors();
327 // FTWScanner::SetExts - Set extensions to support /*{{{*/
328 // ---------------------------------------------------------------------
330 bool FTWScanner::SetExts(string Vals
)
333 string::size_type Start
= 0;
334 while (Start
<= Vals
.length()-1)
336 string::size_type Space
= Vals
.find(' ',Start
);
337 string::size_type Length
;
338 if (Space
== string::npos
)
340 Length
= Vals
.length()-Start
;
344 Length
= Space
-Start
;
346 AddPattern(string("*") + Vals
.substr(Start
, Length
));
354 // PackagesWriter::DoPackage - Process a single package /*{{{*/
355 // ---------------------------------------------------------------------
356 /* This method takes a package and gets its control information and
357 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
358 rewritten and the path/size/hash appended. */
359 bool PackagesWriter::DoPackage(string FileName
)
361 // Pull all the data we need form the DB
362 if (Db
.GetFileInfo(FileName
, true, DoContents
, true, DoMD5
, DoSHA1
, DoSHA256
)
368 off_t FileSize
= Db
.GetFileSize();
369 if (Delink(FileName
,OriginalPath
,Stats
.DeLinkBytes
,FileSize
) == false)
372 // Lookup the overide information
373 pkgTagSection
&Tags
= Db
.Control
.Section
;
374 string Package
= Tags
.FindS("Package");
376 // if we generate a Packages file for a given arch, we use it to
377 // look for overrides. if we run in "simple" mode without the
378 // "Architecures" variable in the config we use the architecure value
383 Architecture
= Tags
.FindS("Architecture");
384 auto_ptr
<Override::Item
> OverItem(Over
.GetItem(Package
,Architecture
));
386 if (Package
.empty() == true)
387 return _error
->Error(_("Archive had no package field"));
389 // If we need to do any rewriting of the header do it now..
390 if (OverItem
.get() == 0)
392 if (NoOverride
== false)
395 ioprintf(c1out
, _(" %s has no override entry\n"), Package
.c_str());
398 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
399 OverItem
->FieldOverride
["Section"] = Tags
.FindS("Section");
400 OverItem
->Priority
= Tags
.FindS("Priority");
404 sprintf(Size
,"%lu", (unsigned long) FileSize
);
406 // Strip the DirStrip prefix from the FileName and add the PathPrefix
408 if (DirStrip
.empty() == false &&
409 FileName
.length() > DirStrip
.length() &&
410 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
411 DirStrip
.begin(),DirStrip
.end()) == 0)
412 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
414 NewFileName
= FileName
;
415 if (PathPrefix
.empty() == false)
416 NewFileName
= flCombine(PathPrefix
,NewFileName
);
418 // This lists all the changes to the fields we are going to make.
419 // (7 hardcoded + maintainer + suggests + end marker)
420 TFRewriteData Changes
[6+2+OverItem
->FieldOverride
.size()+1];
422 unsigned int End
= 0;
423 SetTFRewriteData(Changes
[End
++], "Size", Size
);
424 SetTFRewriteData(Changes
[End
++], "MD5sum", Db
.MD5Res
.c_str());
425 SetTFRewriteData(Changes
[End
++], "SHA1", Db
.SHA1Res
.c_str());
426 SetTFRewriteData(Changes
[End
++], "SHA256", Db
.SHA256Res
.c_str());
427 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
428 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
429 SetTFRewriteData(Changes
[End
++], "Status", 0);
430 SetTFRewriteData(Changes
[End
++], "Optional", 0);
432 // Rewrite the maintainer field if necessary
434 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
435 if (MaintFailed
== true)
437 if (NoOverride
== false)
440 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
441 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
445 if (NewMaint
.empty() == false)
446 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
448 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
449 dpkg-scanpackages does.. Well sort of. dpkg-scanpackages just does renaming
450 but dpkg does this append bit. So we do the append bit, at least that way the
451 status file and package file will remain similar. There are other transforms
452 but optional is the only legacy one still in use for some lazy reason. */
453 string OptionalStr
= Tags
.FindS("Optional");
454 if (OptionalStr
.empty() == false)
456 if (Tags
.FindS("Suggests").empty() == false)
457 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
458 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
461 for (map
<string
,string
>::iterator I
= OverItem
->FieldOverride
.begin();
462 I
!= OverItem
->FieldOverride
.end(); I
++)
463 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
465 SetTFRewriteData(Changes
[End
++], 0, 0);
467 // Rewrite and store the fields.
468 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
470 fprintf(Output
,"\n");
476 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
477 // ---------------------------------------------------------------------
479 SourcesWriter::SourcesWriter(string BOverrides
,string SOverrides
,
488 // Process the command line options
489 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
491 // Read the override file
492 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
497 // WTF?? The logic above: if we can't read binary overrides, don't even try
498 // reading source overrides. if we can read binary overrides, then say there
499 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
501 if (ExtOverrides
.empty() == false)
502 SOver
.ReadExtraOverride(ExtOverrides
);
504 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
505 SOver
.ReadOverride(SOverrides
,true);
508 // SourcesWriter::DoPackage - Process a single package /*{{{*/
509 // ---------------------------------------------------------------------
511 bool SourcesWriter::DoPackage(string FileName
)
514 FileFd
F(FileName
,FileFd::ReadOnly
);
515 if (_error
->PendingError() == true)
518 // Stat the file for later
520 if (fstat(F
.Fd(),&St
) != 0)
521 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
523 if (St
.st_size
> 128*1024)
524 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
526 if (BufSize
< (unsigned)St
.st_size
+1)
528 BufSize
= St
.st_size
+1;
529 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
532 if (F
.Read(Buffer
,St
.st_size
) == false)
536 char *Start
= Buffer
;
537 char *BlkEnd
= Buffer
+ St
.st_size
;
539 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
541 // Add an extra \n to the end, just in case
544 /* Remove the PGP trailer. Some .dsc's have this without a blank line
546 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
547 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
549 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
556 /* Read records until we locate the Source record. This neatly skips the
557 GPG header (which is RFC822 formed) without any trouble. */
562 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
563 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
564 if (Tags
.Find("Source",Pos
) == true)
566 Start
+= Tags
.size();
571 // Lookup the overide information, finding first the best priority.
573 string Bins
= Tags
.FindS("Binary");
574 char Buffer
[Bins
.length() + 1];
575 auto_ptr
<Override::Item
> OverItem(0);
576 if (Bins
.empty() == false)
578 strcpy(Buffer
,Bins
.c_str());
580 // Ignore too-long errors.
582 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
584 // Look at all the binaries
585 unsigned char BestPrioV
= pkgCache::State::Extra
;
586 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
588 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
592 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
593 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
595 BestPrioV
= NewPrioV
;
596 BestPrio
= Itm
->Priority
;
599 if (OverItem
.get() == 0)
604 // If we need to do any rewriting of the header do it now..
605 if (OverItem
.get() == 0)
607 if (NoOverride
== false)
610 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
613 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
616 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
617 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
618 if (SOverItem
.get() == 0)
620 ioprintf(c1out
, _(" %s has no source override entry\n"), Tags
.FindS("Source").c_str());
621 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
622 if (SOverItem
.get() == 0)
624 ioprintf(c1out
, _(" %s has no binary override entry either\n"), Tags
.FindS("Source").c_str());
625 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
626 *SOverItem
= *OverItem
;
630 // Add the dsc to the files hash list
632 snprintf(Files
,sizeof(Files
),"\n %s %lu %s\n %s",
633 string(MD5
.Result()).c_str(),St
.st_size
,
634 flNotDir(FileName
).c_str(),
635 Tags
.FindS("Files").c_str());
637 // Strip the DirStrip prefix from the FileName and add the PathPrefix
639 if (DirStrip
.empty() == false &&
640 FileName
.length() > DirStrip
.length() &&
641 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
642 NewFileName
= string(OriginalPath
+ DirStrip
.length());
644 NewFileName
= OriginalPath
;
645 if (PathPrefix
.empty() == false)
646 NewFileName
= flCombine(PathPrefix
,NewFileName
);
648 string Directory
= flNotFile(OriginalPath
);
649 string Package
= Tags
.FindS("Source");
651 // Perform the delinking operation over all of the files
653 const char *C
= Files
;
654 for (;isspace(*C
); C
++);
657 // Parse each of the elements
658 if (ParseQuoteWord(C
,ParseJnk
) == false ||
659 ParseQuoteWord(C
,ParseJnk
) == false ||
660 ParseQuoteWord(C
,ParseJnk
) == false)
661 return _error
->Error("Error parsing file record");
664 string OriginalPath
= Directory
+ ParseJnk
;
665 if (RealPath
!= 0 && readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
666 realpath(OriginalPath
.c_str(),RealPath
) != 0)
668 string RP
= RealPath
;
669 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
674 Directory
= flNotFile(NewFileName
);
675 if (Directory
.length() > 2)
676 Directory
.erase(Directory
.end()-1);
678 // This lists all the changes to the fields we are going to make.
679 // (5 hardcoded + maintainer + end marker)
680 TFRewriteData Changes
[5+1+SOverItem
->FieldOverride
.size()+1];
682 unsigned int End
= 0;
683 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
684 SetTFRewriteData(Changes
[End
++],"Files",Files
);
685 if (Directory
!= "./")
686 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
687 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
688 SetTFRewriteData(Changes
[End
++],"Status",0);
690 // Rewrite the maintainer field if necessary
692 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
693 if (MaintFailed
== true)
695 if (NoOverride
== false)
698 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
699 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
702 if (NewMaint
.empty() == false)
703 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
705 for (map
<string
,string
>::iterator I
= SOverItem
->FieldOverride
.begin();
706 I
!= SOverItem
->FieldOverride
.end(); I
++)
707 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
709 SetTFRewriteData(Changes
[End
++], 0, 0);
711 // Rewrite and store the fields.
712 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
714 fprintf(Output
,"\n");
722 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
723 // ---------------------------------------------------------------------
725 ContentsWriter::ContentsWriter(string DB
) :
726 Db(DB
), Stats(Db
.Stats
)
733 // ContentsWriter::DoPackage - Process a single package /*{{{*/
734 // ---------------------------------------------------------------------
735 /* If Package is the empty string the control record will be parsed to
736 determine what the package name is. */
737 bool ContentsWriter::DoPackage(string FileName
,string Package
)
739 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false))
744 // Parse the package name
745 if (Package
.empty() == true)
747 Package
= Db
.Control
.Section
.FindS("Package");
750 Db
.Contents
.Add(Gen
,Package
);
755 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
756 // ---------------------------------------------------------------------
758 bool ContentsWriter::ReadFromPkgs(string PkgFile
,string PkgCompress
)
760 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
761 if (_error
->PendingError() == true)
764 // Open the package file
767 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
771 FileFd
Fd(CompFd
,false);
772 pkgTagFile
Tags(&Fd
);
773 if (_error
->PendingError() == true)
775 Pkgs
.CloseOld(CompFd
,Proc
);
780 pkgTagSection Section
;
781 while (Tags
.Step(Section
) == true)
783 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
784 string Package
= Section
.FindS("Section");
785 if (Package
.empty() == false && Package
.end()[-1] != '/')
788 Package
+= Section
.FindS("Package");
791 Package
+= Section
.FindS("Package");
793 DoPackage(File
,Package
);
794 if (_error
->empty() == false)
796 _error
->Error("Errors apply to file '%s'",File
.c_str());
797 _error
->DumpErrors();
801 // Tidy the compressor
802 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
810 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
811 // ---------------------------------------------------------------------
813 ReleaseWriter::ReleaseWriter(string DB
)
815 AddPattern("Packages");
816 AddPattern("Packages.gz");
817 AddPattern("Packages.bz2");
818 AddPattern("Sources");
819 AddPattern("Sources.gz");
820 AddPattern("Sources.bz2");
821 AddPattern("Release");
822 AddPattern("md5sum.txt");
825 time_t now
= time(NULL
);
827 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
833 map
<string
,string
> Fields
;
834 Fields
["Origin"] = "";
835 Fields
["Label"] = "";
836 Fields
["Suite"] = "";
837 Fields
["Version"] = "";
838 Fields
["Codename"] = "";
839 Fields
["Date"] = datestr
;
840 Fields
["Architectures"] = "";
841 Fields
["Components"] = "";
842 Fields
["Description"] = "";
844 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
848 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
849 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
853 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
857 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
858 // ---------------------------------------------------------------------
859 bool ReleaseWriter::DoPackage(string FileName
)
861 // Strip the DirStrip prefix from the FileName and add the PathPrefix
863 if (DirStrip
.empty() == false &&
864 FileName
.length() > DirStrip
.length() &&
865 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
866 DirStrip
.begin(),DirStrip
.end()) == 0)
868 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
869 while (NewFileName
[0] == '/')
870 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
873 NewFileName
= FileName
;
875 if (PathPrefix
.empty() == false)
876 NewFileName
= flCombine(PathPrefix
,NewFileName
);
878 FileFd
fd(FileName
, FileFd::ReadOnly
);
885 CheckSums
[NewFileName
].size
= fd
.Size();
888 MD5
.AddFD(fd
.Fd(), fd
.Size());
889 CheckSums
[NewFileName
].MD5
= MD5
.Result();
893 SHA1
.AddFD(fd
.Fd(), fd
.Size());
894 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
897 SHA256Summation SHA256
;
898 SHA256
.AddFD(fd
.Fd(), fd
.Size());
899 CheckSums
[NewFileName
].SHA256
= SHA256
.Result();
907 // ReleaseWriter::Finish - Output the checksums /*{{{*/
908 // ---------------------------------------------------------------------
909 void ReleaseWriter::Finish()
911 fprintf(Output
, "MD5Sum:\n");
912 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
913 I
!= CheckSums
.end();
916 fprintf(Output
, " %s %16ld %s\n",
917 (*I
).second
.MD5
.c_str(),
922 fprintf(Output
, "SHA1:\n");
923 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
924 I
!= CheckSums
.end();
927 fprintf(Output
, " %s %16ld %s\n",
928 (*I
).second
.SHA1
.c_str(),
933 fprintf(Output
, "SHA256:\n");
934 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
935 I
!= CheckSums
.end();
938 fprintf(Output
, " %s %16ld %s\n",
939 (*I
).second
.SHA256
.c_str(),