]>
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
]));
584 if (OverItem
.get() == 0)
587 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
588 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
590 BestPrioV
= NewPrioV
;
591 BestPrio
= Itm
->Priority
;
596 // If we need to do any rewriting of the header do it now..
597 if (OverItem
.get() == 0)
599 if (NoOverride
== false)
602 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
605 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
608 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
609 const auto_ptr
<Override::Item
> autoSOverItem(SOverItem
);
610 if (SOverItem
.get() == 0)
612 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
613 if (SOverItem
.get() == 0)
615 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
616 *SOverItem
= *OverItem
;
620 // Add the dsc to the files hash list
622 snprintf(Files
,sizeof(Files
),"\n %s %lu %s\n %s",
623 string(MD5
.Result()).c_str(),St
.st_size
,
624 flNotDir(FileName
).c_str(),
625 Tags
.FindS("Files").c_str());
627 // Strip the DirStrip prefix from the FileName and add the PathPrefix
629 if (DirStrip
.empty() == false &&
630 FileName
.length() > DirStrip
.length() &&
631 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
632 NewFileName
= string(OriginalPath
+ DirStrip
.length());
634 NewFileName
= OriginalPath
;
635 if (PathPrefix
.empty() == false)
636 NewFileName
= flCombine(PathPrefix
,NewFileName
);
638 string Directory
= flNotFile(OriginalPath
);
639 string Package
= Tags
.FindS("Source");
641 // Perform the delinking operation over all of the files
643 const char *C
= Files
;
644 for (;isspace(*C
); C
++);
647 // Parse each of the elements
648 if (ParseQuoteWord(C
,ParseJnk
) == false ||
649 ParseQuoteWord(C
,ParseJnk
) == false ||
650 ParseQuoteWord(C
,ParseJnk
) == false)
651 return _error
->Error("Error parsing file record");
654 string OriginalPath
= Directory
+ ParseJnk
;
655 if (RealPath
!= 0 && readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
656 realpath(OriginalPath
.c_str(),RealPath
) != 0)
658 string RP
= RealPath
;
659 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
) == false)
664 Directory
= flNotFile(NewFileName
);
665 if (Directory
.length() > 2)
666 Directory
.erase(Directory
.end()-1);
668 // This lists all the changes to the fields we are going to make.
669 // (5 hardcoded + maintainer + end marker)
670 TFRewriteData Changes
[5+1+SOverItem
->FieldOverride
.size()+1];
672 unsigned int End
= 0;
673 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
674 SetTFRewriteData(Changes
[End
++],"Files",Files
);
675 if (Directory
!= "./")
676 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
677 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
678 SetTFRewriteData(Changes
[End
++],"Status",0);
680 // Rewrite the maintainer field if necessary
682 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
683 if (MaintFailed
== true)
685 if (NoOverride
== false)
688 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
689 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
692 if (NewMaint
.empty() == false)
693 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
695 for (map
<string
,string
>::iterator I
= SOverItem
->FieldOverride
.begin();
696 I
!= SOverItem
->FieldOverride
.end(); I
++)
697 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
699 SetTFRewriteData(Changes
[End
++], 0, 0);
701 // Rewrite and store the fields.
702 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
704 fprintf(Output
,"\n");
712 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
713 // ---------------------------------------------------------------------
715 ContentsWriter::ContentsWriter(string DB
) :
716 Db(DB
), Stats(Db
.Stats
)
723 // ContentsWriter::DoPackage - Process a single package /*{{{*/
724 // ---------------------------------------------------------------------
725 /* If Package is the empty string the control record will be parsed to
726 determine what the package name is. */
727 bool ContentsWriter::DoPackage(string FileName
,string Package
)
730 FileFd
F(FileName
,FileFd::ReadOnly
);
731 if (_error
->PendingError() == true)
734 // Stat the file for later
736 if (fstat(F
.Fd(),&St
) != 0)
737 return _error
->Errno("fstat","Failed too stat %s",FileName
.c_str());
740 if (Db
.SetFile(FileName
,St
,&F
) == false ||
741 Db
.LoadContents(false) == false)
744 // Parse the package name
745 if (Package
.empty() == true)
747 if (Db
.LoadControl() == false)
749 Package
= Db
.Control
.Section
.FindS("Package");
752 Db
.Contents
.Add(Gen
,Package
);
757 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
758 // ---------------------------------------------------------------------
760 bool ContentsWriter::ReadFromPkgs(string PkgFile
,string PkgCompress
)
762 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
763 if (_error
->PendingError() == true)
766 // Open the package file
769 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
773 FileFd
Fd(CompFd
,false);
774 pkgTagFile
Tags(&Fd
);
775 if (_error
->PendingError() == true)
777 Pkgs
.CloseOld(CompFd
,Proc
);
782 pkgTagSection Section
;
783 while (Tags
.Step(Section
) == true)
785 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
786 string Package
= Section
.FindS("Section");
787 if (Package
.empty() == false && Package
.end()[-1] != '/')
790 Package
+= Section
.FindS("Package");
793 Package
+= Section
.FindS("Package");
795 DoPackage(File
,Package
);
796 if (_error
->empty() == false)
798 _error
->Error("Errors apply to file '%s'",File
.c_str());
799 _error
->DumpErrors();
803 // Tidy the compressor
804 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
812 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
813 // ---------------------------------------------------------------------
815 ReleaseWriter::ReleaseWriter(string DB
)
817 AddPattern("Packages");
818 AddPattern("Packages.gz");
819 AddPattern("Packages.bz2");
820 AddPattern("Sources");
821 AddPattern("Sources.gz");
822 AddPattern("Sources.bz2");
823 AddPattern("Release");
824 AddPattern("md5sum.txt");
827 time_t now
= time(NULL
);
829 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
835 map
<string
,string
> Fields
;
836 Fields
["Origin"] = "";
837 Fields
["Label"] = "";
838 Fields
["Suite"] = "";
839 Fields
["Version"] = "";
840 Fields
["Codename"] = "";
841 Fields
["Date"] = datestr
;
842 Fields
["Architectures"] = "";
843 Fields
["Components"] = "";
844 Fields
["Description"] = "";
846 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
850 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
851 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
855 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
859 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
860 // ---------------------------------------------------------------------
861 bool ReleaseWriter::DoPackage(string FileName
)
863 // Strip the DirStrip prefix from the FileName and add the PathPrefix
865 if (DirStrip
.empty() == false &&
866 FileName
.length() > DirStrip
.length() &&
867 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
868 DirStrip
.begin(),DirStrip
.end()) == 0)
870 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
871 while (NewFileName
[0] == '/')
872 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
875 NewFileName
= FileName
;
877 if (PathPrefix
.empty() == false)
878 NewFileName
= flCombine(PathPrefix
,NewFileName
);
880 FileFd
fd(FileName
, FileFd::ReadOnly
);
887 CheckSums
[NewFileName
].size
= fd
.Size();
890 MD5
.AddFD(fd
.Fd(), fd
.Size());
891 CheckSums
[NewFileName
].MD5
= MD5
.Result();
895 SHA1
.AddFD(fd
.Fd(), fd
.Size());
896 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
904 // ReleaseWriter::Finish - Output the checksums /*{{{*/
905 // ---------------------------------------------------------------------
906 void ReleaseWriter::Finish()
908 fprintf(Output
, "MD5Sum:\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
.MD5
.c_str(),
919 fprintf(Output
, "SHA1:\n");
920 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
921 I
!= CheckSums
.end();
924 fprintf(Output
, " %s %16ld %s\n",
925 (*I
).second
.SHA1
.c_str(),