]>
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 const &ReadLink
)
94 const char *LastComponent
= strrchr(File
, '/');
95 if (LastComponent
== NULL
)
100 vector
<string
>::const_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 const 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
const &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 const 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
const &Dir
, string
const &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
,
239 off_t
const &FileSize
)
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
const &DB
,string
const &Overrides
,string
const &ExtOverrides
,
297 string
const &aArch
) :
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 DoAlwaysStat
= _config
->FindB("APT::FTPArchive::AlwaysStat", false);
310 DoContents
= _config
->FindB("APT::FTPArchive::Contents",true);
311 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
312 LongDescription
= _config
->FindB("APT::FTPArchive::LongDescription",true);
314 if (Db
.Loaded() == false)
317 // Read the override file
318 if (Overrides
.empty() == false && Over
.ReadOverride(Overrides
) == false)
323 if (ExtOverrides
.empty() == false)
324 Over
.ReadExtraOverride(ExtOverrides
);
326 _error
->DumpErrors();
329 // FTWScanner::SetExts - Set extensions to support /*{{{*/
330 // ---------------------------------------------------------------------
332 bool FTWScanner::SetExts(string
const &Vals
)
335 string::size_type Start
= 0;
336 while (Start
<= Vals
.length()-1)
338 string::size_type Space
= Vals
.find(' ',Start
);
339 string::size_type Length
;
340 if (Space
== string::npos
)
342 Length
= Vals
.length()-Start
;
346 Length
= Space
-Start
;
348 AddPattern(string("*") + Vals
.substr(Start
, Length
));
356 // PackagesWriter::DoPackage - Process a single package /*{{{*/
357 // ---------------------------------------------------------------------
358 /* This method takes a package and gets its control information and
359 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
360 rewritten and the path/size/hash appended. */
361 bool PackagesWriter::DoPackage(string FileName
)
363 // Pull all the data we need form the DB
364 if (Db
.GetFileInfo(FileName
, true, DoContents
, true, DoMD5
, DoSHA1
, DoSHA256
, DoAlwaysStat
)
370 off_t FileSize
= Db
.GetFileSize();
371 if (Delink(FileName
,OriginalPath
,Stats
.DeLinkBytes
,FileSize
) == false)
374 // Lookup the overide information
375 pkgTagSection
&Tags
= Db
.Control
.Section
;
376 string Package
= Tags
.FindS("Package");
378 // if we generate a Packages file for a given arch, we use it to
379 // look for overrides. if we run in "simple" mode without the
380 // "Architecures" variable in the config we use the architecure value
385 Architecture
= Tags
.FindS("Architecture");
386 auto_ptr
<Override::Item
> OverItem(Over
.GetItem(Package
,Architecture
));
388 if (Package
.empty() == true)
389 return _error
->Error(_("Archive had no package field"));
391 // If we need to do any rewriting of the header do it now..
392 if (OverItem
.get() == 0)
394 if (NoOverride
== false)
397 ioprintf(c1out
, _(" %s has no override entry\n"), Package
.c_str());
400 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
401 OverItem
->FieldOverride
["Section"] = Tags
.FindS("Section");
402 OverItem
->Priority
= Tags
.FindS("Priority");
406 sprintf(Size
,"%lu", (unsigned long) FileSize
);
408 // Strip the DirStrip prefix from the FileName and add the PathPrefix
410 if (DirStrip
.empty() == false &&
411 FileName
.length() > DirStrip
.length() &&
412 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
413 DirStrip
.begin(),DirStrip
.end()) == 0)
414 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
416 NewFileName
= FileName
;
417 if (PathPrefix
.empty() == false)
418 NewFileName
= flCombine(PathPrefix
,NewFileName
);
420 /* Configuration says we don't want to include the long Description
421 in the package file - instead we want to ship a separated file */
423 if (LongDescription
== false) {
424 desc
= Tags
.FindS("Description").append("\n");
425 OverItem
->FieldOverride
["Description"] = desc
.substr(0, desc
.find('\n')).c_str();
428 // This lists all the changes to the fields we are going to make.
429 // (7 hardcoded + maintainer + suggests + end marker)
430 TFRewriteData Changes
[6+2+OverItem
->FieldOverride
.size()+1+1];
432 unsigned int End
= 0;
433 SetTFRewriteData(Changes
[End
++], "Size", Size
);
434 SetTFRewriteData(Changes
[End
++], "MD5sum", Db
.MD5Res
.c_str());
435 SetTFRewriteData(Changes
[End
++], "SHA1", Db
.SHA1Res
.c_str());
436 SetTFRewriteData(Changes
[End
++], "SHA256", Db
.SHA256Res
.c_str());
437 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
438 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
439 SetTFRewriteData(Changes
[End
++], "Status", 0);
440 SetTFRewriteData(Changes
[End
++], "Optional", 0);
442 string DescriptionMd5
;
443 if (LongDescription
== false) {
444 MD5Summation descmd5
;
445 descmd5
.Add(desc
.c_str());
446 DescriptionMd5
= descmd5
.Result().Value();
447 SetTFRewriteData(Changes
[End
++], "Description-md5", DescriptionMd5
.c_str());
450 // Rewrite the maintainer field if necessary
452 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
453 if (MaintFailed
== true)
455 if (NoOverride
== false)
458 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
459 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
463 if (NewMaint
.empty() == false)
464 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
466 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
467 dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
468 but dpkg does this append bit. So we do the append bit, at least that way the
469 status file and package file will remain similar. There are other transforms
470 but optional is the only legacy one still in use for some lazy reason. */
471 string OptionalStr
= Tags
.FindS("Optional");
472 if (OptionalStr
.empty() == false)
474 if (Tags
.FindS("Suggests").empty() == false)
475 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
476 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
479 for (map
<string
,string
>::const_iterator I
= OverItem
->FieldOverride
.begin();
480 I
!= OverItem
->FieldOverride
.end(); I
++)
481 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
483 SetTFRewriteData(Changes
[End
++], 0, 0);
485 // Rewrite and store the fields.
486 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
488 fprintf(Output
,"\n");
494 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
495 // ---------------------------------------------------------------------
497 SourcesWriter::SourcesWriter(string
const &BOverrides
,string
const &SOverrides
,
498 string
const &ExtOverrides
)
506 // Process the command line options
507 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
509 // Read the override file
510 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
515 // WTF?? The logic above: if we can't read binary overrides, don't even try
516 // reading source overrides. if we can read binary overrides, then say there
517 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
519 if (ExtOverrides
.empty() == false)
520 SOver
.ReadExtraOverride(ExtOverrides
);
522 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
523 SOver
.ReadOverride(SOverrides
,true);
526 // SourcesWriter::DoPackage - Process a single package /*{{{*/
527 // ---------------------------------------------------------------------
529 bool SourcesWriter::DoPackage(string FileName
)
532 FileFd
F(FileName
,FileFd::ReadOnly
);
533 if (_error
->PendingError() == true)
536 // Stat the file for later
538 if (fstat(F
.Fd(),&St
) != 0)
539 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
541 if (St
.st_size
> 128*1024)
542 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
544 if (BufSize
< (unsigned)St
.st_size
+1)
546 BufSize
= St
.st_size
+1;
547 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
550 if (F
.Read(Buffer
,St
.st_size
) == false)
554 char *Start
= Buffer
;
555 char *BlkEnd
= Buffer
+ St
.st_size
;
557 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
559 // Add an extra \n to the end, just in case
562 /* Remove the PGP trailer. Some .dsc's have this without a blank line
564 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
565 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
567 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
574 /* Read records until we locate the Source record. This neatly skips the
575 GPG header (which is RFC822 formed) without any trouble. */
580 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
581 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
582 if (Tags
.Find("Source",Pos
) == true)
584 Start
+= Tags
.size();
589 // Lookup the overide information, finding first the best priority.
591 string Bins
= Tags
.FindS("Binary");
592 char Buffer
[Bins
.length() + 1];
593 auto_ptr
<Override::Item
> OverItem(0);
594 if (Bins
.empty() == false)
596 strcpy(Buffer
,Bins
.c_str());
598 // Ignore too-long errors.
600 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
602 // Look at all the binaries
603 unsigned char BestPrioV
= pkgCache::State::Extra
;
604 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
606 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
610 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
611 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
613 BestPrioV
= NewPrioV
;
614 BestPrio
= Itm
->Priority
;
617 if (OverItem
.get() == 0)
622 // If we need to do any rewriting of the header do it now..
623 if (OverItem
.get() == 0)
625 if (NoOverride
== false)
628 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
631 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
634 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
635 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
636 if (SOverItem
.get() == 0)
638 ioprintf(c1out
, _(" %s has no source override entry\n"), Tags
.FindS("Source").c_str());
639 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
640 if (SOverItem
.get() == 0)
642 ioprintf(c1out
, _(" %s has no binary override entry either\n"), Tags
.FindS("Source").c_str());
643 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
644 *SOverItem
= *OverItem
;
648 // Add the dsc to the files hash list
650 snprintf(Files
,sizeof(Files
),"\n %s %lu %s\n %s",
651 string(MD5
.Result()).c_str(),St
.st_size
,
652 flNotDir(FileName
).c_str(),
653 Tags
.FindS("Files").c_str());
655 // Strip the DirStrip prefix from the FileName and add the PathPrefix
657 if (DirStrip
.empty() == false &&
658 FileName
.length() > DirStrip
.length() &&
659 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
660 NewFileName
= string(OriginalPath
+ DirStrip
.length());
662 NewFileName
= OriginalPath
;
663 if (PathPrefix
.empty() == false)
664 NewFileName
= flCombine(PathPrefix
,NewFileName
);
666 string Directory
= flNotFile(OriginalPath
);
667 string Package
= Tags
.FindS("Source");
669 // Perform the delinking operation over all of the files
671 const char *C
= Files
;
672 for (;isspace(*C
); C
++);
675 // Parse each of the elements
676 if (ParseQuoteWord(C
,ParseJnk
) == false ||
677 ParseQuoteWord(C
,ParseJnk
) == false ||
678 ParseQuoteWord(C
,ParseJnk
) == false)
679 return _error
->Error("Error parsing file record");
682 string OriginalPath
= Directory
+ ParseJnk
;
683 if (RealPath
!= 0 && readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
684 realpath(OriginalPath
.c_str(),RealPath
) != 0)
686 string RP
= RealPath
;
687 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
692 Directory
= flNotFile(NewFileName
);
693 if (Directory
.length() > 2)
694 Directory
.erase(Directory
.end()-1);
696 // This lists all the changes to the fields we are going to make.
697 // (5 hardcoded + maintainer + end marker)
698 TFRewriteData Changes
[5+1+SOverItem
->FieldOverride
.size()+1];
700 unsigned int End
= 0;
701 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
702 SetTFRewriteData(Changes
[End
++],"Files",Files
);
703 if (Directory
!= "./")
704 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
705 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
706 SetTFRewriteData(Changes
[End
++],"Status",0);
708 // Rewrite the maintainer field if necessary
710 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
711 if (MaintFailed
== true)
713 if (NoOverride
== false)
716 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
717 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
720 if (NewMaint
.empty() == false)
721 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
723 for (map
<string
,string
>::const_iterator I
= SOverItem
->FieldOverride
.begin();
724 I
!= SOverItem
->FieldOverride
.end(); I
++)
725 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
727 SetTFRewriteData(Changes
[End
++], 0, 0);
729 // Rewrite and store the fields.
730 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
732 fprintf(Output
,"\n");
740 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
741 // ---------------------------------------------------------------------
743 ContentsWriter::ContentsWriter(string
const &DB
) :
744 Db(DB
), Stats(Db
.Stats
)
751 // ContentsWriter::DoPackage - Process a single package /*{{{*/
752 // ---------------------------------------------------------------------
753 /* If Package is the empty string the control record will be parsed to
754 determine what the package name is. */
755 bool ContentsWriter::DoPackage(string FileName
, string Package
)
757 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false, false))
762 // Parse the package name
763 if (Package
.empty() == true)
765 Package
= Db
.Control
.Section
.FindS("Package");
768 Db
.Contents
.Add(Gen
,Package
);
773 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
774 // ---------------------------------------------------------------------
776 bool ContentsWriter::ReadFromPkgs(string
const &PkgFile
,string
const &PkgCompress
)
778 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
779 if (_error
->PendingError() == true)
782 // Open the package file
785 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
789 FileFd
Fd(CompFd
,false);
790 pkgTagFile
Tags(&Fd
);
791 if (_error
->PendingError() == true)
793 Pkgs
.CloseOld(CompFd
,Proc
);
798 pkgTagSection Section
;
799 while (Tags
.Step(Section
) == true)
801 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
802 string Package
= Section
.FindS("Section");
803 if (Package
.empty() == false && Package
.end()[-1] != '/')
806 Package
+= Section
.FindS("Package");
809 Package
+= Section
.FindS("Package");
811 DoPackage(File
,Package
);
812 if (_error
->empty() == false)
814 _error
->Error("Errors apply to file '%s'",File
.c_str());
815 _error
->DumpErrors();
819 // Tidy the compressor
820 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
828 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
829 // ---------------------------------------------------------------------
831 ReleaseWriter::ReleaseWriter(string
const &DB
)
833 AddPattern("Packages");
834 AddPattern("Packages.gz");
835 AddPattern("Packages.bz2");
836 AddPattern("Packages.lzma");
837 AddPattern("Sources");
838 AddPattern("Sources.gz");
839 AddPattern("Sources.bz2");
840 AddPattern("Sources.lzma");
841 AddPattern("Release");
842 AddPattern("md5sum.txt");
845 time_t const now
= time(NULL
);
847 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
853 map
<string
,string
> Fields
;
854 Fields
["Origin"] = "";
855 Fields
["Label"] = "";
856 Fields
["Suite"] = "";
857 Fields
["Version"] = "";
858 Fields
["Codename"] = "";
859 Fields
["Date"] = datestr
;
860 Fields
["Architectures"] = "";
861 Fields
["Components"] = "";
862 Fields
["Description"] = "";
864 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
868 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
869 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
873 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
877 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
878 // ---------------------------------------------------------------------
879 bool ReleaseWriter::DoPackage(string FileName
)
881 // Strip the DirStrip prefix from the FileName and add the PathPrefix
883 if (DirStrip
.empty() == false &&
884 FileName
.length() > DirStrip
.length() &&
885 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
886 DirStrip
.begin(),DirStrip
.end()) == 0)
888 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
889 while (NewFileName
[0] == '/')
890 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
893 NewFileName
= FileName
;
895 if (PathPrefix
.empty() == false)
896 NewFileName
= flCombine(PathPrefix
,NewFileName
);
898 FileFd
fd(FileName
, FileFd::ReadOnly
);
905 CheckSums
[NewFileName
].size
= fd
.Size();
908 MD5
.AddFD(fd
.Fd(), fd
.Size());
909 CheckSums
[NewFileName
].MD5
= MD5
.Result();
913 SHA1
.AddFD(fd
.Fd(), fd
.Size());
914 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
917 SHA256Summation SHA256
;
918 SHA256
.AddFD(fd
.Fd(), fd
.Size());
919 CheckSums
[NewFileName
].SHA256
= SHA256
.Result();
927 // ReleaseWriter::Finish - Output the checksums /*{{{*/
928 // ---------------------------------------------------------------------
929 void ReleaseWriter::Finish()
931 fprintf(Output
, "MD5Sum:\n");
932 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
933 I
!= CheckSums
.end();
936 fprintf(Output
, " %s %16ld %s\n",
937 (*I
).second
.MD5
.c_str(),
942 fprintf(Output
, "SHA1:\n");
943 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
944 I
!= CheckSums
.end();
947 fprintf(Output
, " %s %16ld %s\n",
948 (*I
).second
.SHA1
.c_str(),
953 fprintf(Output
, "SHA256:\n");
954 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
955 I
!= CheckSums
.end();
958 fprintf(Output
, " %s %16ld %s\n",
959 (*I
).second
.SHA256
.c_str(),