| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052 |
- // -*- mode: cpp; mode: fold -*-
- // Description /*{{{*/
- // $Id: writer.cc,v 1.14 2004/03/24 01:40:43 mdz Exp $
- /* ######################################################################
- Writer
-
- The file writer classes. These write various types of output, sources,
- packages and contents.
-
- ##################################################################### */
- /*}}}*/
- // Include Files /*{{{*/
- #include "writer.h"
-
- #include <apti18n.h>
- #include <apt-pkg/strutl.h>
- #include <apt-pkg/error.h>
- #include <apt-pkg/configuration.h>
- #include <apt-pkg/md5.h>
- #include <apt-pkg/sha1.h>
- #include <apt-pkg/sha256.h>
- #include <apt-pkg/deblistparser.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <ctime>
- #include <ftw.h>
- #include <fnmatch.h>
- #include <iostream>
- #include <sstream>
- #include <memory>
-
- #include "cachedb.h"
- #include "apt-ftparchive.h"
- #include "multicompress.h"
- /*}}}*/
- using namespace std;
- FTWScanner *FTWScanner::Owner;
- // SetTFRewriteData - Helper for setting rewrite lists /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- inline void SetTFRewriteData(struct TFRewriteData &tfrd,
- const char *tag,
- const char *rewrite,
- const char *newtag = 0)
- {
- tfrd.Tag = tag;
- tfrd.Rewrite = rewrite;
- tfrd.NewTag = newtag;
- }
- /*}}}*/
- // FTWScanner::FTWScanner - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- FTWScanner::FTWScanner(string const &Arch): Arch(Arch)
- {
- ErrorPrinted = false;
- NoLinkAct = !_config->FindB("APT::FTPArchive::DeLinkAct",true);
- }
- /*}}}*/
- // FTWScanner::Scanner - FTW Scanner /*{{{*/
- // ---------------------------------------------------------------------
- /* This is the FTW scanner, it processes each directory element in the
- directory tree. */
- int FTWScanner::ScannerFTW(const char *File,const struct stat *sb,int Flag)
- {
- if (Flag == FTW_DNR)
- {
- Owner->NewLine(1);
- ioprintf(c1out, _("W: Unable to read directory %s\n"), File);
- }
- if (Flag == FTW_NS)
- {
- Owner->NewLine(1);
- ioprintf(c1out, _("W: Unable to stat %s\n"), File);
- }
- if (Flag != FTW_F)
- return 0;
- return ScannerFile(File, true);
- }
- /*}}}*/
- // FTWScanner::ScannerFile - File Scanner /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- int FTWScanner::ScannerFile(const char *File, bool const &ReadLink)
- {
- const char *LastComponent = strrchr(File, '/');
- char *RealPath = NULL;
- if (LastComponent == NULL)
- LastComponent = File;
- else
- LastComponent++;
- vector<string>::const_iterator I;
- for(I = Owner->Patterns.begin(); I != Owner->Patterns.end(); ++I)
- {
- if (fnmatch((*I).c_str(), LastComponent, 0) == 0)
- break;
- }
- if (I == Owner->Patterns.end())
- return 0;
- /* Process it. If the file is a link then resolve it into an absolute
- name.. This works best if the directory components the scanner are
- given are not links themselves. */
- char Jnk[2];
- Owner->OriginalPath = File;
- if (ReadLink &&
- readlink(File,Jnk,sizeof(Jnk)) != -1 &&
- (RealPath = realpath(File,NULL)) != 0)
- {
- Owner->DoPackage(RealPath);
- free(RealPath);
- }
- else
- Owner->DoPackage(File);
-
- if (_error->empty() == false)
- {
- // Print any errors or warnings found
- string Err;
- bool SeenPath = false;
- while (_error->empty() == false)
- {
- Owner->NewLine(1);
-
- bool const Type = _error->PopMessage(Err);
- if (Type == true)
- cerr << _("E: ") << Err << endl;
- else
- cerr << _("W: ") << Err << endl;
-
- if (Err.find(File) != string::npos)
- SeenPath = true;
- }
-
- if (SeenPath == false)
- cerr << _("E: Errors apply to file ") << "'" << File << "'" << endl;
- return 0;
- }
-
- return 0;
- }
- /*}}}*/
- // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- bool FTWScanner::RecursiveScan(string const &Dir)
- {
- char *RealPath = NULL;
- /* If noprefix is set then jam the scan root in, so we don't generate
- link followed paths out of control */
- if (InternalPrefix.empty() == true)
- {
- if ((RealPath = realpath(Dir.c_str(),NULL)) == 0)
- return _error->Errno("realpath",_("Failed to resolve %s"),Dir.c_str());
- InternalPrefix = RealPath;
- free(RealPath);
- }
-
- // Do recursive directory searching
- Owner = this;
- int const Res = ftw(Dir.c_str(),ScannerFTW,30);
-
- // Error treewalking?
- if (Res != 0)
- {
- if (_error->PendingError() == false)
- _error->Errno("ftw",_("Tree walking failed"));
- return false;
- }
-
- return true;
- }
- /*}}}*/
- // FTWScanner::LoadFileList - Load the file list from a file /*{{{*/
- // ---------------------------------------------------------------------
- /* This is an alternative to using FTW to locate files, it reads the list
- of files from another file. */
- bool FTWScanner::LoadFileList(string const &Dir, string const &File)
- {
- char *RealPath = NULL;
- /* If noprefix is set then jam the scan root in, so we don't generate
- link followed paths out of control */
- if (InternalPrefix.empty() == true)
- {
- if ((RealPath = realpath(Dir.c_str(),NULL)) == 0)
- return _error->Errno("realpath",_("Failed to resolve %s"),Dir.c_str());
- InternalPrefix = RealPath;
- free(RealPath);
- }
-
- Owner = this;
- FILE *List = fopen(File.c_str(),"r");
- if (List == 0)
- return _error->Errno("fopen",_("Failed to open %s"),File.c_str());
-
- /* We are a tad tricky here.. We prefix the buffer with the directory
- name, that way if we need a full path with just use line.. Sneaky and
- fully evil. */
- char Line[1000];
- char *FileStart;
- if (Dir.empty() == true || Dir.end()[-1] != '/')
- FileStart = Line + snprintf(Line,sizeof(Line),"%s/",Dir.c_str());
- else
- FileStart = Line + snprintf(Line,sizeof(Line),"%s",Dir.c_str());
- while (fgets(FileStart,sizeof(Line) - (FileStart - Line),List) != 0)
- {
- char *FileName = _strstrip(FileStart);
- if (FileName[0] == 0)
- continue;
-
- if (FileName[0] != '/')
- {
- if (FileName != FileStart)
- memmove(FileStart,FileName,strlen(FileStart));
- FileName = Line;
- }
-
- #if 0
- struct stat St;
- int Flag = FTW_F;
- if (stat(FileName,&St) != 0)
- Flag = FTW_NS;
- #endif
- if (ScannerFile(FileName, false) != 0)
- break;
- }
-
- fclose(List);
- return true;
- }
- /*}}}*/
- // FTWScanner::Delink - Delink symlinks /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
- unsigned long &DeLinkBytes,
- off_t const &FileSize)
- {
- // See if this isn't an internaly prefix'd file name.
- if (InternalPrefix.empty() == false &&
- InternalPrefix.length() < FileName.length() &&
- stringcmp(FileName.begin(),FileName.begin() + InternalPrefix.length(),
- InternalPrefix.begin(),InternalPrefix.end()) != 0)
- {
- if (DeLinkLimit != 0 && DeLinkBytes/1024 < DeLinkLimit)
- {
- // Tidy up the display
- if (DeLinkBytes == 0)
- cout << endl;
-
- NewLine(1);
- ioprintf(c1out, _(" DeLink %s [%s]\n"), (OriginalPath + InternalPrefix.length()),
- SizeToStr(FileSize).c_str());
- c1out << flush;
-
- if (NoLinkAct == false)
- {
- char OldLink[400];
- if (readlink(OriginalPath,OldLink,sizeof(OldLink)) == -1)
- _error->Errno("readlink",_("Failed to readlink %s"),OriginalPath);
- else
- {
- if (unlink(OriginalPath) != 0)
- _error->Errno("unlink",_("Failed to unlink %s"),OriginalPath);
- else
- {
- if (link(FileName.c_str(),OriginalPath) != 0)
- {
- // Panic! Restore the symlink
- symlink(OldLink,OriginalPath);
- return _error->Errno("link",_("*** Failed to link %s to %s"),
- FileName.c_str(),
- OriginalPath);
- }
- }
- }
- }
-
- DeLinkBytes += FileSize;
- if (DeLinkBytes/1024 >= DeLinkLimit)
- ioprintf(c1out, _(" DeLink limit of %sB hit.\n"), SizeToStr(DeLinkBytes).c_str());
- }
-
- FileName = OriginalPath;
- }
-
- return true;
- }
- /*}}}*/
- // PackagesWriter::PackagesWriter - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- PackagesWriter::PackagesWriter(string const &DB,string const &Overrides,string const &ExtOverrides,
- string const &Arch) :
- FTWScanner(Arch), Db(DB), Stats(Db.Stats), TransWriter(NULL)
- {
- Output = stdout;
- SetExts(".deb .udeb");
- DeLinkLimit = 0;
-
- // Process the command line options
- DoMD5 = _config->FindB("APT::FTPArchive::MD5",true);
- DoSHA1 = _config->FindB("APT::FTPArchive::SHA1",true);
- DoSHA256 = _config->FindB("APT::FTPArchive::SHA256",true);
- DoAlwaysStat = _config->FindB("APT::FTPArchive::AlwaysStat", false);
- DoContents = _config->FindB("APT::FTPArchive::Contents",true);
- NoOverride = _config->FindB("APT::FTPArchive::NoOverrideMsg",false);
- LongDescription = _config->FindB("APT::FTPArchive::LongDescription",true);
- if (Db.Loaded() == false)
- DoContents = false;
- // Read the override file
- if (Overrides.empty() == false && Over.ReadOverride(Overrides) == false)
- return;
- else
- NoOverride = true;
- if (ExtOverrides.empty() == false)
- Over.ReadExtraOverride(ExtOverrides);
- _error->DumpErrors();
- }
- /*}}}*/
- // FTWScanner::SetExts - Set extensions to support /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- bool FTWScanner::SetExts(string const &Vals)
- {
- ClearPatterns();
- string::size_type Start = 0;
- while (Start <= Vals.length()-1)
- {
- string::size_type const Space = Vals.find(' ',Start);
- string::size_type const Length = ((Space == string::npos) ? Vals.length() : Space) - Start;
- if ( Arch.empty() == false )
- {
- AddPattern(string("*_") + Arch + Vals.substr(Start, Length));
- AddPattern(string("*_all") + Vals.substr(Start, Length));
- }
- else
- AddPattern(string("*") + Vals.substr(Start, Length));
- Start += Length + 1;
- }
- return true;
- }
- /*}}}*/
- // PackagesWriter::DoPackage - Process a single package /*{{{*/
- // ---------------------------------------------------------------------
- /* This method takes a package and gets its control information and
- MD5, SHA1 and SHA256 then writes out a control record with the proper fields
- rewritten and the path/size/hash appended. */
- bool PackagesWriter::DoPackage(string FileName)
- {
- // Pull all the data we need form the DB
- if (Db.GetFileInfo(FileName, true, DoContents, true, DoMD5, DoSHA1, DoSHA256, DoAlwaysStat)
- == false)
- {
- return false;
- }
- off_t FileSize = Db.GetFileSize();
- if (Delink(FileName,OriginalPath,Stats.DeLinkBytes,FileSize) == false)
- return false;
-
- // Lookup the overide information
- pkgTagSection &Tags = Db.Control.Section;
- string Package = Tags.FindS("Package");
- string Architecture;
- // if we generate a Packages file for a given arch, we use it to
- // look for overrides. if we run in "simple" mode without the
- // "Architecures" variable in the config we use the architecure value
- // from the deb file
- if(Arch != "")
- Architecture = Arch;
- else
- Architecture = Tags.FindS("Architecture");
- auto_ptr<Override::Item> OverItem(Over.GetItem(Package,Architecture));
-
- if (Package.empty() == true)
- return _error->Error(_("Archive had no package field"));
- // If we need to do any rewriting of the header do it now..
- if (OverItem.get() == 0)
- {
- if (NoOverride == false)
- {
- NewLine(1);
- ioprintf(c1out, _(" %s has no override entry\n"), Package.c_str());
- }
-
- OverItem = auto_ptr<Override::Item>(new Override::Item);
- OverItem->FieldOverride["Section"] = Tags.FindS("Section");
- OverItem->Priority = Tags.FindS("Priority");
- }
- char Size[40];
- sprintf(Size,"%lu", (unsigned long) FileSize);
-
- // Strip the DirStrip prefix from the FileName and add the PathPrefix
- string NewFileName;
- if (DirStrip.empty() == false &&
- FileName.length() > DirStrip.length() &&
- stringcmp(FileName.begin(),FileName.begin() + DirStrip.length(),
- DirStrip.begin(),DirStrip.end()) == 0)
- NewFileName = string(FileName.begin() + DirStrip.length(),FileName.end());
- else
- NewFileName = FileName;
- if (PathPrefix.empty() == false)
- NewFileName = flCombine(PathPrefix,NewFileName);
- /* Configuration says we don't want to include the long Description
- in the package file - instead we want to ship a separated file */
- string desc;
- if (LongDescription == false) {
- desc = Tags.FindS("Description").append("\n");
- OverItem->FieldOverride["Description"] = desc.substr(0, desc.find('\n')).c_str();
- }
- // This lists all the changes to the fields we are going to make.
- // (7 hardcoded + maintainer + suggests + end marker)
- TFRewriteData Changes[6+2+OverItem->FieldOverride.size()+1+1];
- unsigned int End = 0;
- SetTFRewriteData(Changes[End++], "Size", Size);
- SetTFRewriteData(Changes[End++], "MD5sum", Db.MD5Res.c_str());
- SetTFRewriteData(Changes[End++], "SHA1", Db.SHA1Res.c_str());
- SetTFRewriteData(Changes[End++], "SHA256", Db.SHA256Res.c_str());
- SetTFRewriteData(Changes[End++], "Filename", NewFileName.c_str());
- SetTFRewriteData(Changes[End++], "Priority", OverItem->Priority.c_str());
- SetTFRewriteData(Changes[End++], "Status", 0);
- SetTFRewriteData(Changes[End++], "Optional", 0);
- string DescriptionMd5;
- if (LongDescription == false) {
- MD5Summation descmd5;
- descmd5.Add(desc.c_str());
- DescriptionMd5 = descmd5.Result().Value();
- SetTFRewriteData(Changes[End++], "Description-md5", DescriptionMd5.c_str());
- if (TransWriter != NULL)
- TransWriter->DoPackage(Package, desc, DescriptionMd5);
- }
- // Rewrite the maintainer field if necessary
- bool MaintFailed;
- string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
- if (MaintFailed == true)
- {
- if (NoOverride == false)
- {
- NewLine(1);
- ioprintf(c1out, _(" %s maintainer is %s not %s\n"),
- Package.c_str(), Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
- }
- }
-
- if (NewMaint.empty() == false)
- SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
-
- /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that
- dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming
- but dpkg does this append bit. So we do the append bit, at least that way the
- status file and package file will remain similar. There are other transforms
- but optional is the only legacy one still in use for some lazy reason. */
- string OptionalStr = Tags.FindS("Optional");
- if (OptionalStr.empty() == false)
- {
- if (Tags.FindS("Suggests").empty() == false)
- OptionalStr = Tags.FindS("Suggests") + ", " + OptionalStr;
- SetTFRewriteData(Changes[End++], "Suggests", OptionalStr.c_str());
- }
- for (map<string,string>::const_iterator I = OverItem->FieldOverride.begin();
- I != OverItem->FieldOverride.end(); I++)
- SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
- SetTFRewriteData(Changes[End++], 0, 0);
- // Rewrite and store the fields.
- if (TFRewrite(Output,Tags,TFRewritePackageOrder,Changes) == false)
- return false;
- fprintf(Output,"\n");
- return Db.Finish();
- }
- /*}}}*/
- // TranslationWriter::TranslationWriter - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* Create a Translation-Master file for this Packages file */
- TranslationWriter::TranslationWriter(string const &File, string const &TransCompress,
- mode_t const &Permissions) : Output(NULL),
- RefCounter(0)
- {
- if (File.empty() == true)
- return;
- Comp = new MultiCompress(File, TransCompress, Permissions);
- Output = Comp->Input;
- }
- /*}}}*/
- // TranslationWriter::DoPackage - Process a single package /*{{{*/
- // ---------------------------------------------------------------------
- /* Create a Translation-Master file for this Packages file */
- bool TranslationWriter::DoPackage(string const &Pkg, string const &Desc,
- string const &MD5)
- {
- if (Output == NULL)
- return true;
- // Different archs can include different versions and therefore
- // different descriptions - so we need to check for both name and md5.
- string const Record = Pkg + ":" + MD5;
- if (Included.find(Record) != Included.end())
- return true;
- fprintf(Output, "Package: %s\nDescription-md5: %s\nDescription-en: %s\n",
- Pkg.c_str(), MD5.c_str(), Desc.c_str());
- Included.insert(Record);
- return true;
- }
- /*}}}*/
- // TranslationWriter::~TranslationWriter - Destructor /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- TranslationWriter::~TranslationWriter()
- {
- if (Comp == NULL)
- return;
- delete Comp;
- }
- /*}}}*/
- // SourcesWriter::SourcesWriter - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- SourcesWriter::SourcesWriter(string const &BOverrides,string const &SOverrides,
- string const &ExtOverrides)
- {
- Output = stdout;
- AddPattern("*.dsc");
- DeLinkLimit = 0;
- Buffer = 0;
- BufSize = 0;
-
- // Process the command line options
- NoOverride = _config->FindB("APT::FTPArchive::NoOverrideMsg",false);
- // Read the override file
- if (BOverrides.empty() == false && BOver.ReadOverride(BOverrides) == false)
- return;
- else
- NoOverride = true;
- // WTF?? The logic above: if we can't read binary overrides, don't even try
- // reading source overrides. if we can read binary overrides, then say there
- // are no overrides. THIS MAKES NO SENSE! -- ajt@d.o, 2006/02/28
- if (ExtOverrides.empty() == false)
- SOver.ReadExtraOverride(ExtOverrides);
-
- if (SOverrides.empty() == false && FileExists(SOverrides) == true)
- SOver.ReadOverride(SOverrides,true);
- }
- /*}}}*/
- // SourcesWriter::DoPackage - Process a single package /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- bool SourcesWriter::DoPackage(string FileName)
- {
- // Open the archive
- FileFd F(FileName,FileFd::ReadOnly);
- if (_error->PendingError() == true)
- return false;
-
- // Stat the file for later
- struct stat St;
- if (fstat(F.Fd(),&St) != 0)
- return _error->Errno("fstat","Failed to stat %s",FileName.c_str());
- if (St.st_size > 128*1024)
- return _error->Error("DSC file '%s' is too large!",FileName.c_str());
-
- if (BufSize < (unsigned)St.st_size+1)
- {
- BufSize = St.st_size+1;
- Buffer = (char *)realloc(Buffer,St.st_size+1);
- }
-
- if (F.Read(Buffer,St.st_size) == false)
- return false;
- // Hash the file
- char *Start = Buffer;
- char *BlkEnd = Buffer + St.st_size;
- MD5Summation MD5;
- MD5.Add((unsigned char *)Start,BlkEnd - Start);
- SHA1Summation SHA1;
- SHA256Summation SHA256;
- SHA1.Add((unsigned char *)Start,BlkEnd - Start);
- SHA256.Add((unsigned char *)Start,BlkEnd - Start);
- // Add an extra \n to the end, just in case
- *BlkEnd++ = '\n';
-
- /* Remove the PGP trailer. Some .dsc's have this without a blank line
- before */
- const char *Key = "-----BEGIN PGP SIGNATURE-----";
- for (char *MsgEnd = Start; MsgEnd < BlkEnd - strlen(Key) -1; MsgEnd++)
- {
- if (*MsgEnd == '\n' && strncmp(MsgEnd+1,Key,strlen(Key)) == 0)
- {
- MsgEnd[1] = '\n';
- break;
- }
- }
-
- /* Read records until we locate the Source record. This neatly skips the
- GPG header (which is RFC822 formed) without any trouble. */
- pkgTagSection Tags;
- do
- {
- unsigned Pos;
- if (Tags.Scan(Start,BlkEnd - Start) == false)
- return _error->Error("Could not find a record in the DSC '%s'",FileName.c_str());
- if (Tags.Find("Source",Pos) == true)
- break;
- Start += Tags.size();
- }
- while (1);
- Tags.Trim();
-
- // Lookup the overide information, finding first the best priority.
- string BestPrio;
- string Bins = Tags.FindS("Binary");
- char Buffer[Bins.length() + 1];
- auto_ptr<Override::Item> OverItem(0);
- if (Bins.empty() == false)
- {
- strcpy(Buffer,Bins.c_str());
-
- // Ignore too-long errors.
- char *BinList[400];
- TokSplitString(',',Buffer,BinList,sizeof(BinList)/sizeof(BinList[0]));
-
- // Look at all the binaries
- unsigned char BestPrioV = pkgCache::State::Extra;
- for (unsigned I = 0; BinList[I] != 0; I++)
- {
- auto_ptr<Override::Item> Itm(BOver.GetItem(BinList[I]));
- if (Itm.get() == 0)
- continue;
- unsigned char NewPrioV = debListParser::GetPrio(Itm->Priority);
- if (NewPrioV < BestPrioV || BestPrio.empty() == true)
- {
- BestPrioV = NewPrioV;
- BestPrio = Itm->Priority;
- }
- if (OverItem.get() == 0)
- OverItem = Itm;
- }
- }
-
- // If we need to do any rewriting of the header do it now..
- if (OverItem.get() == 0)
- {
- if (NoOverride == false)
- {
- NewLine(1);
- ioprintf(c1out, _(" %s has no override entry\n"), Tags.FindS("Source").c_str());
- }
-
- OverItem = auto_ptr<Override::Item>(new Override::Item);
- }
-
- auto_ptr<Override::Item> SOverItem(SOver.GetItem(Tags.FindS("Source")));
- // const auto_ptr<Override::Item> autoSOverItem(SOverItem);
- if (SOverItem.get() == 0)
- {
- ioprintf(c1out, _(" %s has no source override entry\n"), Tags.FindS("Source").c_str());
- SOverItem = auto_ptr<Override::Item>(BOver.GetItem(Tags.FindS("Source")));
- if (SOverItem.get() == 0)
- {
- ioprintf(c1out, _(" %s has no binary override entry either\n"), Tags.FindS("Source").c_str());
- SOverItem = auto_ptr<Override::Item>(new Override::Item);
- *SOverItem = *OverItem;
- }
- }
-
- // Add the dsc to the files hash list
- string const strippedName = flNotDir(FileName);
- std::ostringstream ostreamFiles;
- if (Tags.Exists("Files"))
- ostreamFiles << "\n " << string(MD5.Result()) << " " << St.st_size << " "
- << strippedName << "\n " << Tags.FindS("Files");
- string const Files = ostreamFiles.str();
- std::ostringstream ostreamSha1;
- if (Tags.Exists("Checksums-Sha1"))
- ostreamSha1 << "\n " << string(SHA1.Result()) << " " << St.st_size << " "
- << strippedName << "\n " << Tags.FindS("Checksums-Sha1");
- string const ChecksumsSha1 = ostreamSha1.str();
- std::ostringstream ostreamSha256;
- if (Tags.Exists("Checksums-Sha256"))
- ostreamSha256 << "\n " << string(SHA256.Result()) << " " << St.st_size << " "
- << strippedName << "\n " << Tags.FindS("Checksums-Sha256");
- string const ChecksumsSha256 = ostreamSha256.str();
- // Strip the DirStrip prefix from the FileName and add the PathPrefix
- string NewFileName;
- if (DirStrip.empty() == false &&
- FileName.length() > DirStrip.length() &&
- stringcmp(DirStrip,OriginalPath,OriginalPath + DirStrip.length()) == 0)
- NewFileName = string(OriginalPath + DirStrip.length());
- else
- NewFileName = OriginalPath;
- if (PathPrefix.empty() == false)
- NewFileName = flCombine(PathPrefix,NewFileName);
- string Directory = flNotFile(OriginalPath);
- string Package = Tags.FindS("Source");
- // Perform the delinking operation over all of the files
- string ParseJnk;
- const char *C = Files.c_str();
- char *RealPath = NULL;
- for (;isspace(*C); C++);
- while (*C != 0)
- {
- // Parse each of the elements
- if (ParseQuoteWord(C,ParseJnk) == false ||
- ParseQuoteWord(C,ParseJnk) == false ||
- ParseQuoteWord(C,ParseJnk) == false)
- return _error->Error("Error parsing file record");
-
- char Jnk[2];
- string OriginalPath = Directory + ParseJnk;
- if (readlink(OriginalPath.c_str(),Jnk,sizeof(Jnk)) != -1 &&
- (RealPath = realpath(OriginalPath.c_str(),NULL)) != 0)
- {
- string RP = RealPath;
- free(RealPath);
- if (Delink(RP,OriginalPath.c_str(),Stats.DeLinkBytes,St.st_size) == false)
- return false;
- }
- }
- Directory = flNotFile(NewFileName);
- if (Directory.length() > 2)
- Directory.erase(Directory.end()-1);
- // This lists all the changes to the fields we are going to make.
- // (5 hardcoded + checksums + maintainer + end marker)
- TFRewriteData Changes[5+2+1+SOverItem->FieldOverride.size()+1];
- unsigned int End = 0;
- SetTFRewriteData(Changes[End++],"Source",Package.c_str(),"Package");
- SetTFRewriteData(Changes[End++],"Files",Files.c_str());
- SetTFRewriteData(Changes[End++],"Checksums-Sha1",ChecksumsSha1.c_str());
- SetTFRewriteData(Changes[End++],"Checksums-Sha256",ChecksumsSha256.c_str());
- if (Directory != "./")
- SetTFRewriteData(Changes[End++],"Directory",Directory.c_str());
- SetTFRewriteData(Changes[End++],"Priority",BestPrio.c_str());
- SetTFRewriteData(Changes[End++],"Status",0);
- // Rewrite the maintainer field if necessary
- bool MaintFailed;
- string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed);
- if (MaintFailed == true)
- {
- if (NoOverride == false)
- {
- NewLine(1);
- ioprintf(c1out, _(" %s maintainer is %s not %s\n"), Package.c_str(),
- Tags.FindS("Maintainer").c_str(), OverItem->OldMaint.c_str());
- }
- }
- if (NewMaint.empty() == false)
- SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str());
-
- for (map<string,string>::const_iterator I = SOverItem->FieldOverride.begin();
- I != SOverItem->FieldOverride.end(); I++)
- SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str());
- SetTFRewriteData(Changes[End++], 0, 0);
-
- // Rewrite and store the fields.
- if (TFRewrite(Output,Tags,TFRewriteSourceOrder,Changes) == false)
- return false;
- fprintf(Output,"\n");
- Stats.Packages++;
-
- return true;
- }
- /*}}}*/
- // ContentsWriter::ContentsWriter - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- ContentsWriter::ContentsWriter(string const &DB, string const &Arch) :
- FTWScanner(Arch), Db(DB), Stats(Db.Stats)
- {
- SetExts(".deb");
- Output = stdout;
- }
- /*}}}*/
- // ContentsWriter::DoPackage - Process a single package /*{{{*/
- // ---------------------------------------------------------------------
- /* If Package is the empty string the control record will be parsed to
- determine what the package name is. */
- bool ContentsWriter::DoPackage(string FileName, string Package)
- {
- if (!Db.GetFileInfo(FileName, Package.empty(), true, false, false, false, false, false))
- {
- return false;
- }
- // Parse the package name
- if (Package.empty() == true)
- {
- Package = Db.Control.Section.FindS("Package");
- }
- Db.Contents.Add(Gen,Package);
-
- return Db.Finish();
- }
- /*}}}*/
- // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- bool ContentsWriter::ReadFromPkgs(string const &PkgFile,string const &PkgCompress)
- {
- MultiCompress Pkgs(PkgFile,PkgCompress,0,false);
- if (_error->PendingError() == true)
- return false;
-
- // Open the package file
- int CompFd = -1;
- pid_t Proc = -1;
- if (Pkgs.OpenOld(CompFd,Proc) == false)
- return false;
-
- // No auto-close FD
- FileFd Fd(CompFd,false);
- pkgTagFile Tags(&Fd);
- if (_error->PendingError() == true)
- {
- Pkgs.CloseOld(CompFd,Proc);
- return false;
- }
-
- // Parse.
- pkgTagSection Section;
- while (Tags.Step(Section) == true)
- {
- string File = flCombine(Prefix,Section.FindS("FileName"));
- string Package = Section.FindS("Section");
- if (Package.empty() == false && Package.end()[-1] != '/')
- {
- Package += '/';
- Package += Section.FindS("Package");
- }
- else
- Package += Section.FindS("Package");
-
- DoPackage(File,Package);
- if (_error->empty() == false)
- {
- _error->Error("Errors apply to file '%s'",File.c_str());
- _error->DumpErrors();
- }
- }
-
- // Tidy the compressor
- if (Pkgs.CloseOld(CompFd,Proc) == false)
- return false;
-
- return true;
- }
- /*}}}*/
- // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- ReleaseWriter::ReleaseWriter(string const &DB)
- {
- AddPattern("Packages");
- AddPattern("Packages.gz");
- AddPattern("Packages.bz2");
- AddPattern("Packages.lzma");
- AddPattern("Sources");
- AddPattern("Sources.gz");
- AddPattern("Sources.bz2");
- AddPattern("Sources.lzma");
- AddPattern("Release");
- AddPattern("md5sum.txt");
- Output = stdout;
- time_t const now = time(NULL);
- char datestr[128];
- if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S UTC",
- gmtime(&now)) == 0)
- {
- datestr[0] = '\0';
- }
- time_t const validuntil = now + _config->FindI("APT::FTPArchive::Release::ValidTime", 0);
- char validstr[128];
- if (now == validuntil ||
- strftime(validstr, sizeof(validstr), "%a, %d %b %Y %H:%M:%S UTC",
- gmtime(&validuntil)) == 0)
- {
- validstr[0] = '\0';
- }
- map<string,string> Fields;
- Fields["Origin"] = "";
- Fields["Label"] = "";
- Fields["Suite"] = "";
- Fields["Version"] = "";
- Fields["Codename"] = "";
- Fields["Date"] = datestr;
- Fields["Valid-Until"] = validstr;
- Fields["Architectures"] = "";
- Fields["Components"] = "";
- Fields["Description"] = "";
- for(map<string,string>::const_iterator I = Fields.begin();
- I != Fields.end();
- ++I)
- {
- string Config = string("APT::FTPArchive::Release::") + (*I).first;
- string Value = _config->Find(Config, (*I).second.c_str());
- if (Value == "")
- continue;
- fprintf(Output, "%s: %s\n", (*I).first.c_str(), Value.c_str());
- }
- }
- /*}}}*/
- // ReleaseWriter::DoPackage - Process a single package /*{{{*/
- // ---------------------------------------------------------------------
- bool ReleaseWriter::DoPackage(string FileName)
- {
- // Strip the DirStrip prefix from the FileName and add the PathPrefix
- string NewFileName;
- if (DirStrip.empty() == false &&
- FileName.length() > DirStrip.length() &&
- stringcmp(FileName.begin(),FileName.begin() + DirStrip.length(),
- DirStrip.begin(),DirStrip.end()) == 0)
- {
- NewFileName = string(FileName.begin() + DirStrip.length(),FileName.end());
- while (NewFileName[0] == '/')
- NewFileName = string(NewFileName.begin() + 1,NewFileName.end());
- }
- else
- NewFileName = FileName;
- if (PathPrefix.empty() == false)
- NewFileName = flCombine(PathPrefix,NewFileName);
- FileFd fd(FileName, FileFd::ReadOnly);
- if (!fd.IsOpen())
- {
- return false;
- }
- CheckSums[NewFileName].size = fd.Size();
- MD5Summation MD5;
- MD5.AddFD(fd.Fd(), fd.Size());
- CheckSums[NewFileName].MD5 = MD5.Result();
- fd.Seek(0);
- SHA1Summation SHA1;
- SHA1.AddFD(fd.Fd(), fd.Size());
- CheckSums[NewFileName].SHA1 = SHA1.Result();
- fd.Seek(0);
- SHA256Summation SHA256;
- SHA256.AddFD(fd.Fd(), fd.Size());
- CheckSums[NewFileName].SHA256 = SHA256.Result();
- fd.Close();
-
- return true;
- }
- /*}}}*/
- // ReleaseWriter::Finish - Output the checksums /*{{{*/
- // ---------------------------------------------------------------------
- void ReleaseWriter::Finish()
- {
- fprintf(Output, "MD5Sum:\n");
- for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
- I != CheckSums.end();
- ++I)
- {
- fprintf(Output, " %s %16ld %s\n",
- (*I).second.MD5.c_str(),
- (*I).second.size,
- (*I).first.c_str());
- }
- fprintf(Output, "SHA1:\n");
- for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
- I != CheckSums.end();
- ++I)
- {
- fprintf(Output, " %s %16ld %s\n",
- (*I).second.SHA1.c_str(),
- (*I).second.size,
- (*I).first.c_str());
- }
- fprintf(Output, "SHA256:\n");
- for(map<string,struct CheckSum>::const_iterator I = CheckSums.begin();
- I != CheckSums.end();
- ++I)
- {
- fprintf(Output, " %s %16ld %s\n",
- (*I).second.SHA256.c_str(),
- (*I).second.size,
- (*I).first.c_str());
- }
- }
|