| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932 |
- // -*- 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 /*{{{*/
- #ifdef __GNUG__
- #pragma implementation "writer.h"
- #endif
- #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/deblistparser.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <ctime>
- #include <ftw.h>
- #include <fnmatch.h>
- #include <iostream>
-
- #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()
- {
- ErrorPrinted = false;
- NoLinkAct = !_config->FindB("APT::FTPArchive::DeLinkAct",true);
- RealPath = 0;
- long PMax = pathconf(".",_PC_PATH_MAX);
- if (PMax > 0)
- RealPath = new char[PMax];
- }
- /*}}}*/
- // FTWScanner::Scanner - FTW Scanner /*{{{*/
- // ---------------------------------------------------------------------
- /* This is the FTW scanner, it processes each directory element in the
- directory tree. */
- int FTWScanner::Scanner(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;
- const char *LastComponent = strrchr(File, '/');
- if (LastComponent == NULL)
- LastComponent = File;
- else
- LastComponent++;
- vector<string>::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 (Owner->RealPath != 0 && readlink(File,Jnk,sizeof(Jnk)) != -1 &&
- realpath(File,Owner->RealPath) != 0)
- Owner->DoPackage(Owner->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 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 Dir)
- {
- /* 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(Dir.c_str(),RealPath) == 0)
- return _error->Errno("realpath",_("Failed to resolve %s"),Dir.c_str());
- InternalPrefix = RealPath;
- }
-
- // Do recursive directory searching
- Owner = this;
- int Res = ftw(Dir.c_str(),Scanner,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 Dir,string File)
- {
- /* 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(Dir.c_str(),RealPath) == 0)
- return _error->Errno("realpath",_("Failed to resolve %s"),Dir.c_str());
- InternalPrefix = 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;
- }
-
- struct stat St;
- int Flag = FTW_F;
- if (stat(FileName,&St) != 0)
- Flag = FTW_NS;
- if (Scanner(FileName,&St,Flag) != 0)
- break;
- }
-
- fclose(List);
- return true;
- }
- /*}}}*/
- // FTWScanner::Delink - Delink symlinks /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- bool FTWScanner::Delink(string &FileName,const char *OriginalPath,
- unsigned long &DeLinkBytes,
- struct stat &St)
- {
- // 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(St.st_size).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 += St.st_size;
- 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 DB,string Overrides,string ExtOverrides,
- string aArch) :
- Db(DB),Stats(Db.Stats), Arch(aArch)
- {
- Output = stdout;
- SetExts(".deb .udeb .foo .bar .baz");
- AddPattern("*.deb");
- DeLinkLimit = 0;
-
- // Process the command line options
- DoMD5 = _config->FindB("APT::FTPArchive::MD5",true);
- DoContents = _config->FindB("APT::FTPArchive::Contents",true);
- NoOverride = _config->FindB("APT::FTPArchive::NoOverrideMsg",false);
- 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 Vals)
- {
- ClearPatterns();
- string::size_type Start = 0;
- while (Start <= Vals.length()-1)
- {
- string::size_type Space = Vals.find(' ',Start);
- string::size_type Length;
- if (Space == string::npos)
- {
- Length = Vals.length()-Start;
- }
- else
- {
- Length = Space-Start;
- }
- 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 then writes out a control record with the proper fields rewritten
- and the path/size/hash appended. */
- bool PackagesWriter::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());
- // Pull all the data we need form the DB
- string MD5Res;
- if (Db.SetFile(FileName,St,&F) == false ||
- Db.LoadControl() == false ||
- (DoContents == true && Db.LoadContents(true) == false) ||
- (DoMD5 == true && Db.GetMD5(MD5Res,false) == false))
- return false;
- if (Delink(FileName,OriginalPath,Stats.DeLinkBytes,St) == 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",St.st_size);
-
- // 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);
-
- // 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];
- unsigned int End = 0;
- SetTFRewriteData(Changes[End++], "Size", Size);
- SetTFRewriteData(Changes[End++], "MD5sum", MD5Res.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);
- // 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>::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();
- }
- /*}}}*/
- // SourcesWriter::SourcesWriter - Constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- SourcesWriter::SourcesWriter(string BOverrides,string SOverrides,
- string 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;
- 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);
-
- // 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)
- {
- SOverItem = auto_ptr<Override::Item>(BOver.GetItem(Tags.FindS("Source")));
- if (SOverItem.get() == 0)
- {
- SOverItem = auto_ptr<Override::Item>(new Override::Item);
- *SOverItem = *OverItem;
- }
- }
-
- // Add the dsc to the files hash list
- char Files[1000];
- snprintf(Files,sizeof(Files),"\n %s %lu %s\n %s",
- string(MD5.Result()).c_str(),St.st_size,
- flNotDir(FileName).c_str(),
- Tags.FindS("Files").c_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;
- 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 (RealPath != 0 && readlink(OriginalPath.c_str(),Jnk,sizeof(Jnk)) != -1 &&
- realpath(OriginalPath.c_str(),RealPath) != 0)
- {
- string RP = RealPath;
- if (Delink(RP,OriginalPath.c_str(),Stats.DeLinkBytes,St) == 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 + maintainer + end marker)
- TFRewriteData Changes[5+1+SOverItem->FieldOverride.size()+1];
- unsigned int End = 0;
- SetTFRewriteData(Changes[End++],"Source",Package.c_str(),"Package");
- SetTFRewriteData(Changes[End++],"Files",Files);
- 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>::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 DB) :
- Db(DB), Stats(Db.Stats)
- {
- AddPattern("*.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)
- {
- // 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 too stat %s",FileName.c_str());
- // Ready the DB
- if (Db.SetFile(FileName,St,&F) == false ||
- Db.LoadContents(false) == false)
- return false;
- // Parse the package name
- if (Package.empty() == true)
- {
- if (Db.LoadControl() == false)
- return false;
- 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 PkgFile,string 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 DB)
- {
- AddPattern("Packages");
- AddPattern("Packages.gz");
- AddPattern("Packages.bz2");
- AddPattern("Sources");
- AddPattern("Sources.gz");
- AddPattern("Sources.bz2");
- AddPattern("Release");
- AddPattern("md5sum.txt");
- Output = stdout;
- time_t 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';
- }
- map<string,string> Fields;
- Fields["Origin"] = "";
- Fields["Label"] = "";
- Fields["Suite"] = "";
- Fields["Version"] = "";
- Fields["Codename"] = "";
- Fields["Date"] = datestr;
- 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.Close();
-
- return true;
- }
- /*}}}*/
- // ReleaseWriter::Finish - Output the checksums /*{{{*/
- // ---------------------------------------------------------------------
- void ReleaseWriter::Finish()
- {
- fprintf(Output, "MD5Sum:\n");
- for(map<string,struct CheckSum>::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>::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());
- }
- }
|