]>
git.saurik.com Git - apt.git/blob - ftparchive/writer.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: writer.cc,v 1.13 2004/01/04 00:20:59 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/deblistparser.h>
28 #include <sys/types.h>
36 #include "apt-ftparchive.h"
37 #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::Scanner(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 const char *LastComponent
= strrchr(File
, '/');
90 if (LastComponent
== NULL
)
95 vector
<string
>::iterator I
;
96 for(I
= Owner
->Patterns
.begin(); I
!= Owner
->Patterns
.end(); ++I
)
98 if (fnmatch((*I
).c_str(), LastComponent
, 0) == 0)
101 if (I
== Owner
->Patterns
.end())
104 /* Process it. If the file is a link then resolve it into an absolute
105 name.. This works best if the directory components the scanner are
106 given are not links themselves. */
108 Owner
->OriginalPath
= File
;
109 if (Owner
->RealPath
!= 0 && readlink(File
,Jnk
,sizeof(Jnk
)) != -1 &&
110 realpath(File
,Owner
->RealPath
) != 0)
111 Owner
->DoPackage(Owner
->RealPath
);
113 Owner
->DoPackage(File
);
115 if (_error
->empty() == false)
117 // Print any errors or warnings found
119 bool SeenPath
= false;
120 while (_error
->empty() == false)
124 bool Type
= _error
->PopMessage(Err
);
126 cerr
<< _("E: ") << Err
<< endl
;
128 cerr
<< _("W: ") << Err
<< endl
;
130 if (Err
.find(File
) != string::npos
)
134 if (SeenPath
== false)
135 cerr
<< _("E: Errors apply to file ") << "'" << File
<< "'" << endl
;
142 // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
143 // ---------------------------------------------------------------------
145 bool FTWScanner::RecursiveScan(string Dir
)
147 /* If noprefix is set then jam the scan root in, so we don't generate
148 link followed paths out of control */
149 if (InternalPrefix
.empty() == true)
151 if (realpath(Dir
.c_str(),RealPath
) == 0)
152 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
153 InternalPrefix
= RealPath
;
156 // Do recursive directory searching
158 int Res
= ftw(Dir
.c_str(),Scanner
,30);
160 // Error treewalking?
163 if (_error
->PendingError() == false)
164 _error
->Errno("ftw",_("Tree walking failed"));
171 // FTWScanner::LoadFileList - Load the file list from a file /*{{{*/
172 // ---------------------------------------------------------------------
173 /* This is an alternative to using FTW to locate files, it reads the list
174 of files from another file. */
175 bool FTWScanner::LoadFileList(string Dir
,string File
)
177 /* If noprefix is set then jam the scan root in, so we don't generate
178 link followed paths out of control */
179 if (InternalPrefix
.empty() == true)
181 if (realpath(Dir
.c_str(),RealPath
) == 0)
182 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
183 InternalPrefix
= RealPath
;
187 FILE *List
= fopen(File
.c_str(),"r");
189 return _error
->Errno("fopen",_("Failed to open %s"),File
.c_str());
191 /* We are a tad tricky here.. We prefix the buffer with the directory
192 name, that way if we need a full path with just use line.. Sneaky and
196 if (Dir
.empty() == true || Dir
.end()[-1] != '/')
197 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s/",Dir
.c_str());
199 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s",Dir
.c_str());
200 while (fgets(FileStart
,sizeof(Line
) - (FileStart
- Line
),List
) != 0)
202 char *FileName
= _strstrip(FileStart
);
203 if (FileName
[0] == 0)
206 if (FileName
[0] != '/')
208 if (FileName
!= FileStart
)
209 memmove(FileStart
,FileName
,strlen(FileStart
));
215 if (stat(FileName
,&St
) != 0)
218 if (Scanner(FileName
,&St
,Flag
) != 0)
226 // FTWScanner::Delink - Delink symlinks /*{{{*/
227 // ---------------------------------------------------------------------
229 bool FTWScanner::Delink(string
&FileName
,const char *OriginalPath
,
230 unsigned long &DeLinkBytes
,
233 // See if this isn't an internaly prefix'd file name.
234 if (InternalPrefix
.empty() == false &&
235 InternalPrefix
.length() < FileName
.length() &&
236 stringcmp(FileName
.begin(),FileName
.begin() + InternalPrefix
.length(),
237 InternalPrefix
.begin(),InternalPrefix
.end()) != 0)
239 if (DeLinkLimit
!= 0 && DeLinkBytes
/1024 < DeLinkLimit
)
241 // Tidy up the display
242 if (DeLinkBytes
== 0)
246 ioprintf(c1out
, _(" DeLink %s [%s]\n"), (OriginalPath
+ InternalPrefix
.length()),
247 SizeToStr(St
.st_size
).c_str());
250 if (NoLinkAct
== false)
253 if (readlink(OriginalPath
,OldLink
,sizeof(OldLink
)) == -1)
254 _error
->Errno("readlink",_("Failed to readlink %s"),OriginalPath
);
257 if (unlink(OriginalPath
) != 0)
258 _error
->Errno("unlink",_("Failed to unlink %s"),OriginalPath
);
261 if (link(FileName
.c_str(),OriginalPath
) != 0)
263 // Panic! Restore the symlink
264 symlink(OldLink
,OriginalPath
);
265 return _error
->Errno("link",_("*** Failed to link %s to %s"),
273 DeLinkBytes
+= St
.st_size
;
274 if (DeLinkBytes
/1024 >= DeLinkLimit
)
275 ioprintf(c1out
, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes
).c_str());
278 FileName
= OriginalPath
;
285 // PackagesWriter::PackagesWriter - Constructor /*{{{*/
286 // ---------------------------------------------------------------------
288 PackagesWriter::PackagesWriter(string DB
,string Overrides
,string ExtOverrides
) :
289 Db(DB
),Stats(Db
.Stats
)
292 SetExts(".deb .udeb .foo .bar .baz");
296 // Process the command line options
297 DoMD5
= _config
->FindB("APT::FTPArchive::MD5",true);
298 DoContents
= _config
->FindB("APT::FTPArchive::Contents",true);
299 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
301 if (Db
.Loaded() == false)
304 // Read the override file
305 if (Overrides
.empty() == false && Over
.ReadOverride(Overrides
) == false)
310 if (ExtOverrides
.empty() == false)
311 Over
.ReadExtraOverride(ExtOverrides
);
313 _error
->DumpErrors();
316 // FTWScanner::SetExts - Set extensions to support /*{{{*/
317 // ---------------------------------------------------------------------
319 bool FTWScanner::SetExts(string Vals
)
322 string::size_type Start
= 0;
323 while (Start
<= Vals
.length()-1)
325 string::size_type Space
= Vals
.find(' ',Start
);
326 string::size_type Length
;
327 if (Space
== string::npos
)
329 Length
= Vals
.length()-Start
;
333 Length
= Space
-Start
;
335 AddPattern(string("*") + Vals
.substr(Start
, Length
));
343 // PackagesWriter::DoPackage - Process a single package /*{{{*/
344 // ---------------------------------------------------------------------
345 /* This method takes a package and gets its control information and
346 MD5 then writes out a control record with the proper fields rewritten
347 and the path/size/hash appended. */
348 bool PackagesWriter::DoPackage(string FileName
)
351 FileFd
F(FileName
,FileFd::ReadOnly
);
352 if (_error
->PendingError() == true)
355 // Stat the file for later
357 if (fstat(F
.Fd(),&St
) != 0)
358 return _error
->Errno("fstat",_("Failed to stat %s"),FileName
.c_str());
360 // Pull all the data we need form the DB
362 if (Db
.SetFile(FileName
,St
,&F
) == false ||
363 Db
.LoadControl() == false ||
364 (DoContents
== true && Db
.LoadContents(true) == false) ||
365 (DoMD5
== true && Db
.GetMD5(MD5Res
,false) == false))
368 if (Delink(FileName
,OriginalPath
,Stats
.DeLinkBytes
,St
) == false)
371 // Lookup the overide information
372 pkgTagSection
&Tags
= Db
.Control
.Section
;
373 string Package
= Tags
.FindS("Package");
375 Override::Item
*OverItem
= Over
.GetItem(Package
);
377 if (Package
.empty() == true)
378 return _error
->Error(_("Archive had no package field"));
380 // If we need to do any rewriting of the header do it now..
383 if (NoOverride
== false)
386 ioprintf(c1out
, _(" %s has no override entry\n"), Package
.c_str());
390 Tmp
.FieldOverride
["Section"] = Tags
.FindS("Section");
391 Tmp
.Priority
= Tags
.FindS("Priority");
395 sprintf(Size
,"%lu",St
.st_size
);
397 // Strip the DirStrip prefix from the FileName and add the PathPrefix
399 if (DirStrip
.empty() == false &&
400 FileName
.length() > DirStrip
.length() &&
401 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
402 DirStrip
.begin(),DirStrip
.end()) == 0)
403 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
405 NewFileName
= FileName
;
406 if (PathPrefix
.empty() == false)
407 NewFileName
= flCombine(PathPrefix
,NewFileName
);
409 // This lists all the changes to the fields we are going to make.
410 // (7 hardcoded + maintainer + suggests + end marker)
411 TFRewriteData Changes
[6+2+OverItem
->FieldOverride
.size()+1];
413 unsigned int End
= 0;
414 SetTFRewriteData(Changes
[End
++], "Size", Size
);
415 SetTFRewriteData(Changes
[End
++], "MD5sum", MD5Res
.c_str());
416 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
417 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
418 SetTFRewriteData(Changes
[End
++], "Status", 0);
419 SetTFRewriteData(Changes
[End
++], "Optional", 0);
421 // Rewrite the maintainer field if necessary
423 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
424 if (MaintFailed
== true)
426 if (NoOverride
== false)
429 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
430 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
434 if (NewMaint
.empty() == false)
435 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
437 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
438 dpkg-scanpackages does.. Well sort of. dpkg-scanpackages just does renaming
439 but dpkg does this append bit. So we do the append bit, at least that way the
440 status file and package file will remain similar. There are other transforms
441 but optional is the only legacy one still in use for some lazy reason. */
442 string OptionalStr
= Tags
.FindS("Optional");
443 if (OptionalStr
.empty() == false)
445 if (Tags
.FindS("Suggests").empty() == false)
446 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
447 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
450 for (map
<string
,string
>::iterator I
= OverItem
->FieldOverride
.begin();
451 I
!= OverItem
->FieldOverride
.end(); I
++)
452 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
454 SetTFRewriteData(Changes
[End
++], 0, 0);
456 // Rewrite and store the fields.
457 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
459 fprintf(Output
,"\n");
465 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
466 // ---------------------------------------------------------------------
468 SourcesWriter::SourcesWriter(string BOverrides
,string SOverrides
,
477 // Process the command line options
478 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
480 // Read the override file
481 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
486 if (ExtOverrides
.empty() == false)
487 SOver
.ReadExtraOverride(ExtOverrides
);
489 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
490 SOver
.ReadOverride(SOverrides
,true);
493 // SourcesWriter::DoPackage - Process a single package /*{{{*/
494 // ---------------------------------------------------------------------
496 bool SourcesWriter::DoPackage(string FileName
)
499 FileFd
F(FileName
,FileFd::ReadOnly
);
500 if (_error
->PendingError() == true)
503 // Stat the file for later
505 if (fstat(F
.Fd(),&St
) != 0)
506 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
508 if (St
.st_size
> 128*1024)
509 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
511 if (BufSize
< (unsigned)St
.st_size
+1)
513 BufSize
= St
.st_size
+1;
514 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
517 if (F
.Read(Buffer
,St
.st_size
) == false)
521 char *Start
= Buffer
;
522 char *BlkEnd
= Buffer
+ St
.st_size
;
524 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
526 // Add an extra \n to the end, just in case
529 /* Remove the PGP trailer. Some .dsc's have this without a blank line
531 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
532 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
534 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
541 /* Read records until we locate the Source record. This neatly skips the
542 GPG header (which is RFC822 formed) without any trouble. */
547 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
548 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
549 if (Tags
.Find("Source",Pos
) == true)
551 Start
+= Tags
.size();
556 // Lookup the overide information, finding first the best priority.
559 string Bins
= Tags
.FindS("Binary");
560 Override::Item
*OverItem
= 0;
561 if (Bins
.empty() == false && Bins
.length() < sizeof(Buffer
))
563 strcpy(Buffer
,Bins
.c_str());
565 // Ignore too-long errors.
567 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
569 // Look at all the binaries
570 unsigned char BestPrioV
= pkgCache::State::Extra
;
571 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
573 Override::Item
*Itm
= BOver
.GetItem(BinList
[I
]);
579 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
580 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
582 BestPrioV
= NewPrioV
;
583 BestPrio
= Itm
->Priority
;
588 // If we need to do any rewriting of the header do it now..
592 if (NoOverride
== false)
595 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
601 Override::Item
*SOverItem
= SOver
.GetItem(Tags
.FindS("Source"));
604 SOverItem
= BOver
.GetItem(Tags
.FindS("Source"));
606 SOverItem
= OverItem
;
609 // Add the dsc to the files hash list
611 snprintf(Files
,sizeof(Files
),"\n %s %lu %s\n %s",
612 string(MD5
.Result()).c_str(),St
.st_size
,
613 flNotDir(FileName
).c_str(),
614 Tags
.FindS("Files").c_str());
616 // Strip the DirStrip prefix from the FileName and add the PathPrefix
618 if (DirStrip
.empty() == false &&
619 FileName
.length() > DirStrip
.length() &&
620 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
621 NewFileName
= string(OriginalPath
+ DirStrip
.length());
623 NewFileName
= OriginalPath
;
624 if (PathPrefix
.empty() == false)
625 NewFileName
= flCombine(PathPrefix
,NewFileName
);
627 string Directory
= flNotFile(OriginalPath
);
628 string Package
= Tags
.FindS("Source");
630 // Perform the delinking operation over all of the files
632 const char *C
= Files
;
633 for (;isspace(*C
); C
++);
636 // Parse each of the elements
637 if (ParseQuoteWord(C
,ParseJnk
) == false ||
638 ParseQuoteWord(C
,ParseJnk
) == false ||
639 ParseQuoteWord(C
,ParseJnk
) == false)
640 return _error
->Error("Error parsing file record");
643 string OriginalPath
= Directory
+ ParseJnk
;
644 if (RealPath
!= 0 && readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
645 realpath(OriginalPath
.c_str(),RealPath
) != 0)
647 string RP
= RealPath
;
648 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
) == false)
653 Directory
= flNotFile(NewFileName
);
654 if (Directory
.length() > 2)
655 Directory
.erase(Directory
.end()-1);
657 // This lists all the changes to the fields we are going to make.
658 // (5 hardcoded + maintainer + end marker)
659 TFRewriteData Changes
[5+1+SOverItem
->FieldOverride
.size()+1];
661 unsigned int End
= 0;
662 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
663 SetTFRewriteData(Changes
[End
++],"Files",Files
);
664 if (Directory
!= "./")
665 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
666 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
667 SetTFRewriteData(Changes
[End
++],"Status",0);
669 // Rewrite the maintainer field if necessary
671 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
672 if (MaintFailed
== true)
674 if (NoOverride
== false)
677 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
678 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
681 if (NewMaint
.empty() == false)
682 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
684 for (map
<string
,string
>::iterator I
= SOverItem
->FieldOverride
.begin();
685 I
!= SOverItem
->FieldOverride
.end(); I
++)
686 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
688 SetTFRewriteData(Changes
[End
++], 0, 0);
690 // Rewrite and store the fields.
691 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
693 fprintf(Output
,"\n");
701 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
702 // ---------------------------------------------------------------------
704 ContentsWriter::ContentsWriter(string DB
) :
705 Db(DB
), Stats(Db
.Stats
)
712 // ContentsWriter::DoPackage - Process a single package /*{{{*/
713 // ---------------------------------------------------------------------
714 /* If Package is the empty string the control record will be parsed to
715 determine what the package name is. */
716 bool ContentsWriter::DoPackage(string FileName
,string Package
)
719 FileFd
F(FileName
,FileFd::ReadOnly
);
720 if (_error
->PendingError() == true)
723 // Stat the file for later
725 if (fstat(F
.Fd(),&St
) != 0)
726 return _error
->Errno("fstat","Failed too stat %s",FileName
.c_str());
729 if (Db
.SetFile(FileName
,St
,&F
) == false ||
730 Db
.LoadContents(false) == false)
733 // Parse the package name
734 if (Package
.empty() == true)
736 if (Db
.LoadControl() == false)
738 Package
= Db
.Control
.Section
.FindS("Package");
741 Db
.Contents
.Add(Gen
,Package
);
746 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
747 // ---------------------------------------------------------------------
749 bool ContentsWriter::ReadFromPkgs(string PkgFile
,string PkgCompress
)
751 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
752 if (_error
->PendingError() == true)
755 // Open the package file
758 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
762 FileFd
Fd(CompFd
,false);
763 pkgTagFile
Tags(&Fd
);
764 if (_error
->PendingError() == true)
766 Pkgs
.CloseOld(CompFd
,Proc
);
771 pkgTagSection Section
;
772 while (Tags
.Step(Section
) == true)
774 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
775 string Package
= Section
.FindS("Section");
776 if (Package
.empty() == false && Package
.end()[-1] != '/')
779 Package
+= Section
.FindS("Package");
782 Package
+= Section
.FindS("Package");
784 DoPackage(File
,Package
);
785 if (_error
->empty() == false)
787 _error
->Error("Errors apply to file '%s'",File
.c_str());
788 _error
->DumpErrors();
792 // Tidy the compressor
793 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
801 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
802 // ---------------------------------------------------------------------
804 ReleaseWriter::ReleaseWriter(string DB
)
806 AddPattern("Packages");
807 AddPattern("Packages.gz");
808 AddPattern("Packages.bz2");
809 AddPattern("Sources");
810 AddPattern("Sources.gz");
811 AddPattern("Sources.bz2");
812 AddPattern("Release");
813 AddPattern("md5sum.txt");
816 time_t now
= time(NULL
);
818 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
824 map
<string
,string
> Fields
;
825 Fields
["Origin"] = "";
826 Fields
["Label"] = "";
827 Fields
["Suite"] = "";
828 Fields
["Version"] = "";
829 Fields
["Codename"] = "";
830 Fields
["Date"] = datestr
;
831 Fields
["Architectures"] = "";
832 Fields
["Components"] = "";
833 Fields
["Description"] = "";
835 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
839 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
840 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
844 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
848 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
849 // ---------------------------------------------------------------------
850 bool ReleaseWriter::DoPackage(string FileName
)
852 // Strip the DirStrip prefix from the FileName and add the PathPrefix
854 if (DirStrip
.empty() == false &&
855 FileName
.length() > DirStrip
.length() &&
856 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
857 DirStrip
.begin(),DirStrip
.end()) == 0)
859 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
860 while (NewFileName
[0] == '/')
861 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
864 NewFileName
= FileName
;
866 if (PathPrefix
.empty() == false)
867 NewFileName
= flCombine(PathPrefix
,NewFileName
);
869 FileFd
fd(FileName
, FileFd::ReadOnly
);
876 CheckSums
[NewFileName
].size
= fd
.Size();
879 MD5
.AddFD(fd
.Fd(), fd
.Size());
880 CheckSums
[NewFileName
].MD5
= MD5
.Result();
884 SHA1
.AddFD(fd
.Fd(), fd
.Size());
885 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
893 // ReleaseWriter::Finish - Output the checksums /*{{{*/
894 // ---------------------------------------------------------------------
895 void ReleaseWriter::Finish()
897 fprintf(Output
, "MD5Sum:\n");
898 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
899 I
!= CheckSums
.end();
902 fprintf(Output
, " %s %16ld %s\n",
903 (*I
).second
.MD5
.c_str(),
908 fprintf(Output
, "SHA1:\n");
909 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
910 I
!= CheckSums
.end();
913 fprintf(Output
, " %s %16ld %s\n",
914 (*I
).second
.SHA1
.c_str(),