]>
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>
33 #include "apt-ftparchive.h"
34 #include "multicompress.h"
37 FTWScanner
*FTWScanner::Owner
;
39 // SetTFRewriteData - Helper for setting rewrite lists /*{{{*/
40 // ---------------------------------------------------------------------
42 inline void SetTFRewriteData(struct TFRewriteData
&tfrd
,
45 const char *newtag
= 0)
48 tfrd
.Rewrite
= rewrite
;
53 // FTWScanner::FTWScanner - Constructor /*{{{*/
54 // ---------------------------------------------------------------------
56 FTWScanner::FTWScanner()
59 NoLinkAct
= !_config
->FindB("APT::FTPArchive::DeLinkAct",true);
61 long PMax
= pathconf(".",_PC_PATH_MAX
);
63 RealPath
= new char[PMax
];
66 // FTWScanner::Scanner - FTW Scanner /*{{{*/
67 // ---------------------------------------------------------------------
68 /* This is the FTW scanner, it processes each directory element in the
70 int FTWScanner::ScannerFTW(const char *File
,const struct stat
*sb
,int Flag
)
75 ioprintf(c1out
, _("W: Unable to read directory %s\n"), File
);
80 ioprintf(c1out
, _("W: Unable to stat %s\n"), File
);
85 return ScannerFile(File
, true);
88 // FTWScanner::ScannerFile - File Scanner /*{{{*/
89 // ---------------------------------------------------------------------
91 int FTWScanner::ScannerFile(const char *File
, bool ReadLink
)
93 const char *LastComponent
= strrchr(File
, '/');
94 if (LastComponent
== NULL
)
99 vector
<string
>::iterator I
;
100 for(I
= Owner
->Patterns
.begin(); I
!= Owner
->Patterns
.end(); ++I
)
102 if (fnmatch((*I
).c_str(), LastComponent
, 0) == 0)
105 if (I
== Owner
->Patterns
.end())
108 /* Process it. If the file is a link then resolve it into an absolute
109 name.. This works best if the directory components the scanner are
110 given are not links themselves. */
112 Owner
->OriginalPath
= File
;
113 if (ReadLink
&& Owner
->RealPath
!= 0 &&
114 readlink(File
,Jnk
,sizeof(Jnk
)) != -1 &&
115 realpath(File
,Owner
->RealPath
) != 0)
116 Owner
->DoPackage(Owner
->RealPath
);
118 Owner
->DoPackage(File
);
120 if (_error
->empty() == false)
122 // Print any errors or warnings found
124 bool SeenPath
= false;
125 while (_error
->empty() == false)
129 bool Type
= _error
->PopMessage(Err
);
131 cerr
<< _("E: ") << Err
<< endl
;
133 cerr
<< _("W: ") << Err
<< endl
;
135 if (Err
.find(File
) != string::npos
)
139 if (SeenPath
== false)
140 cerr
<< _("E: Errors apply to file ") << "'" << File
<< "'" << endl
;
147 // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
148 // ---------------------------------------------------------------------
150 bool FTWScanner::RecursiveScan(string Dir
)
152 /* If noprefix is set then jam the scan root in, so we don't generate
153 link followed paths out of control */
154 if (InternalPrefix
.empty() == true)
156 if (realpath(Dir
.c_str(),RealPath
) == 0)
157 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
158 InternalPrefix
= RealPath
;
161 // Do recursive directory searching
163 int Res
= ftw(Dir
.c_str(),ScannerFTW
,30);
165 // Error treewalking?
168 if (_error
->PendingError() == false)
169 _error
->Errno("ftw",_("Tree walking failed"));
176 // FTWScanner::LoadFileList - Load the file list from a file /*{{{*/
177 // ---------------------------------------------------------------------
178 /* This is an alternative to using FTW to locate files, it reads the list
179 of files from another file. */
180 bool FTWScanner::LoadFileList(string Dir
,string File
)
182 /* If noprefix is set then jam the scan root in, so we don't generate
183 link followed paths out of control */
184 if (InternalPrefix
.empty() == true)
186 if (realpath(Dir
.c_str(),RealPath
) == 0)
187 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
188 InternalPrefix
= RealPath
;
192 FILE *List
= fopen(File
.c_str(),"r");
194 return _error
->Errno("fopen",_("Failed to open %s"),File
.c_str());
196 /* We are a tad tricky here.. We prefix the buffer with the directory
197 name, that way if we need a full path with just use line.. Sneaky and
201 if (Dir
.empty() == true || Dir
.end()[-1] != '/')
202 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s/",Dir
.c_str());
204 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s",Dir
.c_str());
205 while (fgets(FileStart
,sizeof(Line
) - (FileStart
- Line
),List
) != 0)
207 char *FileName
= _strstrip(FileStart
);
208 if (FileName
[0] == 0)
211 if (FileName
[0] != '/')
213 if (FileName
!= FileStart
)
214 memmove(FileStart
,FileName
,strlen(FileStart
));
221 if (stat(FileName
,&St
) != 0)
225 if (ScannerFile(FileName
, false) != 0)
233 // FTWScanner::Delink - Delink symlinks /*{{{*/
234 // ---------------------------------------------------------------------
236 bool FTWScanner::Delink(string
&FileName
,const char *OriginalPath
,
237 unsigned long &DeLinkBytes
,
240 // See if this isn't an internaly prefix'd file name.
241 if (InternalPrefix
.empty() == false &&
242 InternalPrefix
.length() < FileName
.length() &&
243 stringcmp(FileName
.begin(),FileName
.begin() + InternalPrefix
.length(),
244 InternalPrefix
.begin(),InternalPrefix
.end()) != 0)
246 if (DeLinkLimit
!= 0 && DeLinkBytes
/1024 < DeLinkLimit
)
248 // Tidy up the display
249 if (DeLinkBytes
== 0)
253 ioprintf(c1out
, _(" DeLink %s [%s]\n"), (OriginalPath
+ InternalPrefix
.length()),
254 SizeToStr(FileSize
).c_str());
257 if (NoLinkAct
== false)
260 if (readlink(OriginalPath
,OldLink
,sizeof(OldLink
)) == -1)
261 _error
->Errno("readlink",_("Failed to readlink %s"),OriginalPath
);
264 if (unlink(OriginalPath
) != 0)
265 _error
->Errno("unlink",_("Failed to unlink %s"),OriginalPath
);
268 if (link(FileName
.c_str(),OriginalPath
) != 0)
270 // Panic! Restore the symlink
271 symlink(OldLink
,OriginalPath
);
272 return _error
->Errno("link",_("*** Failed to link %s to %s"),
280 DeLinkBytes
+= FileSize
;
281 if (DeLinkBytes
/1024 >= DeLinkLimit
)
282 ioprintf(c1out
, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes
).c_str());
285 FileName
= OriginalPath
;
292 // PackagesWriter::PackagesWriter - Constructor /*{{{*/
293 // ---------------------------------------------------------------------
295 PackagesWriter::PackagesWriter(string DB
,string Overrides
,string ExtOverrides
,
297 Db(DB
),Stats(Db
.Stats
), Arch(aArch
)
300 SetExts(".deb .udeb .foo .bar .baz");
304 // Process the command line options
305 DoMD5
= _config
->FindB("APT::FTPArchive::MD5",true);
306 DoSHA1
= _config
->FindB("APT::FTPArchive::SHA1",true);
307 DoSHA256
= _config
->FindB("APT::FTPArchive::SHA256",true);
308 DoContents
= _config
->FindB("APT::FTPArchive::Contents",true);
309 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
311 if (Db
.Loaded() == false)
314 // Read the override file
315 if (Overrides
.empty() == false && Over
.ReadOverride(Overrides
) == false)
320 if (ExtOverrides
.empty() == false)
321 Over
.ReadExtraOverride(ExtOverrides
);
323 _error
->DumpErrors();
326 // FTWScanner::SetExts - Set extensions to support /*{{{*/
327 // ---------------------------------------------------------------------
329 bool FTWScanner::SetExts(string Vals
)
332 string::size_type Start
= 0;
333 while (Start
<= Vals
.length()-1)
335 string::size_type Space
= Vals
.find(' ',Start
);
336 string::size_type Length
;
337 if (Space
== string::npos
)
339 Length
= Vals
.length()-Start
;
343 Length
= Space
-Start
;
345 AddPattern(string("*") + Vals
.substr(Start
, Length
));
353 // PackagesWriter::DoPackage - Process a single package /*{{{*/
354 // ---------------------------------------------------------------------
355 /* This method takes a package and gets its control information and
356 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
357 rewritten and the path/size/hash appended. */
358 bool PackagesWriter::DoPackage(string FileName
)
360 // Pull all the data we need form the DB
361 if (Db
.GetFileInfo(FileName
, true, DoContents
, true, DoMD5
, DoSHA1
, DoSHA256
)
367 off_t FileSize
= Db
.GetFileSize();
368 if (Delink(FileName
,OriginalPath
,Stats
.DeLinkBytes
,FileSize
) == false)
371 // Lookup the overide information
372 pkgTagSection
&Tags
= Db
.Control
.Section
;
373 string Package
= Tags
.FindS("Package");
375 // if we generate a Packages file for a given arch, we use it to
376 // look for overrides. if we run in "simple" mode without the
377 // "Architecures" variable in the config we use the architecure value
382 Architecture
= Tags
.FindS("Architecture");
383 auto_ptr
<Override::Item
> OverItem(Over
.GetItem(Package
,Architecture
));
385 if (Package
.empty() == true)
386 return _error
->Error(_("Archive had no package field"));
388 // If we need to do any rewriting of the header do it now..
389 if (OverItem
.get() == 0)
391 if (NoOverride
== false)
394 ioprintf(c1out
, _(" %s has no override entry\n"), Package
.c_str());
397 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
398 OverItem
->FieldOverride
["Section"] = Tags
.FindS("Section");
399 OverItem
->Priority
= Tags
.FindS("Priority");
403 sprintf(Size
,"%lu", (unsigned long) FileSize
);
405 // Strip the DirStrip prefix from the FileName and add the PathPrefix
407 if (DirStrip
.empty() == false &&
408 FileName
.length() > DirStrip
.length() &&
409 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
410 DirStrip
.begin(),DirStrip
.end()) == 0)
411 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
413 NewFileName
= FileName
;
414 if (PathPrefix
.empty() == false)
415 NewFileName
= flCombine(PathPrefix
,NewFileName
);
417 // This lists all the changes to the fields we are going to make.
418 // (7 hardcoded + maintainer + suggests + end marker)
419 TFRewriteData Changes
[6+2+OverItem
->FieldOverride
.size()+1];
421 unsigned int End
= 0;
422 SetTFRewriteData(Changes
[End
++], "Size", Size
);
423 SetTFRewriteData(Changes
[End
++], "MD5sum", Db
.MD5Res
.c_str());
424 SetTFRewriteData(Changes
[End
++], "SHA1", Db
.SHA1Res
.c_str());
425 SetTFRewriteData(Changes
[End
++], "SHA256", Db
.SHA256Res
.c_str());
426 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
427 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
428 SetTFRewriteData(Changes
[End
++], "Status", 0);
429 SetTFRewriteData(Changes
[End
++], "Optional", 0);
431 // Rewrite the maintainer field if necessary
433 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
434 if (MaintFailed
== true)
436 if (NoOverride
== false)
439 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
440 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
444 if (NewMaint
.empty() == false)
445 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
447 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
448 dpkg-scanpackages does.. Well sort of. dpkg-scanpackages just does renaming
449 but dpkg does this append bit. So we do the append bit, at least that way the
450 status file and package file will remain similar. There are other transforms
451 but optional is the only legacy one still in use for some lazy reason. */
452 string OptionalStr
= Tags
.FindS("Optional");
453 if (OptionalStr
.empty() == false)
455 if (Tags
.FindS("Suggests").empty() == false)
456 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
457 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
460 for (map
<string
,string
>::iterator I
= OverItem
->FieldOverride
.begin();
461 I
!= OverItem
->FieldOverride
.end(); I
++)
462 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
464 SetTFRewriteData(Changes
[End
++], 0, 0);
466 // Rewrite and store the fields.
467 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
469 fprintf(Output
,"\n");
475 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
476 // ---------------------------------------------------------------------
478 SourcesWriter::SourcesWriter(string BOverrides
,string SOverrides
,
487 // Process the command line options
488 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
490 // Read the override file
491 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
496 // WTF?? The logic above: if we can't read binary overrides, don't even try
497 // reading source overrides. if we can read binary overrides, then say there
498 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
500 if (ExtOverrides
.empty() == false)
501 SOver
.ReadExtraOverride(ExtOverrides
);
503 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
504 SOver
.ReadOverride(SOverrides
,true);
507 // SourcesWriter::DoPackage - Process a single package /*{{{*/
508 // ---------------------------------------------------------------------
510 bool SourcesWriter::DoPackage(string FileName
)
513 FileFd
F(FileName
,FileFd::ReadOnly
);
514 if (_error
->PendingError() == true)
517 // Stat the file for later
519 if (fstat(F
.Fd(),&St
) != 0)
520 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
522 if (St
.st_size
> 128*1024)
523 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
525 if (BufSize
< (unsigned)St
.st_size
+1)
527 BufSize
= St
.st_size
+1;
528 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
531 if (F
.Read(Buffer
,St
.st_size
) == false)
535 char *Start
= Buffer
;
536 char *BlkEnd
= Buffer
+ St
.st_size
;
538 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
540 // Add an extra \n to the end, just in case
543 /* Remove the PGP trailer. Some .dsc's have this without a blank line
545 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
546 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
548 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
555 /* Read records until we locate the Source record. This neatly skips the
556 GPG header (which is RFC822 formed) without any trouble. */
561 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
562 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
563 if (Tags
.Find("Source",Pos
) == true)
565 Start
+= Tags
.size();
570 // Lookup the overide information, finding first the best priority.
572 string Bins
= Tags
.FindS("Binary");
573 char Buffer
[Bins
.length() + 1];
574 auto_ptr
<Override::Item
> OverItem(0);
575 if (Bins
.empty() == false)
577 strcpy(Buffer
,Bins
.c_str());
579 // Ignore too-long errors.
581 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
583 // Look at all the binaries
584 unsigned char BestPrioV
= pkgCache::State::Extra
;
585 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
587 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
591 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
592 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
594 BestPrioV
= NewPrioV
;
595 BestPrio
= Itm
->Priority
;
598 if (OverItem
.get() == 0)
603 // If we need to do any rewriting of the header do it now..
604 if (OverItem
.get() == 0)
606 if (NoOverride
== false)
609 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
612 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
615 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
616 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
617 if (SOverItem
.get() == 0)
619 ioprintf(c1out
, _(" %s has no source override entry\n"), Tags
.FindS("Source").c_str());
620 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
621 if (SOverItem
.get() == 0)
623 ioprintf(c1out
, _(" %s has no binary override entry either\n"), Tags
.FindS("Source").c_str());
624 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
625 *SOverItem
= *OverItem
;
629 // Add the dsc to the files hash list
631 snprintf(Files
,sizeof(Files
),"\n %s %lu %s\n %s",
632 string(MD5
.Result()).c_str(),St
.st_size
,
633 flNotDir(FileName
).c_str(),
634 Tags
.FindS("Files").c_str());
636 // Strip the DirStrip prefix from the FileName and add the PathPrefix
638 if (DirStrip
.empty() == false &&
639 FileName
.length() > DirStrip
.length() &&
640 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
641 NewFileName
= string(OriginalPath
+ DirStrip
.length());
643 NewFileName
= OriginalPath
;
644 if (PathPrefix
.empty() == false)
645 NewFileName
= flCombine(PathPrefix
,NewFileName
);
647 string Directory
= flNotFile(OriginalPath
);
648 string Package
= Tags
.FindS("Source");
650 // Perform the delinking operation over all of the files
652 const char *C
= Files
;
653 for (;isspace(*C
); C
++);
656 // Parse each of the elements
657 if (ParseQuoteWord(C
,ParseJnk
) == false ||
658 ParseQuoteWord(C
,ParseJnk
) == false ||
659 ParseQuoteWord(C
,ParseJnk
) == false)
660 return _error
->Error("Error parsing file record");
663 string OriginalPath
= Directory
+ ParseJnk
;
664 if (RealPath
!= 0 && readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
665 realpath(OriginalPath
.c_str(),RealPath
) != 0)
667 string RP
= RealPath
;
668 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
673 Directory
= flNotFile(NewFileName
);
674 if (Directory
.length() > 2)
675 Directory
.erase(Directory
.end()-1);
677 // This lists all the changes to the fields we are going to make.
678 // (5 hardcoded + maintainer + end marker)
679 TFRewriteData Changes
[5+1+SOverItem
->FieldOverride
.size()+1];
681 unsigned int End
= 0;
682 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
683 SetTFRewriteData(Changes
[End
++],"Files",Files
);
684 if (Directory
!= "./")
685 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
686 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
687 SetTFRewriteData(Changes
[End
++],"Status",0);
689 // Rewrite the maintainer field if necessary
691 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
692 if (MaintFailed
== true)
694 if (NoOverride
== false)
697 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
698 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
701 if (NewMaint
.empty() == false)
702 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
704 for (map
<string
,string
>::iterator I
= SOverItem
->FieldOverride
.begin();
705 I
!= SOverItem
->FieldOverride
.end(); I
++)
706 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
708 SetTFRewriteData(Changes
[End
++], 0, 0);
710 // Rewrite and store the fields.
711 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
713 fprintf(Output
,"\n");
721 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
722 // ---------------------------------------------------------------------
724 ContentsWriter::ContentsWriter(string DB
) :
725 Db(DB
), Stats(Db
.Stats
)
732 // ContentsWriter::DoPackage - Process a single package /*{{{*/
733 // ---------------------------------------------------------------------
734 /* If Package is the empty string the control record will be parsed to
735 determine what the package name is. */
736 bool ContentsWriter::DoPackage(string FileName
,string Package
)
738 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false))
743 // Parse the package name
744 if (Package
.empty() == true)
746 Package
= Db
.Control
.Section
.FindS("Package");
749 Db
.Contents
.Add(Gen
,Package
);
754 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
755 // ---------------------------------------------------------------------
757 bool ContentsWriter::ReadFromPkgs(string PkgFile
,string PkgCompress
)
759 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
760 if (_error
->PendingError() == true)
763 // Open the package file
766 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
770 FileFd
Fd(CompFd
,false);
771 pkgTagFile
Tags(&Fd
);
772 if (_error
->PendingError() == true)
774 Pkgs
.CloseOld(CompFd
,Proc
);
779 pkgTagSection Section
;
780 while (Tags
.Step(Section
) == true)
782 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
783 string Package
= Section
.FindS("Section");
784 if (Package
.empty() == false && Package
.end()[-1] != '/')
787 Package
+= Section
.FindS("Package");
790 Package
+= Section
.FindS("Package");
792 DoPackage(File
,Package
);
793 if (_error
->empty() == false)
795 _error
->Error("Errors apply to file '%s'",File
.c_str());
796 _error
->DumpErrors();
800 // Tidy the compressor
801 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
809 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
810 // ---------------------------------------------------------------------
812 ReleaseWriter::ReleaseWriter(string DB
)
814 AddPattern("Packages");
815 AddPattern("Packages.gz");
816 AddPattern("Packages.bz2");
817 AddPattern("Sources");
818 AddPattern("Sources.gz");
819 AddPattern("Sources.bz2");
820 AddPattern("Release");
821 AddPattern("md5sum.txt");
824 time_t now
= time(NULL
);
826 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
832 map
<string
,string
> Fields
;
833 Fields
["Origin"] = "";
834 Fields
["Label"] = "";
835 Fields
["Suite"] = "";
836 Fields
["Version"] = "";
837 Fields
["Codename"] = "";
838 Fields
["Date"] = datestr
;
839 Fields
["Architectures"] = "";
840 Fields
["Components"] = "";
841 Fields
["Description"] = "";
843 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
847 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
848 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
852 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
856 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
857 // ---------------------------------------------------------------------
858 bool ReleaseWriter::DoPackage(string FileName
)
860 // Strip the DirStrip prefix from the FileName and add the PathPrefix
862 if (DirStrip
.empty() == false &&
863 FileName
.length() > DirStrip
.length() &&
864 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
865 DirStrip
.begin(),DirStrip
.end()) == 0)
867 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
868 while (NewFileName
[0] == '/')
869 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
872 NewFileName
= FileName
;
874 if (PathPrefix
.empty() == false)
875 NewFileName
= flCombine(PathPrefix
,NewFileName
);
877 FileFd
fd(FileName
, FileFd::ReadOnly
);
884 CheckSums
[NewFileName
].size
= fd
.Size();
887 MD5
.AddFD(fd
.Fd(), fd
.Size());
888 CheckSums
[NewFileName
].MD5
= MD5
.Result();
892 SHA1
.AddFD(fd
.Fd(), fd
.Size());
893 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
896 SHA256Summation SHA256
;
897 SHA256
.AddFD(fd
.Fd(), fd
.Size());
898 CheckSums
[NewFileName
].SHA256
= SHA256
.Result();
906 // ReleaseWriter::Finish - Output the checksums /*{{{*/
907 // ---------------------------------------------------------------------
908 void ReleaseWriter::Finish()
910 fprintf(Output
, "MD5Sum:\n");
911 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
912 I
!= CheckSums
.end();
915 fprintf(Output
, " %s %16ld %s\n",
916 (*I
).second
.MD5
.c_str(),
921 fprintf(Output
, "SHA1:\n");
922 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
923 I
!= CheckSums
.end();
926 fprintf(Output
, " %s %16ld %s\n",
927 (*I
).second
.SHA1
.c_str(),
932 fprintf(Output
, "SHA256:\n");
933 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
934 I
!= CheckSums
.end();
937 fprintf(Output
, " %s %16ld %s\n",
938 (*I
).second
.SHA256
.c_str(),