]>
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/deblistparser.h>
28 #include <sys/types.h>
36 #include "apt-ftparchive.h"
37 #include "multicompress.h"
40 FTWScanner
*FTWScanner::Owner
;
42 // SetTFRewriteData - Helper for setting rewrite lists /*{{{*/
43 // ---------------------------------------------------------------------
45 inline void SetTFRewriteData(struct TFRewriteData
&tfrd
,
48 const char *newtag
= 0)
51 tfrd
.Rewrite
= rewrite
;
56 // FTWScanner::FTWScanner - Constructor /*{{{*/
57 // ---------------------------------------------------------------------
59 FTWScanner::FTWScanner()
62 NoLinkAct
= !_config
->FindB("APT::FTPArchive::DeLinkAct",true);
64 long PMax
= pathconf(".",_PC_PATH_MAX
);
66 RealPath
= new char[PMax
];
69 // FTWScanner::Scanner - FTW Scanner /*{{{*/
70 // ---------------------------------------------------------------------
71 /* This is the FTW scanner, it processes each directory element in the
73 int FTWScanner::Scanner(const char *File
,const struct stat
*sb
,int Flag
)
78 ioprintf(c1out
, _("W: Unable to read directory %s\n"), File
);
83 ioprintf(c1out
, _("W: Unable to stat %s\n"), File
);
88 const char *LastComponent
= strrchr(File
, '/');
89 if (LastComponent
== NULL
)
94 vector
<string
>::iterator I
;
95 for(I
= Owner
->Patterns
.begin(); I
!= Owner
->Patterns
.end(); ++I
)
97 if (fnmatch((*I
).c_str(), LastComponent
, 0) == 0)
100 if (I
== Owner
->Patterns
.end())
103 /* Process it. If the file is a link then resolve it into an absolute
104 name.. This works best if the directory components the scanner are
105 given are not links themselves. */
107 Owner
->OriginalPath
= File
;
108 if (Owner
->RealPath
!= 0 && readlink(File
,Jnk
,sizeof(Jnk
)) != -1 &&
109 realpath(File
,Owner
->RealPath
) != 0)
110 Owner
->DoPackage(Owner
->RealPath
);
112 Owner
->DoPackage(File
);
114 if (_error
->empty() == false)
116 // Print any errors or warnings found
118 bool SeenPath
= false;
119 while (_error
->empty() == false)
123 bool Type
= _error
->PopMessage(Err
);
125 cerr
<< _("E: ") << Err
<< endl
;
127 cerr
<< _("W: ") << Err
<< endl
;
129 if (Err
.find(File
) != string::npos
)
133 if (SeenPath
== false)
134 cerr
<< _("E: Errors apply to file ") << "'" << File
<< "'" << endl
;
141 // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
142 // ---------------------------------------------------------------------
144 bool FTWScanner::RecursiveScan(string Dir
)
146 /* If noprefix is set then jam the scan root in, so we don't generate
147 link followed paths out of control */
148 if (InternalPrefix
.empty() == true)
150 if (realpath(Dir
.c_str(),RealPath
) == 0)
151 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
152 InternalPrefix
= RealPath
;
155 // Do recursive directory searching
157 int Res
= ftw(Dir
.c_str(),Scanner
,30);
159 // Error treewalking?
162 if (_error
->PendingError() == false)
163 _error
->Errno("ftw",_("Tree walking failed"));
170 // FTWScanner::LoadFileList - Load the file list from a file /*{{{*/
171 // ---------------------------------------------------------------------
172 /* This is an alternative to using FTW to locate files, it reads the list
173 of files from another file. */
174 bool FTWScanner::LoadFileList(string Dir
,string File
)
176 /* If noprefix is set then jam the scan root in, so we don't generate
177 link followed paths out of control */
178 if (InternalPrefix
.empty() == true)
180 if (realpath(Dir
.c_str(),RealPath
) == 0)
181 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
182 InternalPrefix
= RealPath
;
186 FILE *List
= fopen(File
.c_str(),"r");
188 return _error
->Errno("fopen",_("Failed to open %s"),File
.c_str());
190 /* We are a tad tricky here.. We prefix the buffer with the directory
191 name, that way if we need a full path with just use line.. Sneaky and
195 if (Dir
.empty() == true || Dir
.end()[-1] != '/')
196 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s/",Dir
.c_str());
198 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s",Dir
.c_str());
199 while (fgets(FileStart
,sizeof(Line
) - (FileStart
- Line
),List
) != 0)
201 char *FileName
= _strstrip(FileStart
);
202 if (FileName
[0] == 0)
205 if (FileName
[0] != '/')
207 if (FileName
!= FileStart
)
208 memmove(FileStart
,FileName
,strlen(FileStart
));
214 if (stat(FileName
,&St
) != 0)
217 if (Scanner(FileName
,&St
,Flag
) != 0)
225 // FTWScanner::Delink - Delink symlinks /*{{{*/
226 // ---------------------------------------------------------------------
228 bool FTWScanner::Delink(string
&FileName
,const char *OriginalPath
,
229 unsigned long &DeLinkBytes
,
232 // See if this isn't an internaly prefix'd file name.
233 if (InternalPrefix
.empty() == false &&
234 InternalPrefix
.length() < FileName
.length() &&
235 stringcmp(FileName
.begin(),FileName
.begin() + InternalPrefix
.length(),
236 InternalPrefix
.begin(),InternalPrefix
.end()) != 0)
238 if (DeLinkLimit
!= 0 && DeLinkBytes
/1024 < DeLinkLimit
)
240 // Tidy up the display
241 if (DeLinkBytes
== 0)
245 ioprintf(c1out
, _(" DeLink %s [%s]\n"), (OriginalPath
+ InternalPrefix
.length()),
246 SizeToStr(St
.st_size
).c_str());
249 if (NoLinkAct
== false)
252 if (readlink(OriginalPath
,OldLink
,sizeof(OldLink
)) == -1)
253 _error
->Errno("readlink",_("Failed to readlink %s"),OriginalPath
);
256 if (unlink(OriginalPath
) != 0)
257 _error
->Errno("unlink",_("Failed to unlink %s"),OriginalPath
);
260 if (link(FileName
.c_str(),OriginalPath
) != 0)
262 // Panic! Restore the symlink
263 symlink(OldLink
,OriginalPath
);
264 return _error
->Errno("link",_("*** Failed to link %s to %s"),
272 DeLinkBytes
+= St
.st_size
;
273 if (DeLinkBytes
/1024 >= DeLinkLimit
)
274 ioprintf(c1out
, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes
).c_str());
277 FileName
= OriginalPath
;
284 // PackagesWriter::PackagesWriter - Constructor /*{{{*/
285 // ---------------------------------------------------------------------
287 PackagesWriter::PackagesWriter(string DB
,string Overrides
,string ExtOverrides
,
289 Db(DB
),Stats(Db
.Stats
), Arch(aArch
)
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 // 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",St
.st_size
);
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", MD5Res
.c_str());
424 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
425 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
426 SetTFRewriteData(Changes
[End
++], "Status", 0);
427 SetTFRewriteData(Changes
[End
++], "Optional", 0);
429 // Rewrite the maintainer field if necessary
431 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
432 if (MaintFailed
== true)
434 if (NoOverride
== false)
437 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
438 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
442 if (NewMaint
.empty() == false)
443 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
445 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
446 dpkg-scanpackages does.. Well sort of. dpkg-scanpackages just does renaming
447 but dpkg does this append bit. So we do the append bit, at least that way the
448 status file and package file will remain similar. There are other transforms
449 but optional is the only legacy one still in use for some lazy reason. */
450 string OptionalStr
= Tags
.FindS("Optional");
451 if (OptionalStr
.empty() == false)
453 if (Tags
.FindS("Suggests").empty() == false)
454 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
455 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
458 for (map
<string
,string
>::iterator I
= OverItem
->FieldOverride
.begin();
459 I
!= OverItem
->FieldOverride
.end(); I
++)
460 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
462 SetTFRewriteData(Changes
[End
++], 0, 0);
464 // Rewrite and store the fields.
465 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
467 fprintf(Output
,"\n");
473 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
474 // ---------------------------------------------------------------------
476 SourcesWriter::SourcesWriter(string BOverrides
,string SOverrides
,
485 // Process the command line options
486 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
488 // Read the override file
489 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
494 if (ExtOverrides
.empty() == false)
495 SOver
.ReadExtraOverride(ExtOverrides
);
497 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
498 SOver
.ReadOverride(SOverrides
,true);
501 // SourcesWriter::DoPackage - Process a single package /*{{{*/
502 // ---------------------------------------------------------------------
504 bool SourcesWriter::DoPackage(string FileName
)
507 FileFd
F(FileName
,FileFd::ReadOnly
);
508 if (_error
->PendingError() == true)
511 // Stat the file for later
513 if (fstat(F
.Fd(),&St
) != 0)
514 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
516 if (St
.st_size
> 128*1024)
517 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
519 if (BufSize
< (unsigned)St
.st_size
+1)
521 BufSize
= St
.st_size
+1;
522 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
525 if (F
.Read(Buffer
,St
.st_size
) == false)
529 char *Start
= Buffer
;
530 char *BlkEnd
= Buffer
+ St
.st_size
;
532 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
534 // Add an extra \n to the end, just in case
537 /* Remove the PGP trailer. Some .dsc's have this without a blank line
539 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
540 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
542 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
549 /* Read records until we locate the Source record. This neatly skips the
550 GPG header (which is RFC822 formed) without any trouble. */
555 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
556 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
557 if (Tags
.Find("Source",Pos
) == true)
559 Start
+= Tags
.size();
564 // Lookup the overide information, finding first the best priority.
566 string Bins
= Tags
.FindS("Binary");
567 char Buffer
[Bins
.length() + 1];
568 auto_ptr
<Override::Item
> OverItem(0);
569 if (Bins
.empty() == false)
571 strcpy(Buffer
,Bins
.c_str());
573 // Ignore too-long errors.
575 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
577 // Look at all the binaries
578 unsigned char BestPrioV
= pkgCache::State::Extra
;
579 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
581 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
585 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
586 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
588 BestPrioV
= NewPrioV
;
589 BestPrio
= Itm
->Priority
;
592 if (OverItem
.get() == 0)
597 // If we need to do any rewriting of the header do it now..
598 if (OverItem
.get() == 0)
600 if (NoOverride
== false)
603 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
606 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
609 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
610 const auto_ptr
<Override::Item
> autoSOverItem(SOverItem
);
611 if (SOverItem
.get() == 0)
613 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
614 if (SOverItem
.get() == 0)
616 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
617 *SOverItem
= *OverItem
;
621 // Add the dsc to the files hash list
623 snprintf(Files
,sizeof(Files
),"\n %s %lu %s\n %s",
624 string(MD5
.Result()).c_str(),St
.st_size
,
625 flNotDir(FileName
).c_str(),
626 Tags
.FindS("Files").c_str());
628 // Strip the DirStrip prefix from the FileName and add the PathPrefix
630 if (DirStrip
.empty() == false &&
631 FileName
.length() > DirStrip
.length() &&
632 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
633 NewFileName
= string(OriginalPath
+ DirStrip
.length());
635 NewFileName
= OriginalPath
;
636 if (PathPrefix
.empty() == false)
637 NewFileName
= flCombine(PathPrefix
,NewFileName
);
639 string Directory
= flNotFile(OriginalPath
);
640 string Package
= Tags
.FindS("Source");
642 // Perform the delinking operation over all of the files
644 const char *C
= Files
;
645 for (;isspace(*C
); C
++);
648 // Parse each of the elements
649 if (ParseQuoteWord(C
,ParseJnk
) == false ||
650 ParseQuoteWord(C
,ParseJnk
) == false ||
651 ParseQuoteWord(C
,ParseJnk
) == false)
652 return _error
->Error("Error parsing file record");
655 string OriginalPath
= Directory
+ ParseJnk
;
656 if (RealPath
!= 0 && readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
657 realpath(OriginalPath
.c_str(),RealPath
) != 0)
659 string RP
= RealPath
;
660 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
) == false)
665 Directory
= flNotFile(NewFileName
);
666 if (Directory
.length() > 2)
667 Directory
.erase(Directory
.end()-1);
669 // This lists all the changes to the fields we are going to make.
670 // (5 hardcoded + maintainer + end marker)
671 TFRewriteData Changes
[5+1+SOverItem
->FieldOverride
.size()+1];
673 unsigned int End
= 0;
674 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
675 SetTFRewriteData(Changes
[End
++],"Files",Files
);
676 if (Directory
!= "./")
677 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
678 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
679 SetTFRewriteData(Changes
[End
++],"Status",0);
681 // Rewrite the maintainer field if necessary
683 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
684 if (MaintFailed
== true)
686 if (NoOverride
== false)
689 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
690 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
693 if (NewMaint
.empty() == false)
694 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
696 for (map
<string
,string
>::iterator I
= SOverItem
->FieldOverride
.begin();
697 I
!= SOverItem
->FieldOverride
.end(); I
++)
698 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
700 SetTFRewriteData(Changes
[End
++], 0, 0);
702 // Rewrite and store the fields.
703 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
705 fprintf(Output
,"\n");
713 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
714 // ---------------------------------------------------------------------
716 ContentsWriter::ContentsWriter(string DB
) :
717 Db(DB
), Stats(Db
.Stats
)
724 // ContentsWriter::DoPackage - Process a single package /*{{{*/
725 // ---------------------------------------------------------------------
726 /* If Package is the empty string the control record will be parsed to
727 determine what the package name is. */
728 bool ContentsWriter::DoPackage(string FileName
,string Package
)
731 FileFd
F(FileName
,FileFd::ReadOnly
);
732 if (_error
->PendingError() == true)
735 // Stat the file for later
737 if (fstat(F
.Fd(),&St
) != 0)
738 return _error
->Errno("fstat","Failed too stat %s",FileName
.c_str());
741 if (Db
.SetFile(FileName
,St
,&F
) == false ||
742 Db
.LoadContents(false) == false)
745 // Parse the package name
746 if (Package
.empty() == true)
748 if (Db
.LoadControl() == false)
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();
905 // ReleaseWriter::Finish - Output the checksums /*{{{*/
906 // ---------------------------------------------------------------------
907 void ReleaseWriter::Finish()
909 fprintf(Output
, "MD5Sum:\n");
910 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
911 I
!= CheckSums
.end();
914 fprintf(Output
, " %s %16ld %s\n",
915 (*I
).second
.MD5
.c_str(),
920 fprintf(Output
, "SHA1:\n");
921 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
922 I
!= CheckSums
.end();
925 fprintf(Output
, " %s %16ld %s\n",
926 (*I
).second
.SHA1
.c_str(),