]>
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(string
const &Arch
): Arch(Arch
)
60 NoLinkAct
= !_config
->FindB("APT::FTPArchive::DeLinkAct",true);
63 // FTWScanner::Scanner - FTW Scanner /*{{{*/
64 // ---------------------------------------------------------------------
65 /* This is the FTW scanner, it processes each directory element in the
67 int FTWScanner::ScannerFTW(const char *File
,const struct stat
*sb
,int Flag
)
72 ioprintf(c1out
, _("W: Unable to read directory %s\n"), File
);
77 ioprintf(c1out
, _("W: Unable to stat %s\n"), File
);
82 return ScannerFile(File
, true);
85 // FTWScanner::ScannerFile - File Scanner /*{{{*/
86 // ---------------------------------------------------------------------
88 int FTWScanner::ScannerFile(const char *File
, bool const &ReadLink
)
90 const char *LastComponent
= strrchr(File
, '/');
91 char *RealPath
= NULL
;
93 if (LastComponent
== NULL
)
98 vector
<string
>::const_iterator I
;
99 for(I
= Owner
->Patterns
.begin(); I
!= Owner
->Patterns
.end(); ++I
)
101 if (fnmatch((*I
).c_str(), LastComponent
, 0) == 0)
104 if (I
== Owner
->Patterns
.end())
107 /* Process it. If the file is a link then resolve it into an absolute
108 name.. This works best if the directory components the scanner are
109 given are not links themselves. */
111 Owner
->OriginalPath
= File
;
113 readlink(File
,Jnk
,sizeof(Jnk
)) != -1 &&
114 (RealPath
= realpath(File
,NULL
)) != 0)
116 Owner
->DoPackage(RealPath
);
120 Owner
->DoPackage(File
);
122 if (_error
->empty() == false)
124 // Print any errors or warnings found
126 bool SeenPath
= false;
127 while (_error
->empty() == false)
131 bool const Type
= _error
->PopMessage(Err
);
133 cerr
<< _("E: ") << Err
<< endl
;
135 cerr
<< _("W: ") << Err
<< endl
;
137 if (Err
.find(File
) != string::npos
)
141 if (SeenPath
== false)
142 cerr
<< _("E: Errors apply to file ") << "'" << File
<< "'" << endl
;
149 // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
150 // ---------------------------------------------------------------------
152 bool FTWScanner::RecursiveScan(string
const &Dir
)
154 char *RealPath
= NULL
;
155 /* If noprefix is set then jam the scan root in, so we don't generate
156 link followed paths out of control */
157 if (InternalPrefix
.empty() == true)
159 if ((RealPath
= realpath(Dir
.c_str(),NULL
)) == 0)
160 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
161 InternalPrefix
= RealPath
;
165 // Do recursive directory searching
167 int const Res
= ftw(Dir
.c_str(),ScannerFTW
,30);
169 // Error treewalking?
172 if (_error
->PendingError() == false)
173 _error
->Errno("ftw",_("Tree walking failed"));
180 // FTWScanner::LoadFileList - Load the file list from a file /*{{{*/
181 // ---------------------------------------------------------------------
182 /* This is an alternative to using FTW to locate files, it reads the list
183 of files from another file. */
184 bool FTWScanner::LoadFileList(string
const &Dir
, string
const &File
)
186 char *RealPath
= NULL
;
187 /* If noprefix is set then jam the scan root in, so we don't generate
188 link followed paths out of control */
189 if (InternalPrefix
.empty() == true)
191 if ((RealPath
= realpath(Dir
.c_str(),NULL
)) == 0)
192 return _error
->Errno("realpath",_("Failed to resolve %s"),Dir
.c_str());
193 InternalPrefix
= RealPath
;
198 FILE *List
= fopen(File
.c_str(),"r");
200 return _error
->Errno("fopen",_("Failed to open %s"),File
.c_str());
202 /* We are a tad tricky here.. We prefix the buffer with the directory
203 name, that way if we need a full path with just use line.. Sneaky and
207 if (Dir
.empty() == true || Dir
.end()[-1] != '/')
208 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s/",Dir
.c_str());
210 FileStart
= Line
+ snprintf(Line
,sizeof(Line
),"%s",Dir
.c_str());
211 while (fgets(FileStart
,sizeof(Line
) - (FileStart
- Line
),List
) != 0)
213 char *FileName
= _strstrip(FileStart
);
214 if (FileName
[0] == 0)
217 if (FileName
[0] != '/')
219 if (FileName
!= FileStart
)
220 memmove(FileStart
,FileName
,strlen(FileStart
));
227 if (stat(FileName
,&St
) != 0)
231 if (ScannerFile(FileName
, false) != 0)
239 // FTWScanner::Delink - Delink symlinks /*{{{*/
240 // ---------------------------------------------------------------------
242 bool FTWScanner::Delink(string
&FileName
,const char *OriginalPath
,
243 unsigned long &DeLinkBytes
,
244 off_t
const &FileSize
)
246 // See if this isn't an internaly prefix'd file name.
247 if (InternalPrefix
.empty() == false &&
248 InternalPrefix
.length() < FileName
.length() &&
249 stringcmp(FileName
.begin(),FileName
.begin() + InternalPrefix
.length(),
250 InternalPrefix
.begin(),InternalPrefix
.end()) != 0)
252 if (DeLinkLimit
!= 0 && DeLinkBytes
/1024 < DeLinkLimit
)
254 // Tidy up the display
255 if (DeLinkBytes
== 0)
259 ioprintf(c1out
, _(" DeLink %s [%s]\n"), (OriginalPath
+ InternalPrefix
.length()),
260 SizeToStr(FileSize
).c_str());
263 if (NoLinkAct
== false)
266 if (readlink(OriginalPath
,OldLink
,sizeof(OldLink
)) == -1)
267 _error
->Errno("readlink",_("Failed to readlink %s"),OriginalPath
);
270 if (unlink(OriginalPath
) != 0)
271 _error
->Errno("unlink",_("Failed to unlink %s"),OriginalPath
);
274 if (link(FileName
.c_str(),OriginalPath
) != 0)
276 // Panic! Restore the symlink
277 symlink(OldLink
,OriginalPath
);
278 return _error
->Errno("link",_("*** Failed to link %s to %s"),
286 DeLinkBytes
+= FileSize
;
287 if (DeLinkBytes
/1024 >= DeLinkLimit
)
288 ioprintf(c1out
, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes
).c_str());
291 FileName
= OriginalPath
;
298 // PackagesWriter::PackagesWriter - Constructor /*{{{*/
299 // ---------------------------------------------------------------------
301 PackagesWriter::PackagesWriter(string
const &DB
,string
const &Overrides
,string
const &ExtOverrides
,
302 string
const &Arch
) :
303 FTWScanner(Arch
), Db(DB
), Stats(Db
.Stats
), TransWriter(NULL
)
306 SetExts(".deb .udeb");
309 // Process the command line options
310 DoMD5
= _config
->FindB("APT::FTPArchive::MD5",true);
311 DoSHA1
= _config
->FindB("APT::FTPArchive::SHA1",true);
312 DoSHA256
= _config
->FindB("APT::FTPArchive::SHA256",true);
313 DoAlwaysStat
= _config
->FindB("APT::FTPArchive::AlwaysStat", false);
314 DoContents
= _config
->FindB("APT::FTPArchive::Contents",true);
315 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
316 LongDescription
= _config
->FindB("APT::FTPArchive::LongDescription",true);
318 if (Db
.Loaded() == false)
321 // Read the override file
322 if (Overrides
.empty() == false && Over
.ReadOverride(Overrides
) == false)
327 if (ExtOverrides
.empty() == false)
328 Over
.ReadExtraOverride(ExtOverrides
);
330 _error
->DumpErrors();
333 // FTWScanner::SetExts - Set extensions to support /*{{{*/
334 // ---------------------------------------------------------------------
336 bool FTWScanner::SetExts(string
const &Vals
)
339 string::size_type Start
= 0;
340 while (Start
<= Vals
.length()-1)
342 string::size_type
const Space
= Vals
.find(' ',Start
);
343 string::size_type
const Length
= ((Space
== string::npos
) ? Vals
.length() : Space
) - Start
;
344 if ( Arch
.empty() == false )
346 AddPattern(string("*_") + Arch
+ Vals
.substr(Start
, Length
));
347 AddPattern(string("*_all") + Vals
.substr(Start
, Length
));
350 AddPattern(string("*") + Vals
.substr(Start
, Length
));
359 // PackagesWriter::DoPackage - Process a single package /*{{{*/
360 // ---------------------------------------------------------------------
361 /* This method takes a package and gets its control information and
362 MD5, SHA1 and SHA256 then writes out a control record with the proper fields
363 rewritten and the path/size/hash appended. */
364 bool PackagesWriter::DoPackage(string FileName
)
366 // Pull all the data we need form the DB
367 if (Db
.GetFileInfo(FileName
, true, DoContents
, true, DoMD5
, DoSHA1
, DoSHA256
, DoAlwaysStat
)
373 off_t FileSize
= Db
.GetFileSize();
374 if (Delink(FileName
,OriginalPath
,Stats
.DeLinkBytes
,FileSize
) == false)
377 // Lookup the overide information
378 pkgTagSection
&Tags
= Db
.Control
.Section
;
379 string Package
= Tags
.FindS("Package");
381 // if we generate a Packages file for a given arch, we use it to
382 // look for overrides. if we run in "simple" mode without the
383 // "Architecures" variable in the config we use the architecure value
388 Architecture
= Tags
.FindS("Architecture");
389 auto_ptr
<Override::Item
> OverItem(Over
.GetItem(Package
,Architecture
));
391 if (Package
.empty() == true)
392 return _error
->Error(_("Archive had no package field"));
394 // If we need to do any rewriting of the header do it now..
395 if (OverItem
.get() == 0)
397 if (NoOverride
== false)
400 ioprintf(c1out
, _(" %s has no override entry\n"), Package
.c_str());
403 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
404 OverItem
->FieldOverride
["Section"] = Tags
.FindS("Section");
405 OverItem
->Priority
= Tags
.FindS("Priority");
409 sprintf(Size
,"%lu", (unsigned long) FileSize
);
411 // Strip the DirStrip prefix from the FileName and add the PathPrefix
413 if (DirStrip
.empty() == false &&
414 FileName
.length() > DirStrip
.length() &&
415 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
416 DirStrip
.begin(),DirStrip
.end()) == 0)
417 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
419 NewFileName
= FileName
;
420 if (PathPrefix
.empty() == false)
421 NewFileName
= flCombine(PathPrefix
,NewFileName
);
423 /* Configuration says we don't want to include the long Description
424 in the package file - instead we want to ship a separated file */
426 if (LongDescription
== false) {
427 desc
= Tags
.FindS("Description").append("\n");
428 OverItem
->FieldOverride
["Description"] = desc
.substr(0, desc
.find('\n')).c_str();
431 // This lists all the changes to the fields we are going to make.
432 // (7 hardcoded + maintainer + suggests + end marker)
433 TFRewriteData Changes
[6+2+OverItem
->FieldOverride
.size()+1+1];
435 unsigned int End
= 0;
436 SetTFRewriteData(Changes
[End
++], "Size", Size
);
437 SetTFRewriteData(Changes
[End
++], "MD5sum", Db
.MD5Res
.c_str());
438 SetTFRewriteData(Changes
[End
++], "SHA1", Db
.SHA1Res
.c_str());
439 SetTFRewriteData(Changes
[End
++], "SHA256", Db
.SHA256Res
.c_str());
440 SetTFRewriteData(Changes
[End
++], "Filename", NewFileName
.c_str());
441 SetTFRewriteData(Changes
[End
++], "Priority", OverItem
->Priority
.c_str());
442 SetTFRewriteData(Changes
[End
++], "Status", 0);
443 SetTFRewriteData(Changes
[End
++], "Optional", 0);
445 string DescriptionMd5
;
446 if (LongDescription
== false) {
447 MD5Summation descmd5
;
448 descmd5
.Add(desc
.c_str());
449 DescriptionMd5
= descmd5
.Result().Value();
450 SetTFRewriteData(Changes
[End
++], "Description-md5", DescriptionMd5
.c_str());
451 if (TransWriter
!= NULL
)
452 TransWriter
->DoPackage(Package
, desc
, DescriptionMd5
);
455 // Rewrite the maintainer field if necessary
457 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
458 if (MaintFailed
== true)
460 if (NoOverride
== false)
463 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"),
464 Package
.c_str(), Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
468 if (NewMaint
.empty() == false)
469 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
471 /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
472 dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
473 but dpkg does this append bit. So we do the append bit, at least that way the
474 status file and package file will remain similar. There are other transforms
475 but optional is the only legacy one still in use for some lazy reason. */
476 string OptionalStr
= Tags
.FindS("Optional");
477 if (OptionalStr
.empty() == false)
479 if (Tags
.FindS("Suggests").empty() == false)
480 OptionalStr
= Tags
.FindS("Suggests") + ", " + OptionalStr
;
481 SetTFRewriteData(Changes
[End
++], "Suggests", OptionalStr
.c_str());
484 for (map
<string
,string
>::const_iterator I
= OverItem
->FieldOverride
.begin();
485 I
!= OverItem
->FieldOverride
.end(); I
++)
486 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
488 SetTFRewriteData(Changes
[End
++], 0, 0);
490 // Rewrite and store the fields.
491 if (TFRewrite(Output
,Tags
,TFRewritePackageOrder
,Changes
) == false)
493 fprintf(Output
,"\n");
499 // TranslationWriter::TranslationWriter - Constructor /*{{{*/
500 // ---------------------------------------------------------------------
501 /* Create a Translation-Master file for this Packages file */
502 TranslationWriter::TranslationWriter(string
const &File
) : Output(NULL
),
505 if (File
.empty() == true)
508 Output
= fopen(File
.c_str(), "w");
511 // TranslationWriter::DoPackage - Process a single package /*{{{*/
512 // ---------------------------------------------------------------------
513 /* Create a Translation-Master file for this Packages file */
514 bool TranslationWriter::DoPackage(string
const &Pkg
, string
const &Desc
,
520 // Different archs can include different versions and therefore
521 // different descriptions - so we need to check for both name and md5.
522 string
const Record
= Pkg
+ ":" + MD5
;
524 if (Included
.find(Record
) != Included
.end())
527 fprintf(Output
, "Package: %s\nDescription-md5: %s\nDescription-en: %s\n",
528 Pkg
.c_str(), MD5
.c_str(), Desc
.c_str());
530 Included
.insert(Record
);
534 // TranslationWriter::~TranslationWriter - Destructor /*{{{*/
535 // ---------------------------------------------------------------------
537 TranslationWriter::~TranslationWriter()
544 // SourcesWriter::SourcesWriter - Constructor /*{{{*/
545 // ---------------------------------------------------------------------
547 SourcesWriter::SourcesWriter(string
const &BOverrides
,string
const &SOverrides
,
548 string
const &ExtOverrides
)
556 // Process the command line options
557 NoOverride
= _config
->FindB("APT::FTPArchive::NoOverrideMsg",false);
559 // Read the override file
560 if (BOverrides
.empty() == false && BOver
.ReadOverride(BOverrides
) == false)
565 // WTF?? The logic above: if we can't read binary overrides, don't even try
566 // reading source overrides. if we can read binary overrides, then say there
567 // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
569 if (ExtOverrides
.empty() == false)
570 SOver
.ReadExtraOverride(ExtOverrides
);
572 if (SOverrides
.empty() == false && FileExists(SOverrides
) == true)
573 SOver
.ReadOverride(SOverrides
,true);
576 // SourcesWriter::DoPackage - Process a single package /*{{{*/
577 // ---------------------------------------------------------------------
579 bool SourcesWriter::DoPackage(string FileName
)
582 FileFd
F(FileName
,FileFd::ReadOnly
);
583 if (_error
->PendingError() == true)
586 // Stat the file for later
588 if (fstat(F
.Fd(),&St
) != 0)
589 return _error
->Errno("fstat","Failed to stat %s",FileName
.c_str());
591 if (St
.st_size
> 128*1024)
592 return _error
->Error("DSC file '%s' is too large!",FileName
.c_str());
594 if (BufSize
< (unsigned)St
.st_size
+1)
596 BufSize
= St
.st_size
+1;
597 Buffer
= (char *)realloc(Buffer
,St
.st_size
+1);
600 if (F
.Read(Buffer
,St
.st_size
) == false)
604 char *Start
= Buffer
;
605 char *BlkEnd
= Buffer
+ St
.st_size
;
607 MD5
.Add((unsigned char *)Start
,BlkEnd
- Start
);
610 SHA256Summation SHA256
;
611 SHA1
.Add((unsigned char *)Start
,BlkEnd
- Start
);
612 SHA256
.Add((unsigned char *)Start
,BlkEnd
- Start
);
614 // Add an extra \n to the end, just in case
617 /* Remove the PGP trailer. Some .dsc's have this without a blank line
619 const char *Key
= "-----BEGIN PGP SIGNATURE-----";
620 for (char *MsgEnd
= Start
; MsgEnd
< BlkEnd
- strlen(Key
) -1; MsgEnd
++)
622 if (*MsgEnd
== '\n' && strncmp(MsgEnd
+1,Key
,strlen(Key
)) == 0)
629 /* Read records until we locate the Source record. This neatly skips the
630 GPG header (which is RFC822 formed) without any trouble. */
635 if (Tags
.Scan(Start
,BlkEnd
- Start
) == false)
636 return _error
->Error("Could not find a record in the DSC '%s'",FileName
.c_str());
637 if (Tags
.Find("Source",Pos
) == true)
639 Start
+= Tags
.size();
644 // Lookup the overide information, finding first the best priority.
646 string Bins
= Tags
.FindS("Binary");
647 char Buffer
[Bins
.length() + 1];
648 auto_ptr
<Override::Item
> OverItem(0);
649 if (Bins
.empty() == false)
651 strcpy(Buffer
,Bins
.c_str());
653 // Ignore too-long errors.
655 TokSplitString(',',Buffer
,BinList
,sizeof(BinList
)/sizeof(BinList
[0]));
657 // Look at all the binaries
658 unsigned char BestPrioV
= pkgCache::State::Extra
;
659 for (unsigned I
= 0; BinList
[I
] != 0; I
++)
661 auto_ptr
<Override::Item
> Itm(BOver
.GetItem(BinList
[I
]));
665 unsigned char NewPrioV
= debListParser::GetPrio(Itm
->Priority
);
666 if (NewPrioV
< BestPrioV
|| BestPrio
.empty() == true)
668 BestPrioV
= NewPrioV
;
669 BestPrio
= Itm
->Priority
;
672 if (OverItem
.get() == 0)
677 // If we need to do any rewriting of the header do it now..
678 if (OverItem
.get() == 0)
680 if (NoOverride
== false)
683 ioprintf(c1out
, _(" %s has no override entry\n"), Tags
.FindS("Source").c_str());
686 OverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
689 auto_ptr
<Override::Item
> SOverItem(SOver
.GetItem(Tags
.FindS("Source")));
690 // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
691 if (SOverItem
.get() == 0)
693 ioprintf(c1out
, _(" %s has no source override entry\n"), Tags
.FindS("Source").c_str());
694 SOverItem
= auto_ptr
<Override::Item
>(BOver
.GetItem(Tags
.FindS("Source")));
695 if (SOverItem
.get() == 0)
697 ioprintf(c1out
, _(" %s has no binary override entry either\n"), Tags
.FindS("Source").c_str());
698 SOverItem
= auto_ptr
<Override::Item
>(new Override::Item
);
699 *SOverItem
= *OverItem
;
703 // Add the dsc to the files hash list
704 string
const strippedName
= flNotDir(FileName
);
706 snprintf(Files
,sizeof(Files
),"\n %s %lu %s\n %s",
707 string(MD5
.Result()).c_str(),St
.st_size
,
708 strippedName
.c_str(),
709 Tags
.FindS("Files").c_str());
711 char ChecksumsSha1
[1000];
712 snprintf(ChecksumsSha1
,sizeof(ChecksumsSha1
),"\n %s %lu %s\n %s",
713 string(SHA1
.Result()).c_str(),St
.st_size
,
714 strippedName
.c_str(),
715 Tags
.FindS("Checksums-Sha1").c_str());
717 char ChecksumsSha256
[1000];
718 snprintf(ChecksumsSha256
,sizeof(ChecksumsSha256
),"\n %s %lu %s\n %s",
719 string(SHA256
.Result()).c_str(),St
.st_size
,
720 strippedName
.c_str(),
721 Tags
.FindS("Checksums-Sha256").c_str());
723 // Strip the DirStrip prefix from the FileName and add the PathPrefix
725 if (DirStrip
.empty() == false &&
726 FileName
.length() > DirStrip
.length() &&
727 stringcmp(DirStrip
,OriginalPath
,OriginalPath
+ DirStrip
.length()) == 0)
728 NewFileName
= string(OriginalPath
+ DirStrip
.length());
730 NewFileName
= OriginalPath
;
731 if (PathPrefix
.empty() == false)
732 NewFileName
= flCombine(PathPrefix
,NewFileName
);
734 string Directory
= flNotFile(OriginalPath
);
735 string Package
= Tags
.FindS("Source");
737 // Perform the delinking operation over all of the files
739 const char *C
= Files
;
740 char *RealPath
= NULL
;
741 for (;isspace(*C
); C
++);
744 // Parse each of the elements
745 if (ParseQuoteWord(C
,ParseJnk
) == false ||
746 ParseQuoteWord(C
,ParseJnk
) == false ||
747 ParseQuoteWord(C
,ParseJnk
) == false)
748 return _error
->Error("Error parsing file record");
751 string OriginalPath
= Directory
+ ParseJnk
;
752 if (readlink(OriginalPath
.c_str(),Jnk
,sizeof(Jnk
)) != -1 &&
753 (RealPath
= realpath(OriginalPath
.c_str(),NULL
)) != 0)
755 string RP
= RealPath
;
757 if (Delink(RP
,OriginalPath
.c_str(),Stats
.DeLinkBytes
,St
.st_size
) == false)
762 Directory
= flNotFile(NewFileName
);
763 if (Directory
.length() > 2)
764 Directory
.erase(Directory
.end()-1);
766 // This lists all the changes to the fields we are going to make.
767 // (5 hardcoded + checksums + maintainer + end marker)
768 TFRewriteData Changes
[5+2+1+SOverItem
->FieldOverride
.size()+1];
770 unsigned int End
= 0;
771 SetTFRewriteData(Changes
[End
++],"Source",Package
.c_str(),"Package");
772 SetTFRewriteData(Changes
[End
++],"Files",Files
);
773 SetTFRewriteData(Changes
[End
++],"Checksums-Sha1",ChecksumsSha1
);
774 SetTFRewriteData(Changes
[End
++],"Checksums-Sha256",ChecksumsSha256
);
775 if (Directory
!= "./")
776 SetTFRewriteData(Changes
[End
++],"Directory",Directory
.c_str());
777 SetTFRewriteData(Changes
[End
++],"Priority",BestPrio
.c_str());
778 SetTFRewriteData(Changes
[End
++],"Status",0);
780 // Rewrite the maintainer field if necessary
782 string NewMaint
= OverItem
->SwapMaint(Tags
.FindS("Maintainer"),MaintFailed
);
783 if (MaintFailed
== true)
785 if (NoOverride
== false)
788 ioprintf(c1out
, _(" %s maintainer is %s not %s\n"), Package
.c_str(),
789 Tags
.FindS("Maintainer").c_str(), OverItem
->OldMaint
.c_str());
792 if (NewMaint
.empty() == false)
793 SetTFRewriteData(Changes
[End
++], "Maintainer", NewMaint
.c_str());
795 for (map
<string
,string
>::const_iterator I
= SOverItem
->FieldOverride
.begin();
796 I
!= SOverItem
->FieldOverride
.end(); I
++)
797 SetTFRewriteData(Changes
[End
++],I
->first
.c_str(),I
->second
.c_str());
799 SetTFRewriteData(Changes
[End
++], 0, 0);
801 // Rewrite and store the fields.
802 if (TFRewrite(Output
,Tags
,TFRewriteSourceOrder
,Changes
) == false)
804 fprintf(Output
,"\n");
812 // ContentsWriter::ContentsWriter - Constructor /*{{{*/
813 // ---------------------------------------------------------------------
815 ContentsWriter::ContentsWriter(string
const &DB
, string
const &Arch
) :
816 FTWScanner(Arch
), Db(DB
), Stats(Db
.Stats
)
823 // ContentsWriter::DoPackage - Process a single package /*{{{*/
824 // ---------------------------------------------------------------------
825 /* If Package is the empty string the control record will be parsed to
826 determine what the package name is. */
827 bool ContentsWriter::DoPackage(string FileName
, string Package
)
829 if (!Db
.GetFileInfo(FileName
, Package
.empty(), true, false, false, false, false, false))
834 // Parse the package name
835 if (Package
.empty() == true)
837 Package
= Db
.Control
.Section
.FindS("Package");
840 Db
.Contents
.Add(Gen
,Package
);
845 // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
846 // ---------------------------------------------------------------------
848 bool ContentsWriter::ReadFromPkgs(string
const &PkgFile
,string
const &PkgCompress
)
850 MultiCompress
Pkgs(PkgFile
,PkgCompress
,0,false);
851 if (_error
->PendingError() == true)
854 // Open the package file
857 if (Pkgs
.OpenOld(CompFd
,Proc
) == false)
861 FileFd
Fd(CompFd
,false);
862 pkgTagFile
Tags(&Fd
);
863 if (_error
->PendingError() == true)
865 Pkgs
.CloseOld(CompFd
,Proc
);
870 pkgTagSection Section
;
871 while (Tags
.Step(Section
) == true)
873 string File
= flCombine(Prefix
,Section
.FindS("FileName"));
874 string Package
= Section
.FindS("Section");
875 if (Package
.empty() == false && Package
.end()[-1] != '/')
878 Package
+= Section
.FindS("Package");
881 Package
+= Section
.FindS("Package");
883 DoPackage(File
,Package
);
884 if (_error
->empty() == false)
886 _error
->Error("Errors apply to file '%s'",File
.c_str());
887 _error
->DumpErrors();
891 // Tidy the compressor
892 if (Pkgs
.CloseOld(CompFd
,Proc
) == false)
900 // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
901 // ---------------------------------------------------------------------
903 ReleaseWriter::ReleaseWriter(string
const &DB
)
905 AddPattern("Packages");
906 AddPattern("Packages.gz");
907 AddPattern("Packages.bz2");
908 AddPattern("Packages.lzma");
909 AddPattern("Sources");
910 AddPattern("Sources.gz");
911 AddPattern("Sources.bz2");
912 AddPattern("Sources.lzma");
913 AddPattern("Release");
914 AddPattern("md5sum.txt");
917 time_t const now
= time(NULL
);
919 if (strftime(datestr
, sizeof(datestr
), "%a, %d %b %Y %H:%M:%S UTC",
925 map
<string
,string
> Fields
;
926 Fields
["Origin"] = "";
927 Fields
["Label"] = "";
928 Fields
["Suite"] = "";
929 Fields
["Version"] = "";
930 Fields
["Codename"] = "";
931 Fields
["Date"] = datestr
;
932 Fields
["Architectures"] = "";
933 Fields
["Components"] = "";
934 Fields
["Description"] = "";
936 for(map
<string
,string
>::const_iterator I
= Fields
.begin();
940 string Config
= string("APT::FTPArchive::Release::") + (*I
).first
;
941 string Value
= _config
->Find(Config
, (*I
).second
.c_str());
945 fprintf(Output
, "%s: %s\n", (*I
).first
.c_str(), Value
.c_str());
949 // ReleaseWriter::DoPackage - Process a single package /*{{{*/
950 // ---------------------------------------------------------------------
951 bool ReleaseWriter::DoPackage(string FileName
)
953 // Strip the DirStrip prefix from the FileName and add the PathPrefix
955 if (DirStrip
.empty() == false &&
956 FileName
.length() > DirStrip
.length() &&
957 stringcmp(FileName
.begin(),FileName
.begin() + DirStrip
.length(),
958 DirStrip
.begin(),DirStrip
.end()) == 0)
960 NewFileName
= string(FileName
.begin() + DirStrip
.length(),FileName
.end());
961 while (NewFileName
[0] == '/')
962 NewFileName
= string(NewFileName
.begin() + 1,NewFileName
.end());
965 NewFileName
= FileName
;
967 if (PathPrefix
.empty() == false)
968 NewFileName
= flCombine(PathPrefix
,NewFileName
);
970 FileFd
fd(FileName
, FileFd::ReadOnly
);
977 CheckSums
[NewFileName
].size
= fd
.Size();
980 MD5
.AddFD(fd
.Fd(), fd
.Size());
981 CheckSums
[NewFileName
].MD5
= MD5
.Result();
985 SHA1
.AddFD(fd
.Fd(), fd
.Size());
986 CheckSums
[NewFileName
].SHA1
= SHA1
.Result();
989 SHA256Summation SHA256
;
990 SHA256
.AddFD(fd
.Fd(), fd
.Size());
991 CheckSums
[NewFileName
].SHA256
= SHA256
.Result();
999 // ReleaseWriter::Finish - Output the checksums /*{{{*/
1000 // ---------------------------------------------------------------------
1001 void ReleaseWriter::Finish()
1003 fprintf(Output
, "MD5Sum:\n");
1004 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1005 I
!= CheckSums
.end();
1008 fprintf(Output
, " %s %16ld %s\n",
1009 (*I
).second
.MD5
.c_str(),
1011 (*I
).first
.c_str());
1014 fprintf(Output
, "SHA1:\n");
1015 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1016 I
!= CheckSums
.end();
1019 fprintf(Output
, " %s %16ld %s\n",
1020 (*I
).second
.SHA1
.c_str(),
1022 (*I
).first
.c_str());
1025 fprintf(Output
, "SHA256:\n");
1026 for(map
<string
,struct CheckSum
>::const_iterator I
= CheckSums
.begin();
1027 I
!= CheckSums
.end();
1030 fprintf(Output
, " %s %16ld %s\n",
1031 (*I
).second
.SHA256
.c_str(),
1033 (*I
).first
.c_str());