]>
git.saurik.com Git - apt.git/blob - ftparchive/writer.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: writer.cc,v 1.14 2004/03/24 01:40:43 mdz Exp $
4 /* ######################################################################
8 The file writer classes. These write various types of output, sources,
11 ##################################################################### */
13 // Include Files /*{{{*/
17 #include <apt-pkg/strutl.h>
18 #include <apt-pkg/error.h>
19 #include <apt-pkg/configuration.h>
20 #include <apt-pkg/md5.h>
21 #include <apt-pkg/sha1.h>
22 #include <apt-pkg/sha256.h>
23 #include <apt-pkg/deblistparser.h>
25 #include <sys/types.h>
34 #include "apt-ftparchive.h"
35 #include "multicompress.h"
38 FTWScanner
*FTWScanner::Owner
;
40 // SetTFRewriteData - Helper for setting rewrite lists /*{{{*/
41 // ---------------------------------------------------------------------
43 inline void SetTFRewriteData(struct TFRewriteData
&tfrd
,
46 const char *newtag
= 0)
49 tfrd
.Rewrite
= rewrite
;
54 // FTWScanner::FTWScanner - Constructor /*{{{*/
55 // ---------------------------------------------------------------------
57 FTWScanner::FTWScanner()
60 NoLinkAct
= !_config
->FindB("APT::FTPArchive::DeLinkAct",true);
62 long PMax
= pathconf(".",_PC_PATH_MAX
);
64 RealPath
= new char[PMax
];
67 // FTWScanner::Scanner - FTW Scanner /*{{{*/
68 // ---------------------------------------------------------------------
69 /* This is the FTW scanner, it processes each directory element in the
71 int FTWScanner::ScannerFTW(const char *File
,const struct stat
*sb
,int Flag
)
76 ioprintf(c1out
, _("W: Unable to read directory %s\n"), File
);
81 ioprintf(c1out
, _("W: Unable to stat %s\n"), File
);
86 return ScannerFile(File
, true);
89 // FTWScanner::ScannerFile - File Scanner /*{{{*/
90 // ---------------------------------------------------------------------
92 int FTWScanner::ScannerFile(const char *File
, bool ReadLink
)
94 const char *LastComponent
= strrchr(File
, '/');
95 if (LastComponent
== NULL
)
100 vector
<string
>::iterator I
;
101 for(I
= Owner
->Patterns
.begin(); I
!= Owner
->Patterns
.end(); ++I
)
103 if (fnmatch((*I
).c_str(), LastComponent
, 0) == 0)
106 if (I
== Owner
->Patterns
.end())
109 /* Process it. If the file is a link then resolve it into an absolute
110 name.. This works best if the directory components the scanner are
111 given are not links themselves. */
113 Owner
->OriginalPath
= File
;
114 if (ReadLink
&& Owner
->RealPath
!= 0 &&
115 readlink(File
,Jnk
,sizeof(Jnk
)) != -1 &&
116 realpath(File
,Owner
->RealPath
) != 0)
117 Owner
->DoPackage(Owner
->RealPath
);
119 Owner
->DoPackage(File
);
121 if (_error
->empty() == false)
123 // Print any errors or warnings found
125 bool SeenPath
= false;
126 while (_error
->empty() == false)
130 bool Type
= _error
->PopMessage(Err
);
132 cerr
<< _("E: ") << Err
<< endl
;
134 cerr
<< _("W: ") << Err
<< endl
;
136 if (Err
.find(File
) != string::npos
)
140 if (SeenPath
== false)
141 cerr
<< _("E: Errors apply to file ") << "'" << File
<< "'" << endl
;
148 // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
149 // ---------------------------------------------------------------------
151 bool FTWScanner::RecursiveScan(string Dir
)
153 /* If noprefix is set then jam the scan root in, so we don't generate
154 link followed paths out of control */
155 if (InternalPrefix
.empty() == true)
157 if (realpath(Dir
.c_str(),RealPath
) == 0)
158 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
159 InternalPrefix
= RealPath
;
162 // Do recursive directory searching
164 int Res
= ftw(Dir
.c_str(),ScannerFTW
,30);
166 // Error treewalking?
169 if (_error
->PendingError() == false)
170 _error
->Errno("ftw",_("Tree walking failed"));
177 // FTWScanner::LoadFileList - Load the file list from a file /*{{{*/
178 // ---------------------------------------------------------------------
179 /* This is an alternative to using FTW to locate files, it reads the list
180 of files from another file. */
181 bool FTWScanner::LoadFileList(string Dir
,string File
)
183 /* If noprefix is set then jam the scan root in, so we don't generate
184 link followed paths out of control */
185 if (InternalPrefix
.empty() == true)
187 if (realpath(Dir
.c_str(),RealPath
) == 0)
188 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
189 InternalPrefix
= RealPath
;
193 FILE *List
= fopen(File
.c_str(),"r");
195 return _error
->Errno("fopen",_("Failed to open %s"),File
.c_str());
197 /* We are a tad tricky here.. We prefix the buffer with the directory
198 name, that way if we need a full path with just use line.. Sneaky and
202 if (Dir
.empty() == true || Dir
.end()[-1] != '/')
203 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s/",Dir
.c_str());
205 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s",Dir
.c_str());
206 while (fgets(FileStart
,sizeof(Line
) - (FileStart
- Line
),List
) != 0)
208 char *FileName
= _strstrip(FileStart
);
209 if (FileName
[0] == 0)
212 if (FileName
[0] != '/')
214 if (FileName
!= FileStart
)
215 memmove(FileStart
,FileName
,strlen(FileStart
));
222 if (stat(FileName
,&St
) != 0)
226 if (ScannerFile(FileName
, false) != 0)
234 // FTWScanner::Delink - Delink symlinks /*{{{*/
235 // ---------------------------------------------------------------------
237 bool FTWScanner::Delink(string
&FileName
,const char *OriginalPath
,
238 unsigned long &DeLinkBytes
,
241 // See if this isn't an internaly prefix'd file name.
242 if (InternalPrefix
.empty() == false &&
243 InternalPrefix
.length() < FileName
.length() &&
244 stringcmp(FileName
.begin(),FileName
.begin() + InternalPrefix
.length(),
245 InternalPrefix
.begin(),InternalPrefix
.end()) != 0)
247 if (DeLinkLimit
!= 0 && DeLinkBytes
/1024 < DeLinkLimit
)
249 // Tidy up the display
250 if (DeLinkBytes
== 0)
254 ioprintf(c1out
, _(" DeLink %s [%s]\n"), (OriginalPath
+ InternalPrefix
.length()),
255 SizeToStr(FileSize
).c_str());
258 if (NoLinkAct
== false)
261 if (readlink(OriginalPath
,OldLink
,sizeof(OldLink
)) == -1)
262 _error
->Errno("readlink",_("Failed to readlink %s"),OriginalPath
);
265 if (unlink(OriginalPath
) != 0)
266 _error
->Errno("unlink",_("Failed to unlink %s"),OriginalPath
);
269 if (link(FileName
.c_str(),OriginalPath
) != 0)
271 // Panic! Restore the symlink
272 symlink(OldLink
,OriginalPath
);
273 return _error
->Errno("link",_("*** Failed to link %s to %s"),
281 DeLinkBytes
+= FileSize
;
282 if (DeLinkBytes
/1024 >= DeLinkLimit
)
283 ioprintf(c1out
, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes
).c_str());
286 FileName
= OriginalPath
;
293 // PackagesWriter::PackagesWriter - Constructor /*{{{*/
294 // ---------------------------------------------------------------------
296 PackagesWriter::PackagesWriter(string DB
,string Overrides
,string ExtOverrides
,
298 Db(DB
),Stats(Db
.Stats
), Arch(aArch
)
301 SetExts(".deb .udeb .foo .bar .baz");
305 // Process the command line options
306 DoMD5
= _config
->FindB("APT::FTPArchive::MD5",true);
307 DoSHA1
= _config
->FindB("APT::FTPArchive::SHA1",true);
308 DoSHA256
= _config
->FindB("APT::FTPArchive::SHA256",true);
309 DoContents
= _config
->FindB("APT::FTPArchive::Contents",true);
310 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
311 LongDescription
= _config
->FindB("APT::FTPArchive::LongDescription",true);
313 if (Db
.Loaded() == false)
316 // Read the override file
317 if (Overrides
.empty() == false && Over
.ReadOverride(Overrides
) == false)
322 if (ExtOverrides
.empty() == false)
323 Over
.ReadExtraOverride(ExtOverrides
);
325 _error
->DumpErrors();
328 // FTWScanner::SetExts - Set extensions to support /*{{{*/
329 // ---------------------------------------------------------------------
331 bool FTWScanner::SetExts(string Vals
)
334 string::size_type Start
= 0;
335 while (Start
<= Vals
.length()-1)
337 string::size_type Space
= Vals
.find(' ',Start
);
338 string::size_type Length
;
339 if (Space
== string::npos
)
341 Length
= Vals
.length()-Start
;
345 Length
= Space
-Start
;
347 AddPattern(string("*") + Vals
.substr(Start
, Length
));
355 // PackagesWriter::DoPackage - Process a single package /*{{{*/
356 // ---------------------------------------------------------------------
357 /* This method takes a package and gets its control information and
358 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
359 rewritten and the path/size/hash appended. */
360 bool PackagesWriter::DoPackage(string FileName
)
362 // Pull all the data we need form the DB
363 if (Db
.GetFileInfo(FileName
, true, DoContents
, true, DoMD5
, DoSHA1
, DoSHA256
)
369 off_t FileSize
= Db
.GetFileSize();
370 if (Delink(FileName
,OriginalPath
,Stats
.DeLinkBytes
,FileSize
) == false)
373 // Lookup the overide information
374 pkgTagSection
&Tags
= Db
.Control
.Section
;
375 string Package
= Tags
.FindS("Package");
377 // if we generate a Packages file for a given arch, we use it to
378 // look for overrides. if we run in "simple" mode without the
379 // "Architecures" variable in the config we use the architecure value
384 Architecture
= Tags
.FindS("Architecture");
385 auto_ptr
<Override::Item
> OverItem(Over
.GetItem(Package
,Architecture
));
387 if (Package
.empty() == true)
388 return _error
->Error(_("Archive had no package field"));
390 // If we need to do any rewriting of the header do it now..
391 if (OverItem
.get() == 0)
393 if (NoOverride
== false)
396 ioprintf(c1out
, _(" %s has no override entry\n"), Package
.c_str());
399 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
400 OverItem
->FieldOverride
["Section"] = Tags
.FindS("Section");
401 OverItem
->Priority
= Tags
.FindS("Priority");
405 sprintf(Size
,"%lu", (unsigned long) FileSize
);
407 // Strip the DirStrip prefix from the FileName and add the PathPrefix
409 if (DirStrip
.empty() == false &&
410 FileName
.length() > DirStrip
.length() &&
411 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
412 DirStrip
.begin(),DirStrip
.end()) == 0)
413 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
415 NewFileName
= FileName
;
416 if (PathPrefix
.empty() == false)
417 NewFileName
= flCombine(PathPrefix
,NewFileName
);
419 /* Configuration says we don't want to include the long Description
420 in the package file - instead we want to ship a separated file */
422 if (LongDescription
== false) {
423 desc
= Tags
.FindS("Description").append("\n");
424 OverItem
->FieldOverride
["Description"] = desc
.substr(0, desc
.find('\n')).c_str();
427 // This lists all the changes to the fields we are going to make.
428 // (7 hardcoded + maintainer + suggests + end marker)
429 TFRewriteData Changes
[6+2+OverItem
->FieldOverride
.size()+1+1];
431 unsigned int End
= 0;
432 SetTFRewriteData(Changes
[End
++], "Size", Size
);
433 SetTFRewriteData(Changes
[End
++], "MD5sum", Db
.MD5Res
.c_str());
434 SetTFRewriteData(Changes
[End
++], "SHA1", Db
.SHA1Res
.c_str());
435 SetTFRewriteData(Changes
[End
++], "SHA256", Db
.SHA256Res
.c_str());
436 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
437 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
438 SetTFRewriteData(Changes
[End
++], "Status", 0);
439 SetTFRewriteData(Changes
[End
++], "Optional", 0);
441 string DescriptionMd5
;
442 if (LongDescription
== false) {
443 MD5Summation descmd5
;
444 descmd5
.Add(desc
.c_str());
445 DescriptionMd5
= descmd5
.Result().Value();
446 SetTFRewriteData(Changes
[End
++], "Description-md5", DescriptionMd5
.c_str());
449 // Rewrite the maintainer field if necessary
451 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
452 if (MaintFailed
== true)
454 if (NoOverride
== false)
457 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
458 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
462 if (NewMaint
.empty() == false)
463 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
465 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
466 dpkg-scanpackages does.. Well sort of. dpkg-scanpackages just does renaming
467 but dpkg does this append bit. So we do the append bit, at least that way the
468 status file and package file will remain similar. There are other transforms
469 but optional is the only legacy one still in use for some lazy reason. */
470 string OptionalStr
= Tags
.FindS("Optional");
471 if (OptionalStr
.empty() == false)
473 if (Tags
.FindS("Suggests").empty() == false)
474 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
475 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
478 for (map
<string
,string
>::iterator I
= OverItem
->FieldOverride
.begin();
479 I
!= OverItem
->FieldOverride
.end(); I
++)
480 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
482 SetTFRewriteData(Changes
[End
++], 0, 0);
484 // Rewrite and store the fields.
485 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
487 fprintf(Output
,"\n");
493 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
494 // ---------------------------------------------------------------------
496 SourcesWriter::SourcesWriter(string BOverrides
,string SOverrides
,
505 // Process the command line options
506 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
508 // Read the override file
509 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
514 // WTF?? The logic above: if we can't read binary overrides, don't even try
515 // reading source overrides. if we can read binary overrides, then say there
516 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
518 if (ExtOverrides
.empty() == false)
519 SOver
.ReadExtraOverride(ExtOverrides
);
521 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
522 SOver
.ReadOverride(SOverrides
,true);
525 // SourcesWriter::DoPackage - Process a single package /*{{{*/
526 // ---------------------------------------------------------------------
528 bool SourcesWriter::DoPackage(string FileName
)
531 FileFd
F(FileName
,FileFd::ReadOnly
);
532 if (_error
->PendingError() == true)
535 // Stat the file for later
537 if (fstat(F
.Fd(),&St
) != 0)
538 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
540 if (St
.st_size
> 128*1024)
541 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
543 if (BufSize
< (unsigned)St
.st_size
+1)
545 BufSize
= St
.st_size
+1;
546 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
549 if (F
.Read(Buffer
,St
.st_size
) == false)
553 char *Start
= Buffer
;
554 char *BlkEnd
= Buffer
+ St
.st_size
;
556 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
558 // Add an extra \n to the end, just in case
561 /* Remove the PGP trailer. Some .dsc's have this without a blank line
563 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
564 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
566 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
573 /* Read records until we locate the Source record. This neatly skips the
574 GPG header (which is RFC822 formed) without any trouble. */
579 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
580 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
581 if (Tags
.Find("Source",Pos
) == true)
583 Start
+= Tags
.size();
588 // Lookup the overide information, finding first the best priority.
590 string Bins
= Tags
.FindS("Binary");
591 char Buffer
[Bins
.length() + 1];
592 auto_ptr
<Override::Item
> OverItem(0);
593 if (Bins
.empty() == false)
595 strcpy(Buffer
,Bins
.c_str());
597 // Ignore too-long errors.
599 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
601 // Look at all the binaries
602 unsigned char BestPrioV
= pkgCache::State::Extra
;
603 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
605 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
609 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
610 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
612 BestPrioV
= NewPrioV
;
613 BestPrio
= Itm
->Priority
;
616 if (OverItem
.get() == 0)
621 // If we need to do any rewriting of the header do it now..
622 if (OverItem
.get() == 0)
624 if (NoOverride
== false)
627 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
630 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
633 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
634 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
635 if (SOverItem
.get() == 0)
637 ioprintf(c1out
, _(" %s has no source override entry\n"), Tags
.FindS("Source").c_str());
638 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
639 if (SOverItem
.get() == 0)
641 ioprintf(c1out
, _(" %s has no binary override entry either\n"), Tags
.FindS("Source").c_str());
642 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
643 *SOverItem
= *OverItem
;
647 // Add the dsc to the files hash list
649 snprintf(Files
,sizeof(Files
),"\n %s %lu %s\n %s",
650 string(MD5
.Result()).c_str(),St
.st_size
,
651 flNotDir(FileName
).c_str(),
652 Tags
.FindS("Files").c_str());
654 // Strip the DirStrip prefix from the FileName and add the PathPrefix
656 if (DirStrip
.empty() == false &&
657 FileName
.length() > DirStrip
.length() &&
658 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
659 NewFileName
= string(OriginalPath
+ DirStrip
.length());
661 NewFileName
= OriginalPath
;
662 if (PathPrefix
.empty() == false)
663 NewFileName
= flCombine(PathPrefix
,NewFileName
);
665 string Directory
= flNotFile(OriginalPath
);
666 string Package
= Tags
.FindS("Source");
668 // Perform the delinking operation over all of the files
670 const char *C
= Files
;
671 for (;isspace(*C
); C
++);
674 // Parse each of the elements
675 if (ParseQuoteWord(C
,ParseJnk
) == false ||
676 ParseQuoteWord(C
,ParseJnk
) == false ||
677 ParseQuoteWord(C
,ParseJnk
) == false)
678 return _error
->Error("Error parsing file record");
681 string OriginalPath
= Directory
+ ParseJnk
;
682 if (RealPath
!= 0 && readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
683 realpath(OriginalPath
.c_str(),RealPath
) != 0)
685 string RP
= RealPath
;
686 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
691 Directory
= flNotFile(NewFileName
);
692 if (Directory
.length() > 2)
693 Directory
.erase(Directory
.end()-1);
695 // This lists all the changes to the fields we are going to make.
696 // (5 hardcoded + maintainer + end marker)
697 TFRewriteData Changes
[5+1+SOverItem
->FieldOverride
.size()+1];
699 unsigned int End
= 0;
700 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
701 SetTFRewriteData(Changes
[End
++],"Files",Files
);
702 if (Directory
!= "./")
703 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
704 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
705 SetTFRewriteData(Changes
[End
++],"Status",0);
707 // Rewrite the maintainer field if necessary
709 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
710 if (MaintFailed
== true)
712 if (NoOverride
== false)
715 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
716 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
719 if (NewMaint
.empty() == false)
720 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
722 for (map
<string
,string
>::iterator I
= SOverItem
->FieldOverride
.begin();
723 I
!= SOverItem
->FieldOverride
.end(); I
++)
724 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
726 SetTFRewriteData(Changes
[End
++], 0, 0);
728 // Rewrite and store the fields.
729 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
731 fprintf(Output
,"\n");
739 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
740 // ---------------------------------------------------------------------
742 ContentsWriter::ContentsWriter(string DB
) :
743 Db(DB
), Stats(Db
.Stats
)
750 // ContentsWriter::DoPackage - Process a single package /*{{{*/
751 // ---------------------------------------------------------------------
752 /* If Package is the empty string the control record will be parsed to
753 determine what the package name is. */
754 bool ContentsWriter::DoPackage(string FileName
,string Package
)
756 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false))
761 // Parse the package name
762 if (Package
.empty() == true)
764 Package
= Db
.Control
.Section
.FindS("Package");
767 Db
.Contents
.Add(Gen
,Package
);
772 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
773 // ---------------------------------------------------------------------
775 bool ContentsWriter::ReadFromPkgs(string PkgFile
,string PkgCompress
)
777 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
778 if (_error
->PendingError() == true)
781 // Open the package file
784 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
788 FileFd
Fd(CompFd
,false);
789 pkgTagFile
Tags(&Fd
);
790 if (_error
->PendingError() == true)
792 Pkgs
.CloseOld(CompFd
,Proc
);
797 pkgTagSection Section
;
798 while (Tags
.Step(Section
) == true)
800 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
801 string Package
= Section
.FindS("Section");
802 if (Package
.empty() == false && Package
.end()[-1] != '/')
805 Package
+= Section
.FindS("Package");
808 Package
+= Section
.FindS("Package");
810 DoPackage(File
,Package
);
811 if (_error
->empty() == false)
813 _error
->Error("Errors apply to file '%s'",File
.c_str());
814 _error
->DumpErrors();
818 // Tidy the compressor
819 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
827 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
828 // ---------------------------------------------------------------------
830 ReleaseWriter::ReleaseWriter(string DB
)
832 AddPattern("Packages");
833 AddPattern("Packages.gz");
834 AddPattern("Packages.bz2");
835 AddPattern("Packages.lzma");
836 AddPattern("Sources");
837 AddPattern("Sources.gz");
838 AddPattern("Sources.bz2");
839 AddPattern("Sources.lzma");
840 AddPattern("Release");
841 AddPattern("md5sum.txt");
844 time_t now
= time(NULL
);
846 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
852 map
<string
,string
> Fields
;
853 Fields
["Origin"] = "";
854 Fields
["Label"] = "";
855 Fields
["Suite"] = "";
856 Fields
["Version"] = "";
857 Fields
["Codename"] = "";
858 Fields
["Date"] = datestr
;
859 Fields
["Architectures"] = "";
860 Fields
["Components"] = "";
861 Fields
["Description"] = "";
863 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
867 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
868 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
872 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
876 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
877 // ---------------------------------------------------------------------
878 bool ReleaseWriter::DoPackage(string FileName
)
880 // Strip the DirStrip prefix from the FileName and add the PathPrefix
882 if (DirStrip
.empty() == false &&
883 FileName
.length() > DirStrip
.length() &&
884 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
885 DirStrip
.begin(),DirStrip
.end()) == 0)
887 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
888 while (NewFileName
[0] == '/')
889 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
892 NewFileName
= FileName
;
894 if (PathPrefix
.empty() == false)
895 NewFileName
= flCombine(PathPrefix
,NewFileName
);
897 FileFd
fd(FileName
, FileFd::ReadOnly
);
904 CheckSums
[NewFileName
].size
= fd
.Size();
907 MD5
.AddFD(fd
.Fd(), fd
.Size());
908 CheckSums
[NewFileName
].MD5
= MD5
.Result();
912 SHA1
.AddFD(fd
.Fd(), fd
.Size());
913 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
916 SHA256Summation SHA256
;
917 SHA256
.AddFD(fd
.Fd(), fd
.Size());
918 CheckSums
[NewFileName
].SHA256
= SHA256
.Result();
926 // ReleaseWriter::Finish - Output the checksums /*{{{*/
927 // ---------------------------------------------------------------------
928 void ReleaseWriter::Finish()
930 fprintf(Output
, "MD5Sum:\n");
931 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
932 I
!= CheckSums
.end();
935 fprintf(Output
, " %s %16ld %s\n",
936 (*I
).second
.MD5
.c_str(),
941 fprintf(Output
, "SHA1:\n");
942 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
943 I
!= CheckSums
.end();
946 fprintf(Output
, " %s %16ld %s\n",
947 (*I
).second
.SHA1
.c_str(),
952 fprintf(Output
, "SHA256:\n");
953 for(map
<string
,struct CheckSum
>::iterator I
= CheckSums
.begin();
954 I
!= CheckSums
.end();
957 fprintf(Output
, " %s %16ld %s\n",
958 (*I
).second
.SHA256
.c_str(),