diff options
Diffstat (limited to 'apt-pkg')
60 files changed, 3326 insertions, 1298 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index a959253bc..bb8a01db8 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -81,7 +81,7 @@ void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf) Status = StatError; Dequeue(); } - + // report mirror failure back to LP if we actually use a mirror string FailReason = LookupTag(Message, "FailReason"); if(FailReason.size() != 0) @@ -360,7 +360,7 @@ bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile) /*{{{*/ if(last_space != string::npos) Description.erase(last_space, Description.size()-last_space); new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc, - ExpectedHash, available_patches); + ExpectedHash, ServerSha1, available_patches); Complete = false; Status = StatDone; Dequeue(); @@ -428,9 +428,10 @@ void pkgAcqDiffIndex::Done(string Message,unsigned long Size,string Md5Hash, /*{ pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner, string URI,string URIDesc,string ShortDesc, HashString ExpectedHash, + string ServerSha1, vector<DiffInfo> diffs) : Item(Owner), RealURI(URI), ExpectedHash(ExpectedHash), - available_patches(diffs) + available_patches(diffs), ServerSha1(ServerSha1) { DestFile = _config->FindDir("Dir::State::lists") + "partial/"; @@ -516,6 +517,13 @@ bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/ std::clog << "QueueNextDiff: " << FinalFile << " (" << local_sha1 << ")"<<std::endl; + // final file reached before all patches are applied + if(local_sha1 == ServerSha1) + { + Finish(true); + return true; + } + // remove all patches until the next matching patch is found // this requires the Index file to be ordered for(vector<DiffInfo>::iterator I=available_patches.begin(); @@ -613,7 +621,7 @@ void pkgAcqIndexDiffs::Done(string Message,unsigned long Size,string Md5Hash, /* // see if there is more to download if(available_patches.size() > 0) { new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc, - ExpectedHash, available_patches); + ExpectedHash, ServerSha1, available_patches); return Finish(); } else return Finish(true); @@ -1152,7 +1160,7 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/ // Queue Packages file (either diff or full packages files, depending // on the users option) - if(_config->FindB("Acquire::PDiffs",false) == true) + if(_config->FindB("Acquire::PDiffs", true) == true) new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description, (*Target)->ShortDesc, ExpectedIndexHash); else @@ -1371,7 +1379,8 @@ pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources, the archive is already available in the cache and stashs the MD5 for checking later. */ bool pkgAcqArchive::QueueNext() -{ +{ + string const ForceHash = _config->Find("Acquire::ForceHash"); for (; Vf.end() == false; Vf++) { // Ignore not source sources @@ -1394,12 +1403,25 @@ bool pkgAcqArchive::QueueNext() return false; string PkgFile = Parse.FileName(); - if(Parse.SHA256Hash() != "") - ExpectedHash = HashString("SHA256", Parse.SHA256Hash()); - else if (Parse.SHA1Hash() != "") - ExpectedHash = HashString("SHA1", Parse.SHA1Hash()); - else - ExpectedHash = HashString("MD5Sum", Parse.MD5Hash()); + if (ForceHash.empty() == false) + { + if(stringcasecmp(ForceHash, "sha256") == 0) + ExpectedHash = HashString("SHA256", Parse.SHA256Hash()); + else if (stringcasecmp(ForceHash, "sha1") == 0) + ExpectedHash = HashString("SHA1", Parse.SHA1Hash()); + else + ExpectedHash = HashString("MD5Sum", Parse.MD5Hash()); + } + else + { + string Hash; + if ((Hash = Parse.SHA256Hash()).empty() == false) + ExpectedHash = HashString("SHA256", Hash); + else if ((Hash = Parse.SHA1Hash()).empty() == false) + ExpectedHash = HashString("SHA1", Hash); + else + ExpectedHash = HashString("MD5Sum", Parse.MD5Hash()); + } if (PkgFile.empty() == true) return _error->Error(_("The package index files are corrupted. No Filename: " "field for package %s."), @@ -1591,8 +1613,9 @@ void pkgAcqArchive::Finished() /* The file is added to the queue */ pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string Hash, unsigned long Size,string Dsc,string ShortDesc, - const string &DestDir, const string &DestFilename) : - Item(Owner), ExpectedHash(Hash) + const string &DestDir, const string &DestFilename, + bool IsIndexFile) : + Item(Owner), ExpectedHash(Hash), IsIndexFile(IsIndexFile) { Retries = _config->FindI("Acquire::Retries",0); @@ -1707,3 +1730,13 @@ void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf) Item::Failed(Message,Cnf); } /*}}}*/ +// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/ +// --------------------------------------------------------------------- +/* The only header we use is the last-modified header. */ +string pkgAcqFile::Custom600Headers() +{ + if (IsIndexFile) + return "\nIndex-File: true"; + return ""; +} + /*}}}*/ diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h index 06fcffc73..332df5a6b 100644 --- a/apt-pkg/acquire-item.h +++ b/apt-pkg/acquire-item.h @@ -27,6 +27,7 @@ #include <apt-pkg/pkgrecords.h> #include <apt-pkg/indexrecords.h> #include <apt-pkg/hashes.h> +#include <apt-pkg/weakptr.h> /** \addtogroup acquire * @{ @@ -46,7 +47,7 @@ * * \see pkgAcquire */ -class pkgAcquire::Item +class pkgAcquire::Item : public WeakPointable { protected: @@ -434,6 +435,10 @@ class pkgAcqIndexDiffs : public pkgAcquire::Item * off the front? */ vector<DiffInfo> available_patches; + + /** Stop applying patches when reaching that sha1 */ + string ServerSha1; + /** The current status of this patch. */ enum DiffState { @@ -487,6 +492,7 @@ class pkgAcqIndexDiffs : public pkgAcquire::Item */ pkgAcqIndexDiffs(pkgAcquire *Owner,string URI,string URIDesc, string ShortDesc, HashString ExpectedHash, + string ServerSha1, vector<DiffInfo> diffs=vector<DiffInfo>()); }; /*}}}*/ @@ -868,6 +874,9 @@ class pkgAcqFile : public pkgAcquire::Item */ unsigned int Retries; + /** \brief Should this file be considered a index file */ + bool IsIndexFile; + public: // Specialized action members @@ -876,6 +885,7 @@ class pkgAcqFile : public pkgAcquire::Item pkgAcquire::MethodConfig *Cnf); virtual string DescURI() {return Desc.URI;}; virtual string HashSum() {return ExpectedHash.toStr(); }; + virtual string Custom600Headers(); /** \brief Create a new pkgAcqFile object. * @@ -899,6 +909,8 @@ class pkgAcqFile : public pkgAcquire::Item * * \param DestFilename The filename+path the file is downloaded to. * + * \param IsIndexFile The file is considered a IndexFile and cache-control + * headers like "cache-control: max-age=0" are send * * If DestFilename is empty, download to DestDir/<basename> if * DestDir is non-empty, $CWD/<basename> otherwise. If @@ -908,7 +920,8 @@ class pkgAcqFile : public pkgAcquire::Item pkgAcqFile(pkgAcquire *Owner, string URI, string Hash, unsigned long Size, string Desc, string ShortDesc, - const string &DestDir="", const string &DestFilename=""); + const string &DestDir="", const string &DestFilename="", + bool IsIndexFile=false); }; /*}}}*/ /** @} */ diff --git a/apt-pkg/acquire-worker.h b/apt-pkg/acquire-worker.h index 2942df69f..06283922e 100644 --- a/apt-pkg/acquire-worker.h +++ b/apt-pkg/acquire-worker.h @@ -20,6 +20,7 @@ #define PKGLIB_ACQUIRE_WORKER_H #include <apt-pkg/acquire.h> +#include <apt-pkg/weakptr.h> /** \brief A fetch subprocess. @@ -41,7 +42,7 @@ * * \sa pkgAcqMethod, pkgAcquire::Item, pkgAcquire */ -class pkgAcquire::Worker +class pkgAcquire::Worker : public WeakPointable { friend class pkgAcquire; diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc index 74510ae21..832eaa02c 100644 --- a/apt-pkg/acquire.cc +++ b/apt-pkg/acquire.cc @@ -19,6 +19,7 @@ #include <apt-pkg/configuration.h> #include <apt-pkg/error.h> #include <apt-pkg/strutl.h> +#include <apt-pkg/fileutl.h> #include <apti18n.h> @@ -29,7 +30,6 @@ #include <dirent.h> #include <sys/time.h> #include <errno.h> -#include <sys/stat.h> /*}}}*/ using namespace std; @@ -37,32 +37,81 @@ using namespace std; // Acquire::pkgAcquire - Constructor /*{{{*/ // --------------------------------------------------------------------- /* We grab some runtime state from the configuration space */ -pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log) +pkgAcquire::pkgAcquire() : Queues(0), Workers(0), Configs(0), Log(NULL), ToFetch(0), + Debug(_config->FindB("Debug::pkgAcquire",false)), + Running(false), LockFD(-1) { - Queues = 0; - Configs = 0; - Workers = 0; - ToFetch = 0; - Running = false; - - string Mode = _config->Find("Acquire::Queue-Mode","host"); + string const Mode = _config->Find("Acquire::Queue-Mode","host"); if (strcasecmp(Mode.c_str(),"host") == 0) QueueMode = QueueHost; if (strcasecmp(Mode.c_str(),"access") == 0) - QueueMode = QueueAccess; + QueueMode = QueueAccess; +} +pkgAcquire::pkgAcquire(pkgAcquireStatus *Progress) : Queues(0), Workers(0), + Configs(0), Log(Progress), ToFetch(0), + Debug(_config->FindB("Debug::pkgAcquire",false)), + Running(false), LockFD(-1) +{ + string const Mode = _config->Find("Acquire::Queue-Mode","host"); + if (strcasecmp(Mode.c_str(),"host") == 0) + QueueMode = QueueHost; + if (strcasecmp(Mode.c_str(),"access") == 0) + QueueMode = QueueAccess; + Setup(Progress, ""); +} + /*}}}*/ +// Acquire::Setup - Delayed Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* Do everything needed to be a complete Acquire object and report the + success (or failure) back so the user knows that something is wrong… */ +bool pkgAcquire::Setup(pkgAcquireStatus *Progress, string const &Lock) +{ + Log = Progress; - Debug = _config->FindB("Debug::pkgAcquire",false); - - // This is really a stupid place for this - struct stat St; - if (stat((_config->FindDir("Dir::State::lists") + "partial/").c_str(),&St) != 0 || - S_ISDIR(St.st_mode) == 0) - _error->Error(_("Lists directory %spartial is missing."), - _config->FindDir("Dir::State::lists").c_str()); - if (stat((_config->FindDir("Dir::Cache::Archives") + "partial/").c_str(),&St) != 0 || - S_ISDIR(St.st_mode) == 0) - _error->Error(_("Archive directory %spartial is missing."), - _config->FindDir("Dir::Cache::Archives").c_str()); + // check for existence and possibly create auxiliary directories + string const listDir = _config->FindDir("Dir::State::lists"); + string const partialListDir = listDir + "partial/"; + string const archivesDir = _config->FindDir("Dir::Cache::Archives"); + string const partialArchivesDir = archivesDir + "partial/"; + + if (CheckDirectory(_config->FindDir("Dir::State"), partialListDir) == false && + CheckDirectory(listDir, partialListDir) == false) + return _error->Errno("Acquire", _("List directory %spartial is missing."), listDir.c_str()); + + if (CheckDirectory(_config->FindDir("Dir::Cache"), partialArchivesDir) == false && + CheckDirectory(archivesDir, partialArchivesDir) == false) + return _error->Errno("Acquire", _("Archives directory %spartial is missing."), archivesDir.c_str()); + + if (Lock.empty() == true || _config->FindB("Debug::NoLocking", false) == true) + return true; + + // Lock the directory this acquire object will work in + LockFD = GetLock(flCombine(Lock, "lock")); + if (LockFD == -1) + return _error->Error(_("Unable to lock directory %s"), Lock.c_str()); + + return true; +} + /*}}}*/ +// Acquire::CheckDirectory - ensure that the given directory exists /*{{{*/ +// --------------------------------------------------------------------- +/* a small wrapper around CreateDirectory to check if it exists and to + remove the trailing "/apt/" from the parent directory if needed */ +bool pkgAcquire::CheckDirectory(string const &Parent, string const &Path) const +{ + if (DirectoryExists(Path) == true) + return true; + + size_t const len = Parent.size(); + if (len > 5 && Parent.find("/apt/", len - 6, 5) == len - 5) + { + if (CreateDirectory(Parent.substr(0,len-5), Path) == true) + return true; + } + else if (CreateDirectory(Parent, Path) == true) + return true; + + return false; } /*}}}*/ // Acquire::~pkgAcquire - Destructor /*{{{*/ @@ -71,7 +120,10 @@ pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log) pkgAcquire::~pkgAcquire() { Shutdown(); - + + if (LockFD != -1) + close(LockFD); + while (Configs != 0) { MethodConfig *Jnk = Configs; diff --git a/apt-pkg/acquire.h b/apt-pkg/acquire.h index 6c130c1b3..8e2c21151 100644 --- a/apt-pkg/acquire.h +++ b/apt-pkg/acquire.h @@ -66,6 +66,9 @@ #ifndef PKGLIB_ACQUIRE_H #define PKGLIB_ACQUIRE_H +#include <apt-pkg/macros.h> +#include <apt-pkg/weakptr.h> + #include <vector> #include <string> @@ -161,7 +164,7 @@ class pkgAcquire QueueAccess} QueueMode; /** \brief If \b true, debugging information will be dumped to std::clog. */ - bool Debug; + bool const Debug; /** \brief If \b true, a download is currently in progress. */ bool Running; @@ -332,15 +335,22 @@ class pkgAcquire */ double PartialPresent(); - /** \brief Construct a new pkgAcquire. + /** \brief Delayed constructor * - * \param Log The progress indicator associated with this - * download, or \b NULL for none. This object is not owned by the + * \param Progress indicator associated with this download or + * \b NULL for none. This object is not owned by the * download process and will not be deleted when the pkgAcquire * object is destroyed. Naturally, it should live for at least as * long as the pkgAcquire object does. + * \param Lock defines a lock file that should be acquired to ensure + * only one Acquire class is in action at the time or an empty string + * if no lock file should be used. */ - pkgAcquire(pkgAcquireStatus *Log = 0); + bool Setup(pkgAcquireStatus *Progress = NULL, string const &Lock = ""); + + /** \brief Construct a new pkgAcquire. */ + pkgAcquire(pkgAcquireStatus *Log) __deprecated; + pkgAcquire(); /** \brief Destroy this pkgAcquire object. * @@ -348,6 +358,18 @@ class pkgAcquire * this download. */ virtual ~pkgAcquire(); + + private: + /** \brief FD of the Lock file we acquire in Setup (if any) */ + int LockFD; + + /** \brief Ensure the existence of the given Path + * + * \param Parent directory of the Path directory - a trailing + * /apt/ will be removed before CreateDirectory call. + * \param Path which should exist after (successful) call + */ + bool CheckDirectory(string const &Parent, string const &Path) const; }; /** \brief Represents a single download source from which an item @@ -355,7 +377,7 @@ class pkgAcquire * * An item may have several assocated ItemDescs over its lifetime. */ -struct pkgAcquire::ItemDesc +struct pkgAcquire::ItemDesc : public WeakPointable { /** \brief The URI from which to download this item. */ string URI; diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index a3963d546..f17c76d6c 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -83,13 +83,28 @@ void pkgSimulate::Describe(PkgIterator Pkg,ostream &out,bool Current,bool Candid bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/) { // Adapt the iterator - PkgIterator Pkg = Sim.FindPkg(iPkg.Name()); + PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch()); Flags[Pkg->ID] = 1; cout << "Inst "; Describe(Pkg,cout,true,true); Sim.MarkInstall(Pkg,false); - + + if (strcmp(Pkg.Arch(),"all") == 0) + { + pkgCache::GrpIterator G = Pkg.Group(); + pkgCache::GrpIterator iG = iPkg.Group(); + for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P)) + { + if (strcmp(P.Arch(), "all") == 0) + continue; + if (iG.FindPkg(P.Arch())->CurrentVer == 0) + continue; + Flags[P->ID] = 1; + Sim.MarkInstall(P, false); + } + } + // Look for broken conflicts+predepends. for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++) { @@ -131,9 +146,22 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/) bool pkgSimulate::Configure(PkgIterator iPkg) { // Adapt the iterator - PkgIterator Pkg = Sim.FindPkg(iPkg.Name()); + PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch()); Flags[Pkg->ID] = 2; + + if (strcmp(Pkg.Arch(),"all") == 0) + { + pkgCache::GrpIterator G = Pkg.Group(); + for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P)) + { + if (strcmp(P.Arch(), "all") == 0) + continue; + if (Flags[P->ID] == 1) + Flags[P->ID] = 2; + } + } + // Sim.MarkInstall(Pkg,false); if (Sim[Pkg].InstBroken() == true) { @@ -181,10 +209,26 @@ bool pkgSimulate::Configure(PkgIterator iPkg) bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge) { // Adapt the iterator - PkgIterator Pkg = Sim.FindPkg(iPkg.Name()); + PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch()); Flags[Pkg->ID] = 3; Sim.MarkDelete(Pkg); + + if (strcmp(Pkg.Arch(),"all") == 0) + { + pkgCache::GrpIterator G = Pkg.Group(); + pkgCache::GrpIterator iG = iPkg.Group(); + for (pkgCache::PkgIterator P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P)) + { + if (strcmp(P.Arch(), "all") == 0) + continue; + if (iG.FindPkg(P.Arch())->CurrentVer == 0) + continue; + Flags[P->ID] = 3; + Sim.MarkDelete(P); + } + } + if (Purge == true) cout << "Purg "; else @@ -491,11 +535,11 @@ void pkgProblemResolver::MakeScores() // Important Required Standard Optional Extra signed short PrioMap[] = { 0, - _config->FindI("pkgProblemResolver::Scores::Important",3), - _config->FindI("pkgProblemResolver::Scores::Required",2), - _config->FindI("pkgProblemResolver::Scores::Standard",1), - _config->FindI("pkgProblemResolver::Scores::Optional",-1), - _config->FindI("pkgProblemResolver::Scores::Extra",-2) + (signed short) _config->FindI("pkgProblemResolver::Scores::Important",3), + (signed short) _config->FindI("pkgProblemResolver::Scores::Required",2), + (signed short) _config->FindI("pkgProblemResolver::Scores::Standard",1), + (signed short) _config->FindI("pkgProblemResolver::Scores::Optional",-1), + (signed short) _config->FindI("pkgProblemResolver::Scores::Extra",-2) }; signed short PrioEssentials = _config->FindI("pkgProblemResolver::Scores::Essentials",100); signed short PrioInstalledAndNotObsolete = _config->FindI("pkgProblemResolver::Scores::NotObsolete",1); @@ -1353,7 +1397,9 @@ bool ListUpdate(pkgAcquireStatus &Stat, int PulseInterval) { pkgAcquire::RunResult res; - pkgAcquire Fetcher(&Stat); + pkgAcquire Fetcher; + if (Fetcher.Setup(&Stat, _config->FindDir("Dir::State::Lists")) == false) + return false; // Populate it with the source selection if (List.GetIndexes(&Fetcher) == false) diff --git a/apt-pkg/aptconfiguration.cc b/apt-pkg/aptconfiguration.cc index 45ae9bed5..2acf8dd9f 100644 --- a/apt-pkg/aptconfiguration.cc +++ b/apt-pkg/aptconfiguration.cc @@ -8,13 +8,18 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ -#include <apt-pkg/fileutl.h> #include <apt-pkg/aptconfiguration.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/macros.h> +#include <apt-pkg/strutl.h> + +#include <sys/types.h> +#include <dirent.h> -#include <vector> -#include <string> #include <algorithm> +#include <string> +#include <vector> /*}}}*/ namespace APT { // getCompressionTypes - Return Vector of usbale compressiontypes /*{{{*/ @@ -87,4 +92,255 @@ const Configuration::getCompressionTypes(bool const &Cached) { return types; } /*}}}*/ +// GetLanguages - Return Vector of Language Codes /*{{{*/ +// --------------------------------------------------------------------- +/* return a vector of language codes in the prefered order. + the special word "environment" will be replaced with the long and the short + code of the local settings and it will be insured that this will not add + duplicates. So in an german local the setting "environment, de_DE, en, de" + will result in "de_DE, de, en". + The special word "none" is the stopcode for the not-All code vector */ +std::vector<std::string> const Configuration::getLanguages(bool const &All, + bool const &Cached, char const ** const Locale) { + using std::string; + + // The detection is boring and has a lot of cornercases, + // so we cache the results to calculated it only once. + std::vector<string> static allCodes; + std::vector<string> static codes; + + // we have something in the cache + if (codes.empty() == false || allCodes.empty() == false) { + if (Cached == true) { + if(All == true && allCodes.empty() == false) + return allCodes; + else + return codes; + } else { + allCodes.clear(); + codes.clear(); + } + } + + // Include all Language codes we have a Translation file for in /var/lib/apt/lists + // so they will be all included in the Cache. + std::vector<string> builtin; + DIR *D = opendir(_config->FindDir("Dir::State::lists").c_str()); + if (D != 0) { + builtin.push_back("none"); + for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D)) { + string const name = Ent->d_name; + size_t const foundDash = name.rfind("-"); + size_t const foundUnderscore = name.rfind("_"); + if (foundDash == string::npos || foundUnderscore == string::npos || + foundDash <= foundUnderscore || + name.substr(foundUnderscore+1, foundDash-(foundUnderscore+1)) != "Translation") + continue; + string const c = name.substr(foundDash+1); + if (unlikely(c.empty() == true) || c == "en") + continue; + // Skip unusual files, like backups or that alike + string::const_iterator s = c.begin(); + for (;s != c.end(); ++s) { + if (isalpha(*s) == 0) + break; + } + if (s != c.end()) + continue; + if (std::find(builtin.begin(), builtin.end(), c) != builtin.end()) + continue; + builtin.push_back(c); + } + } + closedir(D); + + // get the environment language codes: LC_MESSAGES (and later LANGUAGE) + // we extract both, a long and a short code and then we will + // check if we actually need both (rare) or if the short is enough + string const envMsg = string(Locale == 0 ? std::setlocale(LC_MESSAGES, NULL) : *Locale); + size_t const lenShort = (envMsg.find('_') != string::npos) ? envMsg.find('_') : 2; + size_t const lenLong = (envMsg.find_first_of(".@") != string::npos) ? envMsg.find_first_of(".@") : (lenShort + 3); + + string envLong = envMsg.substr(0,lenLong); + string const envShort = envLong.substr(0,lenShort); + bool envLongIncluded = true; + + // first cornercase: LANG=C, so we use only "en" Translation + if (envLong == "C") { + codes.push_back("en"); + allCodes = codes; + allCodes.insert(allCodes.end(), builtin.begin(), builtin.end()); + if (All == true) + return allCodes; + else + return codes; + } + + // to save the servers from unneeded queries, we only try also long codes + // for languages it is realistic to have a long code translation file… + // TODO: Improve translation acquire system to drop them dynamic + char const *needLong[] = { "cs", "en", "pt", "sv", "zh", NULL }; + if (envLong != envShort) { + for (char const **l = needLong; *l != NULL; l++) + if (envShort.compare(*l) == 0) { + envLongIncluded = false; + break; + } + } + + // we don't add the long code, but we allow the user to do so + if (envLongIncluded == true) + envLong.clear(); + + // FIXME: Remove support for the old APT::Acquire::Translation + // it was undocumented and so it should be not very widthly used + string const oldAcquire = _config->Find("APT::Acquire::Translation",""); + if (oldAcquire.empty() == false && oldAcquire != "environment") { + if (oldAcquire != "none") + codes.push_back(oldAcquire); + codes.push_back("en"); + allCodes = codes; + for (std::vector<string>::const_iterator b = builtin.begin(); + b != builtin.end(); ++b) + if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end()) + allCodes.push_back(*b); + if (All == true) + return allCodes; + else + return codes; + } + + // It is very likely we will need to environment codes later, + // so let us generate them now from LC_MESSAGES and LANGUAGE + std::vector<string> environment; + // take care of LC_MESSAGES + if (envLongIncluded == false) + environment.push_back(envLong); + environment.push_back(envShort); + // take care of LANGUAGE + const char *language_env = getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE"); + string envLang = Locale == 0 ? language_env : *(Locale+1); + if (envLang.empty() == false) { + std::vector<string> env = VectorizeString(envLang,':'); + short addedLangs = 0; // add a maximum of 3 fallbacks from the environment + for (std::vector<string>::const_iterator e = env.begin(); + e != env.end() && addedLangs < 3; ++e) { + if (unlikely(e->empty() == true) || *e == "en") + continue; + if (*e == envLong || *e == envShort) + continue; + if (std::find(environment.begin(), environment.end(), *e) != environment.end()) + continue; + if (e->find('_') != string::npos) { + // Drop LongCodes here - ShortCodes are also included + string const shorty = e->substr(0, e->find('_')); + char const **n = needLong; + for (; *n != NULL; ++n) + if (shorty == *n) + break; + if (*n == NULL) + continue; + } + ++addedLangs; + environment.push_back(*e); + } + } + + // Support settings like Acquire::Translation=none on the command line to + // override the configuration settings vector of languages. + string const forceLang = _config->Find("Acquire::Languages",""); + if (forceLang.empty() == false) { + if (forceLang == "environment") { + codes = environment; + } else if (forceLang != "none") + codes.push_back(forceLang); + allCodes = codes; + for (std::vector<string>::const_iterator b = builtin.begin(); + b != builtin.end(); ++b) + if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end()) + allCodes.push_back(*b); + if (All == true) + return allCodes; + else + return codes; + } + + std::vector<string> const lang = _config->FindVector("Acquire::Languages"); + // the default setting -> "environment, en" + if (lang.empty() == true) { + codes = environment; + if (envShort != "en") + codes.push_back("en"); + allCodes = codes; + for (std::vector<string>::const_iterator b = builtin.begin(); + b != builtin.end(); ++b) + if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end()) + allCodes.push_back(*b); + if (All == true) + return allCodes; + else + return codes; + } + + // the configs define the order, so add the environment + // then needed and ensure the codes are not listed twice. + bool noneSeen = false; + for (std::vector<string>::const_iterator l = lang.begin(); + l != lang.end(); l++) { + if (*l == "environment") { + for (std::vector<string>::const_iterator e = environment.begin(); + e != environment.end(); ++e) { + if (std::find(allCodes.begin(), allCodes.end(), *e) != allCodes.end()) + continue; + if (noneSeen == false) + codes.push_back(*e); + allCodes.push_back(*e); + } + continue; + } else if (*l == "none") { + noneSeen = true; + continue; + } else if (std::find(allCodes.begin(), allCodes.end(), *l) != allCodes.end()) + continue; + + if (noneSeen == false) + codes.push_back(*l); + allCodes.push_back(*l); + } + + for (std::vector<string>::const_iterator b = builtin.begin(); + b != builtin.end(); ++b) + if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end()) + allCodes.push_back(*b); + + if (All == true) + return allCodes; + else + return codes; +} + /*}}}*/ +// getArchitectures - Return Vector of prefered Architectures /*{{{*/ +std::vector<std::string> const Configuration::getArchitectures(bool const &Cached) { + using std::string; + + std::vector<string> static archs; + if (likely(Cached == true) && archs.empty() == false) + return archs; + + string const arch = _config->Find("APT::Architecture"); + archs = _config->FindVector("APT::Architectures"); + if (archs.empty() == true || + std::find(archs.begin(), archs.end(), arch) == archs.end()) + archs.push_back(arch); + return archs; +} + /*}}}*/ +// checkArchitecture - are we interested in the given Architecture? /*{{{*/ +bool const Configuration::checkArchitecture(std::string const &Arch) { + if (Arch == "all") + return true; + std::vector<std::string> const archs = getArchitectures(true); + return (std::find(archs.begin(), archs.end(), Arch) != archs.end()); +} + /*}}}*/ } diff --git a/apt-pkg/aptconfiguration.h b/apt-pkg/aptconfiguration.h index 6a123adce..dd339d841 100644 --- a/apt-pkg/aptconfiguration.h +++ b/apt-pkg/aptconfiguration.h @@ -39,6 +39,49 @@ public: /*{{{*/ * \return a vector of (all) Language Codes in the prefered usage order */ std::vector<std::string> static const getCompressionTypes(bool const &Cached = true); + + /** \brief Returns a vector of Language Codes + * + * Languages can be defined with their two or five chars long code. + * This methods handles the various ways to set the prefered codes, + * honors the environment and ensures that the codes are not listed twice. + * + * The special word "environment" will be replaced with the long and the short + * code of the local settings and it will be insured that this will not add + * duplicates. So in an german local the setting "environment, de_DE, en, de" + * will result in "de_DE, de, en". + * + * Another special word is "none" which separates the prefered from all codes + * in this setting. So setting and method can be used to get codes the user want + * to see or to get all language codes APT (should) have Translations available. + * + * \param All return all codes or only codes for languages we want to use + * \param Cached saves the result so we need to calculated it only once + * this parameter should ony be used for testing purposes. + * \param Locale don't get the locale from the system but use this one instead + * this parameter should ony be used for testing purposes. + * + * \return a vector of (all) Language Codes in the prefered usage order + */ + std::vector<std::string> static const getLanguages(bool const &All = false, + bool const &Cached = true, char const ** const Locale = 0); + + /** \brief Returns a vector of Architectures we support + * + * \param Cached saves the result so we need to calculated it only once + * this parameter should ony be used for testing purposes. + * + * \return a vector of Architectures in prefered order + */ + std::vector<std::string> static const getArchitectures(bool const &Cached = true); + + /** \brief Are we interested in the given Architecture? + * + * \param Arch we want to check + * \return true if we are interested, false otherwise + */ + bool static const checkArchitecture(std::string const &Arch); + /*}}}*/ }; /*}}}*/ diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h index 28466cd40..e2ca74683 100644 --- a/apt-pkg/cacheiterators.h +++ b/apt-pkg/cacheiterators.h @@ -1,6 +1,5 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: cacheiterators.h,v 1.18.2.1 2004/05/08 22:44:27 mdz Exp $ /* ###################################################################### Cache Iterators - Iterators for navigating the cache structure @@ -30,417 +29,385 @@ /*}}}*/ #ifndef PKGLIB_CACHEITERATORS_H #define PKGLIB_CACHEITERATORS_H +// abstract Iterator template /*{{{*/ +/* This template provides the very basic iterator methods we + need to have for doing some walk-over-the-cache magic */ +template<typename Str, typename Itr> class pkgCache::Iterator { + protected: + Str *S; + pkgCache *Owner; + + /** \brief Returns the Pointer for this struct in the owner + * The implementation of this method should be pretty short + * as it will only return the Pointer into the mmap stored + * in the owner but the name of this pointer is different for + * each stucture and we want to abstract here at least for the + * basic methods from the actual structure. + * \return Pointer to the first structure of this type + */ + virtual Str* OwnerPointer() const = 0; + + public: + // Iteration + virtual void operator ++(int) = 0; + virtual void operator ++() = 0; // Should be {operator ++(0);}; + inline bool end() const {return Owner == 0 || S == OwnerPointer();}; + + // Comparison + inline bool operator ==(const Itr &B) const {return S == B.S;}; + inline bool operator !=(const Itr &B) const {return S != B.S;}; + + // Accessors + inline Str *operator ->() {return S;}; + inline Str const *operator ->() const {return S;}; + inline operator Str *() {return S == OwnerPointer() ? 0 : S;}; + inline operator Str const *() const {return S == OwnerPointer() ? 0 : S;}; + inline Str &operator *() {return *S;}; + inline Str const &operator *() const {return *S;}; + inline pkgCache *Cache() {return Owner;}; + + // Mixed stuff + inline void operator =(const Itr &B) {S = B.S; Owner = B.Owner;}; + inline bool IsGood() const { return S && Owner && ! end();}; + inline unsigned long Index() const {return S - OwnerPointer();}; + + // Constructors - look out for the variable assigning + inline Iterator() : S(0), Owner(0) {}; + inline Iterator(pkgCache &Owner,Str *T = 0) : S(T), Owner(&Owner) {}; +}; + /*}}}*/ +// Group Iterator /*{{{*/ +/* Packages with the same name are collected in a Group so someone only + interest in package names can iterate easily over the names, so the + different architectures can be treated as of the "same" package + (apt internally treat them as totally different packages) */ +class pkgCache::GrpIterator: public Iterator<Group, GrpIterator> { + long HashIndex; + + protected: + inline Group* OwnerPointer() const { + return Owner->GrpP; + }; + + public: + // This constructor is the 'begin' constructor, never use it. + inline GrpIterator(pkgCache &Owner) : Iterator<Group, GrpIterator>(Owner), HashIndex(-1) { + S = OwnerPointer(); + operator ++(0); + }; + + virtual void operator ++(int); + virtual void operator ++() {operator ++(0);}; + + inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;}; + inline PkgIterator PackageList() const; + PkgIterator FindPkg(string Arch = "any"); + PkgIterator NextPkg(PkgIterator const &Pkg); + + // Constructors + inline GrpIterator(pkgCache &Owner, Group *Trg) : Iterator<Group, GrpIterator>(Owner, Trg), HashIndex(0) { + if (S == 0) + S = OwnerPointer(); + }; + inline GrpIterator() : Iterator<Group, GrpIterator>(), HashIndex(0) {}; - +}; + /*}}}*/ // Package Iterator /*{{{*/ -class pkgCache::PkgIterator -{ - friend class pkgCache; - Package *Pkg; - pkgCache *Owner; - long HashIndex; - - protected: - - // This constructor is the 'begin' constructor, never use it. - inline PkgIterator(pkgCache &Owner) : Owner(&Owner), HashIndex(-1) - { - Pkg = Owner.PkgP; - operator ++(0); - }; - - public: - - enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure}; - - // Iteration - void operator ++(int); - inline void operator ++() {operator ++(0);}; - inline bool end() const {return Owner == 0 || Pkg == Owner->PkgP?true:false;}; - - // Comparison - inline bool operator ==(const PkgIterator &B) const {return Pkg == B.Pkg;}; - inline bool operator !=(const PkgIterator &B) const {return Pkg != B.Pkg;}; - - // Accessors - inline Package *operator ->() {return Pkg;}; - inline Package const *operator ->() const {return Pkg;}; - inline Package const &operator *() const {return *Pkg;}; - inline operator Package *() {return Pkg == Owner->PkgP?0:Pkg;}; - inline operator Package const *() const {return Pkg == Owner->PkgP?0:Pkg;}; - inline pkgCache *Cache() {return Owner;}; - - inline const char *Name() const {return Pkg->Name == 0?0:Owner->StrP + Pkg->Name;}; - inline const char *Section() const {return Pkg->Section == 0?0:Owner->StrP + Pkg->Section;}; - inline bool Purge() const {return Pkg->CurrentState == pkgCache::State::Purge || - (Pkg->CurrentVer == 0 && Pkg->CurrentState == pkgCache::State::NotInstalled);}; - inline VerIterator VersionList() const; - inline VerIterator CurrentVer() const; - inline DepIterator RevDependsList() const; - inline PrvIterator ProvidesList() const; - inline unsigned long Index() const {return Pkg - Owner->PkgP;}; - OkState State() const; - - //Nice printable representation - friend std::ostream& operator<<(std::ostream& out, pkgCache::PkgIterator Pkg); - - const char *CandVersion() const; - const char *CurVersion() const; - - // Constructors - inline PkgIterator(pkgCache &Owner,Package *Trg) : Pkg(Trg), Owner(&Owner), - HashIndex(0) - { - if (Pkg == 0) - Pkg = Owner.PkgP; - }; - inline PkgIterator() : Pkg(0), Owner(0), HashIndex(0) {}; +class pkgCache::PkgIterator: public Iterator<Package, PkgIterator> { + long HashIndex; + + protected: + inline Package* OwnerPointer() const { + return Owner->PkgP; + }; + + public: + // This constructor is the 'begin' constructor, never use it. + inline PkgIterator(pkgCache &Owner) : Iterator<Package, PkgIterator>(Owner), HashIndex(-1) { + S = OwnerPointer(); + operator ++(0); + }; + + virtual void operator ++(int); + virtual void operator ++() {operator ++(0);}; + + enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure}; + + // Accessors + inline const char *Name() const {return S->Name == 0?0:Owner->StrP + S->Name;}; + inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;}; + inline bool Purge() const {return S->CurrentState == pkgCache::State::Purge || + (S->CurrentVer == 0 && S->CurrentState == pkgCache::State::NotInstalled);}; + inline const char *Arch() const {return S->Arch == 0?0:Owner->StrP + S->Arch;}; + inline GrpIterator Group() const { return GrpIterator(*Owner, Owner->GrpP + S->Group);}; + + inline VerIterator VersionList() const; + inline VerIterator CurrentVer() const; + inline DepIterator RevDependsList() const; + inline PrvIterator ProvidesList() const; + OkState State() const; + const char *CandVersion() const; + const char *CurVersion() const; + + //Nice printable representation + friend std::ostream& operator <<(std::ostream& out, PkgIterator i); + std::string FullName(bool const &Pretty = false) const; + + // Constructors + inline PkgIterator(pkgCache &Owner,Package *Trg) : Iterator<Package, PkgIterator>(Owner, Trg), HashIndex(0) { + if (S == 0) + S = OwnerPointer(); + }; + inline PkgIterator() : Iterator<Package, PkgIterator>(), HashIndex(0) {}; }; /*}}}*/ // Version Iterator /*{{{*/ -class pkgCache::VerIterator -{ - Version *Ver; - pkgCache *Owner; - - void _dummy(); - - public: - - // Iteration - void operator ++(int) {if (Ver != Owner->VerP) Ver = Owner->VerP + Ver->NextVer;}; - inline void operator ++() {operator ++(0);}; - inline bool end() const {return Owner == 0 || (Ver == Owner->VerP?true:false);}; - inline void operator =(const VerIterator &B) {Ver = B.Ver; Owner = B.Owner;}; - - // Comparison - inline bool operator ==(const VerIterator &B) const {return Ver == B.Ver;}; - inline bool operator !=(const VerIterator &B) const {return Ver != B.Ver;}; - int CompareVer(const VerIterator &B) const; - - // Testing - inline bool IsGood() const { return Ver && Owner && ! end();}; - - // Accessors - inline Version *operator ->() {return Ver;}; - inline Version const *operator ->() const {return Ver;}; - inline Version &operator *() {return *Ver;}; - inline Version const &operator *() const {return *Ver;}; - inline operator Version *() {return Ver == Owner->VerP?0:Ver;}; - inline operator Version const *() const {return Ver == Owner->VerP?0:Ver;}; - inline pkgCache *Cache() {return Owner;}; - - inline const char *VerStr() const {return Ver->VerStr == 0?0:Owner->StrP + Ver->VerStr;}; - inline const char *Section() const {return Ver->Section == 0?0:Owner->StrP + Ver->Section;}; - inline const char *Arch() const {return Ver->Arch == 0?0:Owner->StrP + Ver->Arch;}; - inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + Ver->ParentPkg);}; - inline DescIterator DescriptionList() const; - DescIterator TranslatedDescription() const; - inline DepIterator DependsList() const; - inline PrvIterator ProvidesList() const; - inline VerFileIterator FileList() const; - inline unsigned long Index() const {return Ver - Owner->VerP;}; - bool Downloadable() const; - inline const char *PriorityType() {return Owner->Priority(Ver->Priority);}; - string RelStr(); - - bool Automatic() const; - VerFileIterator NewestFile() const; - - inline VerIterator() : Ver(0), Owner(0) {}; - inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Ver(Trg), - Owner(&Owner) - { - if (Ver == 0) - Ver = Owner.VerP; - }; +class pkgCache::VerIterator : public Iterator<Version, VerIterator> { + protected: + inline Version* OwnerPointer() const { + return Owner->VerP; + }; + + public: + // Iteration + void operator ++(int) {if (S != Owner->VerP) S = Owner->VerP + S->NextVer;}; + inline void operator ++() {operator ++(0);}; + + // Comparison + int CompareVer(const VerIterator &B) const; + + // Accessors + inline const char *VerStr() const {return S->VerStr == 0?0:Owner->StrP + S->VerStr;}; + inline const char *Section() const {return S->Section == 0?0:Owner->StrP + S->Section;}; + inline const char *Arch() const { + if(S->MultiArch == pkgCache::Version::All) + return "all"; + return S->ParentPkg == 0?0:Owner->StrP + ParentPkg()->Arch; + }; + inline const char *Arch(bool const pseudo) const { + if(pseudo == false) + return Arch(); + return S->ParentPkg == 0?0:Owner->StrP + ParentPkg()->Arch; + }; + inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);}; + + inline DescIterator DescriptionList() const; + DescIterator TranslatedDescription() const; + inline DepIterator DependsList() const; + inline PrvIterator ProvidesList() const; + inline VerFileIterator FileList() const; + bool Downloadable() const; + inline const char *PriorityType() {return Owner->Priority(S->Priority);}; + string RelStr(); + + bool Automatic() const; + bool Pseudo() const; + VerFileIterator NewestFile() const; + + inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Iterator<Version, VerIterator>(Owner, Trg) { + if (S == 0) + S = OwnerPointer(); + }; + inline VerIterator() : Iterator<Version, VerIterator>() {}; }; /*}}}*/ // Description Iterator /*{{{*/ -class pkgCache::DescIterator -{ - Description *Desc; - pkgCache *Owner; - - void _dummy(); - - public: - - // Iteration - void operator ++(int) {if (Desc != Owner->DescP) Desc = Owner->DescP + Desc->NextDesc;}; - inline void operator ++() {operator ++(0);}; - inline bool end() const {return Owner == 0 || Desc == Owner->DescP?true:false;}; - inline void operator =(const DescIterator &B) {Desc = B.Desc; Owner = B.Owner;}; - - // Comparison - inline bool operator ==(const DescIterator &B) const {return Desc == B.Desc;}; - inline bool operator !=(const DescIterator &B) const {return Desc != B.Desc;}; - int CompareDesc(const DescIterator &B) const; - - // Accessors - inline Description *operator ->() {return Desc;}; - inline Description const *operator ->() const {return Desc;}; - inline Description &operator *() {return *Desc;}; - inline Description const &operator *() const {return *Desc;}; - inline operator Description *() {return Desc == Owner->DescP?0:Desc;}; - inline operator Description const *() const {return Desc == Owner->DescP?0:Desc;}; - inline pkgCache *Cache() {return Owner;}; - - inline const char *LanguageCode() const {return Owner->StrP + Desc->language_code;}; - inline const char *md5() const {return Owner->StrP + Desc->md5sum;}; - inline DescFileIterator FileList() const; - inline unsigned long Index() const {return Desc - Owner->DescP;}; - - inline DescIterator() : Desc(0), Owner(0) {}; - inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Desc(Trg), - Owner(&Owner) - { - if (Desc == 0) - Desc = Owner.DescP; - }; +class pkgCache::DescIterator : public Iterator<Description, DescIterator> { + protected: + inline Description* OwnerPointer() const { + return Owner->DescP; + }; + + public: + // Iteration + void operator ++(int) {if (S != Owner->DescP) S = Owner->DescP + S->NextDesc;}; + inline void operator ++() {operator ++(0);}; + + // Comparison + int CompareDesc(const DescIterator &B) const; + + // Accessors + inline const char *LanguageCode() const {return Owner->StrP + S->language_code;}; + inline const char *md5() const {return Owner->StrP + S->md5sum;}; + inline DescFileIterator FileList() const; + + inline DescIterator() : Iterator<Description, DescIterator>() {}; + inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Iterator<Description, DescIterator>(Owner, Trg) { + if (S == 0) + S = Owner.DescP; + }; }; /*}}}*/ // Dependency iterator /*{{{*/ -class pkgCache::DepIterator -{ - Dependency *Dep; - enum {DepVer, DepRev} Type; - pkgCache *Owner; - - void _dummy(); - - public: - - // Iteration - void operator ++(int) {if (Dep != Owner->DepP) Dep = Owner->DepP + - (Type == DepVer?Dep->NextDepends:Dep->NextRevDepends);}; - inline void operator ++() {operator ++(0);}; - inline bool end() const {return Owner == 0 || Dep == Owner->DepP?true:false;}; - - // Comparison - inline bool operator ==(const DepIterator &B) const {return Dep == B.Dep;}; - inline bool operator !=(const DepIterator &B) const {return Dep != B.Dep;}; - - // Accessors - inline Dependency *operator ->() {return Dep;}; - inline Dependency const *operator ->() const {return Dep;}; - inline Dependency &operator *() {return *Dep;}; - inline Dependency const &operator *() const {return *Dep;}; - inline operator Dependency *() {return Dep == Owner->DepP?0:Dep;}; - inline operator Dependency const *() const {return Dep == Owner->DepP?0:Dep;}; - inline pkgCache *Cache() {return Owner;}; - - inline const char *TargetVer() const {return Dep->Version == 0?0:Owner->StrP + Dep->Version;}; - inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + Dep->Package);}; - inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;}; - inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + Dep->ParentVer);}; - inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Dep->ParentVer].ParentPkg);}; - inline bool Reverse() {return Type == DepRev;}; - inline unsigned long Index() const {return Dep - Owner->DepP;}; - bool IsCritical(); - void GlobOr(DepIterator &Start,DepIterator &End); - Version **AllTargets(); - bool SmartTargetPkg(PkgIterator &Result); - inline const char *CompType() {return Owner->CompType(Dep->CompareOp);}; - inline const char *DepType() {return Owner->DepType(Dep->Type);}; - - inline DepIterator(pkgCache &Owner,Dependency *Trg,Version * = 0) : - Dep(Trg), Type(DepVer), Owner(&Owner) - { - if (Dep == 0) - Dep = Owner.DepP; - }; - inline DepIterator(pkgCache &Owner,Dependency *Trg,Package *) : - Dep(Trg), Type(DepRev), Owner(&Owner) - { - if (Dep == 0) - Dep = Owner.DepP; - }; - inline DepIterator() : Dep(0), Type(DepVer), Owner(0) {}; +class pkgCache::DepIterator : public Iterator<Dependency, DepIterator> { + enum {DepVer, DepRev} Type; + + protected: + inline Dependency* OwnerPointer() const { + return Owner->DepP; + }; + + public: + // Iteration + void operator ++(int) {if (S != Owner->DepP) S = Owner->DepP + + (Type == DepVer ? S->NextDepends : S->NextRevDepends);}; + inline void operator ++() {operator ++(0);}; + + // Accessors + inline const char *TargetVer() const {return S->Version == 0?0:Owner->StrP + S->Version;}; + inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + S->Package);}; + inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner,0);SmartTargetPkg(R);return R;}; + inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + S->ParentVer);}; + inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[S->ParentVer].ParentPkg);}; + inline bool Reverse() {return Type == DepRev;}; + bool IsCritical(); + void GlobOr(DepIterator &Start,DepIterator &End); + Version **AllTargets(); + bool SmartTargetPkg(PkgIterator &Result); + inline const char *CompType() {return Owner->CompType(S->CompareOp);}; + inline const char *DepType() {return Owner->DepType(S->Type);}; + + inline DepIterator(pkgCache &Owner, Dependency *Trg, Version* = 0) : + Iterator<Dependency, DepIterator>(Owner, Trg), Type(DepVer) { + if (S == 0) + S = Owner.DepP; + }; + inline DepIterator(pkgCache &Owner, Dependency *Trg, Package*) : + Iterator<Dependency, DepIterator>(Owner, Trg), Type(DepRev) { + if (S == 0) + S = Owner.DepP; + }; + inline DepIterator() : Iterator<Dependency, DepIterator>(), Type(DepVer) {}; }; /*}}}*/ // Provides iterator /*{{{*/ -class pkgCache::PrvIterator -{ - Provides *Prv; - enum {PrvVer, PrvPkg} Type; - pkgCache *Owner; - - void _dummy(); - - public: - - // Iteration - void operator ++(int) {if (Prv != Owner->ProvideP) Prv = Owner->ProvideP + - (Type == PrvVer?Prv->NextPkgProv:Prv->NextProvides);}; - inline void operator ++() {operator ++(0);}; - inline bool end() const {return Owner == 0 || Prv == Owner->ProvideP?true:false;}; - - // Comparison - inline bool operator ==(const PrvIterator &B) const {return Prv == B.Prv;}; - inline bool operator !=(const PrvIterator &B) const {return Prv != B.Prv;}; - - // Accessors - inline Provides *operator ->() {return Prv;}; - inline Provides const *operator ->() const {return Prv;}; - inline Provides &operator *() {return *Prv;}; - inline Provides const &operator *() const {return *Prv;}; - inline operator Provides *() {return Prv == Owner->ProvideP?0:Prv;}; - inline operator Provides const *() const {return Prv == Owner->ProvideP?0:Prv;}; - inline pkgCache *Cache() {return Owner;}; - - inline const char *Name() const {return Owner->StrP + Owner->PkgP[Prv->ParentPkg].Name;}; - inline const char *ProvideVersion() const {return Prv->ProvideVersion == 0?0:Owner->StrP + Prv->ProvideVersion;}; - inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Prv->ParentPkg);}; - inline VerIterator OwnerVer() {return VerIterator(*Owner,Owner->VerP + Prv->Version);}; - inline PkgIterator OwnerPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Prv->Version].ParentPkg);}; - inline unsigned long Index() const {return Prv - Owner->ProvideP;}; - - inline PrvIterator() : Prv(0), Type(PrvVer), Owner(0) {}; - - inline PrvIterator(pkgCache &Owner,Provides *Trg,Version *) : - Prv(Trg), Type(PrvVer), Owner(&Owner) - { - if (Prv == 0) - Prv = Owner.ProvideP; - }; - inline PrvIterator(pkgCache &Owner,Provides *Trg,Package *) : - Prv(Trg), Type(PrvPkg), Owner(&Owner) - { - if (Prv == 0) - Prv = Owner.ProvideP; - }; +class pkgCache::PrvIterator : public Iterator<Provides, PrvIterator> { + enum {PrvVer, PrvPkg} Type; + + protected: + inline Provides* OwnerPointer() const { + return Owner->ProvideP; + }; + + public: + // Iteration + void operator ++(int) {if (S != Owner->ProvideP) S = Owner->ProvideP + + (Type == PrvVer?S->NextPkgProv:S->NextProvides);}; + inline void operator ++() {operator ++(0);}; + + // Accessors + inline const char *Name() const {return Owner->StrP + Owner->PkgP[S->ParentPkg].Name;}; + inline const char *ProvideVersion() const {return S->ProvideVersion == 0?0:Owner->StrP + S->ProvideVersion;}; + inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + S->ParentPkg);}; + inline VerIterator OwnerVer() {return VerIterator(*Owner,Owner->VerP + S->Version);}; + inline PkgIterator OwnerPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[S->Version].ParentPkg);}; + + inline PrvIterator() : Iterator<Provides, PrvIterator>(), Type(PrvVer) {}; + + inline PrvIterator(pkgCache &Owner, Provides *Trg, Version*) : + Iterator<Provides, PrvIterator>(Owner, Trg), Type(PrvVer) { + if (S == 0) + S = Owner.ProvideP; + }; + inline PrvIterator(pkgCache &Owner, Provides *Trg, Package*) : + Iterator<Provides, PrvIterator>(Owner, Trg), Type(PrvPkg) { + if (S == 0) + S = Owner.ProvideP; + }; }; /*}}}*/ // Package file /*{{{*/ -class pkgCache::PkgFileIterator -{ - pkgCache *Owner; - PackageFile *File; - - public: - - // Iteration - void operator ++(int) {if (File!= Owner->PkgFileP) File = Owner->PkgFileP + File->NextFile;}; - inline void operator ++() {operator ++(0);}; - inline bool end() const {return Owner == 0 || File == Owner->PkgFileP?true:false;}; - - // Comparison - inline bool operator ==(const PkgFileIterator &B) const {return File == B.File;}; - inline bool operator !=(const PkgFileIterator &B) const {return File != B.File;}; - - // Accessors - inline PackageFile *operator ->() {return File;}; - inline PackageFile const *operator ->() const {return File;}; - inline PackageFile const &operator *() const {return *File;}; - inline operator PackageFile *() {return File == Owner->PkgFileP?0:File;}; - inline operator PackageFile const *() const {return File == Owner->PkgFileP?0:File;}; - inline pkgCache *Cache() {return Owner;}; - - inline const char *FileName() const {return File->FileName == 0?0:Owner->StrP + File->FileName;}; - inline const char *Archive() const {return File->Archive == 0?0:Owner->StrP + File->Archive;}; - inline const char *Component() const {return File->Component == 0?0:Owner->StrP + File->Component;}; - inline const char *Version() const {return File->Version == 0?0:Owner->StrP + File->Version;}; - inline const char *Origin() const {return File->Origin == 0?0:Owner->StrP + File->Origin;}; - inline const char *Codename() const {return File->Codename ==0?0:Owner->StrP + File->Codename;}; - inline const char *Label() const {return File->Label == 0?0:Owner->StrP + File->Label;}; - inline const char *Site() const {return File->Site == 0?0:Owner->StrP + File->Site;}; - inline const char *Architecture() const {return File->Architecture == 0?0:Owner->StrP + File->Architecture;}; - inline const char *IndexType() const {return File->IndexType == 0?0:Owner->StrP + File->IndexType;}; - - inline unsigned long Index() const {return File - Owner->PkgFileP;}; - - bool IsOk(); - string RelStr(); - - // Constructors - inline PkgFileIterator() : Owner(0), File(0) {}; - inline PkgFileIterator(pkgCache &Owner) : Owner(&Owner), File(Owner.PkgFileP) {}; - inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Owner(&Owner), File(Trg) {}; +class pkgCache::PkgFileIterator : public Iterator<PackageFile, PkgFileIterator> { + protected: + inline PackageFile* OwnerPointer() const { + return Owner->PkgFileP; + }; + + public: + // Iteration + void operator ++(int) {if (S != Owner->PkgFileP) S = Owner->PkgFileP + S->NextFile;}; + inline void operator ++() {operator ++(0);}; + + // Accessors + inline const char *FileName() const {return S->FileName == 0?0:Owner->StrP + S->FileName;}; + inline const char *Archive() const {return S->Archive == 0?0:Owner->StrP + S->Archive;}; + inline const char *Component() const {return S->Component == 0?0:Owner->StrP + S->Component;}; + inline const char *Version() const {return S->Version == 0?0:Owner->StrP + S->Version;}; + inline const char *Origin() const {return S->Origin == 0?0:Owner->StrP + S->Origin;}; + inline const char *Codename() const {return S->Codename ==0?0:Owner->StrP + S->Codename;}; + inline const char *Label() const {return S->Label == 0?0:Owner->StrP + S->Label;}; + inline const char *Site() const {return S->Site == 0?0:Owner->StrP + S->Site;}; + inline const char *Architecture() const {return S->Architecture == 0?0:Owner->StrP + S->Architecture;}; + inline const char *IndexType() const {return S->IndexType == 0?0:Owner->StrP + S->IndexType;}; + + bool IsOk(); + string RelStr(); + + // Constructors + inline PkgFileIterator() : Iterator<PackageFile, PkgFileIterator>() {}; + inline PkgFileIterator(pkgCache &Owner) : Iterator<PackageFile, PkgFileIterator>(Owner, Owner.PkgFileP) {}; + inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Iterator<PackageFile, PkgFileIterator>(Owner, Trg) {}; }; /*}}}*/ // Version File /*{{{*/ -class pkgCache::VerFileIterator -{ - pkgCache *Owner; - VerFile *FileP; - - public: - - // Iteration - void operator ++(int) {if (FileP != Owner->VerFileP) FileP = Owner->VerFileP + FileP->NextFile;}; - inline void operator ++() {operator ++(0);}; - inline bool end() const {return Owner == 0 || FileP == Owner->VerFileP?true:false;}; - - // Comparison - inline bool operator ==(const VerFileIterator &B) const {return FileP == B.FileP;}; - inline bool operator !=(const VerFileIterator &B) const {return FileP != B.FileP;}; - - // Accessors - inline VerFile *operator ->() {return FileP;}; - inline VerFile const *operator ->() const {return FileP;}; - inline VerFile const &operator *() const {return *FileP;}; - inline operator VerFile *() {return FileP == Owner->VerFileP?0:FileP;}; - inline operator VerFile const *() const {return FileP == Owner->VerFileP?0:FileP;}; - inline pkgCache *Cache() {return Owner;}; - - inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);}; - inline unsigned long Index() const {return FileP - Owner->VerFileP;}; - - inline VerFileIterator() : Owner(0), FileP(0) {}; - inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Owner(&Owner), FileP(Trg) {}; +class pkgCache::VerFileIterator : public pkgCache::Iterator<VerFile, VerFileIterator> { + protected: + inline VerFile* OwnerPointer() const { + return Owner->VerFileP; + }; + + public: + // Iteration + void operator ++(int) {if (S != Owner->VerFileP) S = Owner->VerFileP + S->NextFile;}; + inline void operator ++() {operator ++(0);}; + + // Accessors + inline PkgFileIterator File() const {return PkgFileIterator(*Owner,S->File + Owner->PkgFileP);}; + + inline VerFileIterator() : Iterator<VerFile, VerFileIterator>() {}; + inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Iterator<VerFile, VerFileIterator>(Owner, Trg) {}; }; /*}}}*/ // Description File /*{{{*/ -class pkgCache::DescFileIterator -{ - pkgCache *Owner; - DescFile *FileP; - - public: - - // Iteration - void operator ++(int) {if (FileP != Owner->DescFileP) FileP = Owner->DescFileP + FileP->NextFile;}; - inline void operator ++() {operator ++(0);}; - inline bool end() const {return Owner == 0 || FileP == Owner->DescFileP?true:false;}; - - // Comparison - inline bool operator ==(const DescFileIterator &B) const {return FileP == B.FileP;}; - inline bool operator !=(const DescFileIterator &B) const {return FileP != B.FileP;}; - - // Accessors - inline DescFile *operator ->() {return FileP;}; - inline DescFile const *operator ->() const {return FileP;}; - inline DescFile const &operator *() const {return *FileP;}; - inline operator DescFile *() {return FileP == Owner->DescFileP?0:FileP;}; - inline operator DescFile const *() const {return FileP == Owner->DescFileP?0:FileP;}; - inline pkgCache *Cache() {return Owner;}; - - inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);}; - inline unsigned long Index() const {return FileP - Owner->DescFileP;}; - - inline DescFileIterator() : Owner(0), FileP(0) {}; - inline DescFileIterator(pkgCache &Owner,DescFile *Trg) : Owner(&Owner), FileP(Trg) {}; +class pkgCache::DescFileIterator : public Iterator<DescFile, DescFileIterator> { + protected: + inline DescFile* OwnerPointer() const { + return Owner->DescFileP; + }; + + public: + // Iteration + void operator ++(int) {if (S != Owner->DescFileP) S = Owner->DescFileP + S->NextFile;}; + inline void operator ++() {operator ++(0);}; + + // Accessors + inline PkgFileIterator File() const {return PkgFileIterator(*Owner,S->File + Owner->PkgFileP);}; + + inline DescFileIterator() : Iterator<DescFile, DescFileIterator>() {}; + inline DescFileIterator(pkgCache &Owner,DescFile *Trg) : Iterator<DescFile, DescFileIterator>(Owner, Trg) {}; }; /*}}}*/ // Inlined Begin functions cant be in the class because of order problems /*{{{*/ +inline pkgCache::PkgIterator pkgCache::GrpIterator::PackageList() const + {return PkgIterator(*Owner,Owner->PkgP + S->FirstPackage);}; inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const - {return VerIterator(*Owner,Owner->VerP + Pkg->VersionList);}; + {return VerIterator(*Owner,Owner->VerP + S->VersionList);}; inline pkgCache::VerIterator pkgCache::PkgIterator::CurrentVer() const - {return VerIterator(*Owner,Owner->VerP + Pkg->CurrentVer);}; + {return VerIterator(*Owner,Owner->VerP + S->CurrentVer);}; inline pkgCache::DepIterator pkgCache::PkgIterator::RevDependsList() const - {return DepIterator(*Owner,Owner->DepP + Pkg->RevDepends,Pkg);}; + {return DepIterator(*Owner,Owner->DepP + S->RevDepends,S);}; inline pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const - {return PrvIterator(*Owner,Owner->ProvideP + Pkg->ProvidesList,Pkg);}; + {return PrvIterator(*Owner,Owner->ProvideP + S->ProvidesList,S);}; inline pkgCache::DescIterator pkgCache::VerIterator::DescriptionList() const - {return DescIterator(*Owner,Owner->DescP + Ver->DescriptionList);}; + {return DescIterator(*Owner,Owner->DescP + S->DescriptionList);}; inline pkgCache::PrvIterator pkgCache::VerIterator::ProvidesList() const - {return PrvIterator(*Owner,Owner->ProvideP + Ver->ProvidesList,Ver);}; + {return PrvIterator(*Owner,Owner->ProvideP + S->ProvidesList,S);}; inline pkgCache::DepIterator pkgCache::VerIterator::DependsList() const - {return DepIterator(*Owner,Owner->DepP + Ver->DependsList,Ver);}; + {return DepIterator(*Owner,Owner->DepP + S->DependsList,S);}; inline pkgCache::VerFileIterator pkgCache::VerIterator::FileList() const - {return VerFileIterator(*Owner,Owner->VerFileP + Ver->FileList);}; + {return VerFileIterator(*Owner,Owner->VerFileP + S->FileList);}; inline pkgCache::DescFileIterator pkgCache::DescIterator::FileList() const - {return DescFileIterator(*Owner,Owner->DescFileP + Desc->FileList);}; + {return DescFileIterator(*Owner,Owner->DescFileP + S->FileList);}; /*}}}*/ #endif diff --git a/apt-pkg/cdrom.cc b/apt-pkg/cdrom.cc index 783ffc430..93deb49c4 100644 --- a/apt-pkg/cdrom.cc +++ b/apt-pkg/cdrom.cc @@ -6,6 +6,8 @@ #include<apt-pkg/cdromutl.h> #include<apt-pkg/strutl.h> #include<apt-pkg/cdrom.h> +#include<apt-pkg/aptconfiguration.h> + #include<sstream> #include<fstream> #include<config.h> @@ -216,33 +218,23 @@ int pkgCdrom::Score(string Path) /* Here we drop everything that is not this machines arch */ bool pkgCdrom::DropBinaryArch(vector<string> &List) { - char S[300]; - snprintf(S,sizeof(S),"/binary-%s/", - _config->Find("Apt::Architecture").c_str()); - + for (unsigned int I = 0; I < List.size(); I++) { const char *Str = List[I].c_str(); - - const char *Res; - if ((Res = strstr(Str,"/binary-")) == 0) + const char *Start, *End; + if ((Start = strstr(Str,"/binary-")) == 0) continue; - // Weird, remove it. - if (strlen(Res) < strlen(S)) - { - List.erase(List.begin() + I); - I--; - continue; - } - - // See if it is our arch - if (stringcmp(Res,Res + strlen(S),S) == 0) - continue; - - // Erase it + // Between Start and End is the architecture + Start += 8; + if ((End = strstr(Start,"/")) != 0 && Start != End && + APT::Configuration::checkArchitecture(string(Start, --End)) == true) + continue; // okay, architecture is accepted + + // not accepted -> Erase it List.erase(List.begin() + I); - I--; + --I; // the next entry is at the same index after the erase } return true; diff --git a/apt-pkg/clean.cc b/apt-pkg/clean.cc index 0d1dfbf74..629afd7cf 100644 --- a/apt-pkg/clean.cc +++ b/apt-pkg/clean.cc @@ -12,6 +12,7 @@ #include <apt-pkg/strutl.h> #include <apt-pkg/error.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/aptconfiguration.h> #include <apti18n.h> @@ -26,7 +27,6 @@ bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache) { bool CleanInstalled = _config->FindB("APT::Clean-Installed",true); - string MyArch = _config->Find("APT::Architecture"); DIR *D = opendir(Dir.c_str()); if (D == 0) @@ -75,9 +75,9 @@ bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache) for (I = Start; *I != 0 && *I != '.' ;I++); if (*I != '.') continue; - string Arch = DeQuoteString(string(Start,I-Start)); + string const Arch = DeQuoteString(string(Start,I-Start)); - if (Arch != "all" && Arch != MyArch) + if (APT::Configuration::checkArchitecture(Arch) == false) continue; // Lookup the package diff --git a/apt-pkg/contrib/cmndline.cc b/apt-pkg/contrib/cmndline.cc index bfd53695e..0b16bf51a 100644 --- a/apt-pkg/contrib/cmndline.cc +++ b/apt-pkg/contrib/cmndline.cc @@ -135,7 +135,9 @@ bool CommandLine::Parse(int argc,const char **argv) for (; I != argc; I++) *Files++ = argv[I]; *Files = 0; - + + SaveInConfig(argc, argv); + return true; } /*}}}*/ @@ -351,3 +353,41 @@ bool CommandLine::DispatchArg(Dispatch *Map,bool NoMatch) return false; } /*}}}*/ +// CommandLine::SaveInConfig - for output later in a logfile or so /*{{{*/ +// --------------------------------------------------------------------- +/* We save the commandline here to have it around later for e.g. logging. + It feels a bit like a hack here and isn't bulletproof, but it is better + than nothing after all. */ +void CommandLine::SaveInConfig(unsigned int const &argc, char const * const * const argv) +{ + char cmdline[300]; + unsigned int length = 0; + bool lastWasOption = false; + bool closeQuote = false; + for (unsigned int i = 0; i < argc; ++i, ++length) + { + for (unsigned int j = 0; argv[i][j] != '\0' && length < sizeof(cmdline)-1; ++j, ++length) + { + cmdline[length] = argv[i][j]; + if (lastWasOption == true && argv[i][j] == '=') + { + // That is possibly an option: Quote it if it includes spaces, + // the benefit is that this will eliminate also most false positives + const char* c = &argv[i][j+1]; + for (; *c != '\0' && *c != ' '; ++c); + if (*c == '\0') continue; + cmdline[++length] = '"'; + closeQuote = true; + } + } + if (closeQuote == true) + cmdline[length++] = '"'; + // Problem: detects also --hello + if (cmdline[length-1] == 'o') + lastWasOption = true; + cmdline[length] = ' '; + } + cmdline[--length] = '\0'; + _config->Set("CommandLine::AsString", cmdline); +} + /*}}}*/ diff --git a/apt-pkg/contrib/cmndline.h b/apt-pkg/contrib/cmndline.h index e28071e81..7c0c71aa7 100644 --- a/apt-pkg/contrib/cmndline.h +++ b/apt-pkg/contrib/cmndline.h @@ -60,6 +60,7 @@ class CommandLine Configuration *Conf; bool HandleOpt(int &I,int argc,const char *argv[], const char *&Opt,Args *A,bool PreceedeMatch = false); + void static SaveInConfig(unsigned int const &argc, char const * const * const argv); public: diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc index 8e3b84499..9129d92f0 100644 --- a/apt-pkg/contrib/configuration.cc +++ b/apt-pkg/contrib/configuration.cc @@ -79,7 +79,7 @@ Configuration::~Configuration() /* This will lookup a single item by name below another item. It is a helper function for the main lookup function */ Configuration::Item *Configuration::Lookup(Item *Head,const char *S, - unsigned long Len,bool Create) + unsigned long const &Len,bool const &Create) { int Res = 1; Item *I = Head->Child; @@ -112,7 +112,7 @@ Configuration::Item *Configuration::Lookup(Item *Head,const char *S, // --------------------------------------------------------------------- /* This performs a fully scoped lookup of a given name, possibly creating new items */ -Configuration::Item *Configuration::Lookup(const char *Name,bool Create) +Configuration::Item *Configuration::Lookup(const char *Name,bool const &Create) { if (Name == 0) return Root->Child; @@ -239,7 +239,7 @@ vector<string> Configuration::FindVector(const char *Name) const // Configuration::FindI - Find an integer value /*{{{*/ // --------------------------------------------------------------------- /* */ -int Configuration::FindI(const char *Name,int Default) const +int Configuration::FindI(const char *Name,int const &Default) const { const Item *Itm = Lookup(Name); if (Itm == 0 || Itm->Value.empty() == true) @@ -256,7 +256,7 @@ int Configuration::FindI(const char *Name,int Default) const // Configuration::FindB - Find a boolean type /*{{{*/ // --------------------------------------------------------------------- /* */ -bool Configuration::FindB(const char *Name,bool Default) const +bool Configuration::FindB(const char *Name,bool const &Default) const { const Item *Itm = Lookup(Name); if (Itm == 0 || Itm->Value.empty() == true) @@ -332,7 +332,7 @@ void Configuration::Set(const char *Name,const string &Value) // Configuration::Set - Set an integer value /*{{{*/ // --------------------------------------------------------------------- /* */ -void Configuration::Set(const char *Name,int Value) +void Configuration::Set(const char *Name,int const &Value) { Item *Itm = Lookup(Name,true); if (Itm == 0) @@ -345,7 +345,7 @@ void Configuration::Set(const char *Name,int Value) // Configuration::Clear - Clear an single value from a list /*{{{*/ // --------------------------------------------------------------------- /* */ -void Configuration::Clear(const string Name, int Value) +void Configuration::Clear(string const &Name, int const &Value) { char S[300]; snprintf(S,sizeof(S),"%i",Value); @@ -355,7 +355,7 @@ void Configuration::Clear(const string Name, int Value) // Configuration::Clear - Clear an single value from a list /*{{{*/ // --------------------------------------------------------------------- /* */ -void Configuration::Clear(const string Name, string Value) +void Configuration::Clear(string const &Name, string const &Value) { Item *Top = Lookup(Name.c_str(),false); if (Top == 0 || Top->Child == 0) @@ -386,7 +386,7 @@ void Configuration::Clear(const string Name, string Value) // Configuration::Clear - Clear an entire tree /*{{{*/ // --------------------------------------------------------------------- /* */ -void Configuration::Clear(string Name) +void Configuration::Clear(string const &Name) { Item *Top = Lookup(Name.c_str(),false); if (Top == 0) @@ -501,8 +501,8 @@ string Configuration::Item::FullTag(const Item *Stop) const sections like 'zone "foo.org" { .. };' This causes each section to be added in with a tag like "zone::foo.org" instead of being split tag/value. AsSectional enables Sectional parsing.*/ -bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional, - unsigned Depth) +bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectional, + unsigned const &Depth) { // Open the stream for reading ifstream F(FName.c_str(),ios::in); @@ -773,6 +773,8 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional, else return _error->Error(_("Syntax error %s:%u: Unsupported directive '%s'"),FName.c_str(),CurLine,Tag.c_str()); } + else if (Tag.empty() == true && NoWord == false && Word == "#clear") + return _error->Error(_("Syntax error %s:%u: clear directive requires an option tree as argument"),FName.c_str(),CurLine); else { // Set the item in the configuration class @@ -830,7 +832,7 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional, // --------------------------------------------------------------------- /* */ bool ReadConfigDir(Configuration &Conf,const string &Dir, - bool AsSectional, unsigned Depth) + bool const &AsSectional, unsigned const &Depth) { vector<string> const List = GetListOfFilesInDir(Dir, "conf", true, true); diff --git a/apt-pkg/contrib/configuration.h b/apt-pkg/contrib/configuration.h index e2da83f5b..2494c1d7c 100644 --- a/apt-pkg/contrib/configuration.h +++ b/apt-pkg/contrib/configuration.h @@ -58,8 +58,8 @@ class Configuration Item *Root; bool ToFree; - Item *Lookup(Item *Head,const char *S,unsigned long Len,bool Create); - Item *Lookup(const char *Name,bool Create); + Item *Lookup(Item *Head,const char *S,unsigned long const &Len,bool const &Create); + Item *Lookup(const char *Name,const bool &Create); inline const Item *Lookup(const char *Name) const { return ((Configuration *)this)->Lookup(Name,false); @@ -68,32 +68,33 @@ class Configuration public: string Find(const char *Name,const char *Default = 0) const; - string Find(const string Name,const char *Default = 0) const {return Find(Name.c_str(),Default);}; + string Find(string const &Name,const char *Default = 0) const {return Find(Name.c_str(),Default);}; + string Find(string const &Name, string const &Default) const {return Find(Name.c_str(),Default.c_str());}; string FindFile(const char *Name,const char *Default = 0) const; string FindDir(const char *Name,const char *Default = 0) const; - std::vector<string> FindVector(const string &Name) const; + std::vector<string> FindVector(string const &Name) const; std::vector<string> FindVector(const char *Name) const; - int FindI(const char *Name,int Default = 0) const; - int FindI(const string Name,int Default = 0) const {return FindI(Name.c_str(),Default);}; - bool FindB(const char *Name,bool Default = false) const; - bool FindB(const string Name,bool Default = false) const {return FindB(Name.c_str(),Default);}; + int FindI(const char *Name,int const &Default = 0) const; + int FindI(string const &Name,int const &Default = 0) const {return FindI(Name.c_str(),Default);}; + bool FindB(const char *Name,bool const &Default = false) const; + bool FindB(string const &Name,bool const &Default = false) const {return FindB(Name.c_str(),Default);}; string FindAny(const char *Name,const char *Default = 0) const; - inline void Set(const string Name,string Value) {Set(Name.c_str(),Value);}; + inline void Set(const string &Name,const string &Value) {Set(Name.c_str(),Value);}; void CndSet(const char *Name,const string &Value); void Set(const char *Name,const string &Value); - void Set(const char *Name,int Value); + void Set(const char *Name,const int &Value); - inline bool Exists(const string Name) const {return Exists(Name.c_str());}; + inline bool Exists(const string &Name) const {return Exists(Name.c_str());}; bool Exists(const char *Name) const; bool ExistsAny(const char *Name) const; // clear a whole tree - void Clear(const string Name); + void Clear(const string &Name); // remove a certain value from a list (e.g. the list of "APT::Keep-Fds") - void Clear(const string List, string Value); - void Clear(const string List, int Value); + void Clear(string const &List, string const &Value); + void Clear(string const &List, int const &Value); inline const Item *Tree(const char *Name) const {return Lookup(Name);}; @@ -108,11 +109,11 @@ class Configuration extern Configuration *_config; bool ReadConfigFile(Configuration &Conf,const string &FName, - bool AsSectional = false, - unsigned Depth = 0); + bool const &AsSectional = false, + unsigned const &Depth = 0); bool ReadConfigDir(Configuration &Conf,const string &Dir, - bool AsSectional = false, - unsigned Depth = 0); + bool const &AsSectional = false, + unsigned const &Depth = 0); #endif diff --git a/apt-pkg/contrib/error.h b/apt-pkg/contrib/error.h index 90747ff7e..8d5ec05ea 100644 --- a/apt-pkg/contrib/error.h +++ b/apt-pkg/contrib/error.h @@ -60,13 +60,13 @@ class GlobalError public: // Call to generate an error from a library call. - bool Errno(const char *Function,const char *Description,...) __like_printf_2 __cold; - bool WarningE(const char *Function,const char *Description,...) __like_printf_2 __cold; + bool Errno(const char *Function,const char *Description,...) __like_printf(3) __cold; + bool WarningE(const char *Function,const char *Description,...) __like_printf(3) __cold; /* A warning should be considered less severe than an error, and may be ignored by the client. */ - bool Error(const char *Description,...) __like_printf_1 __cold; - bool Warning(const char *Description,...) __like_printf_1 __cold; + bool Error(const char *Description,...) __like_printf(2) __cold; + bool Warning(const char *Description,...) __like_printf(2) __cold; // Simple accessors inline bool PendingError() {return PendingFlag;}; diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index da32983f1..16f7ce929 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -18,6 +18,7 @@ /*}}}*/ // Include Files /*{{{*/ #include <apt-pkg/fileutl.h> +#include <apt-pkg/strutl.h> #include <apt-pkg/error.h> #include <apt-pkg/sptr.h> #include <apt-pkg/configuration.h> @@ -197,16 +198,62 @@ bool FileExists(string File) return true; } /*}}}*/ +// DirectoryExists - Check if a directory exists and is really one /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool DirectoryExists(string const &Path) +{ + struct stat Buf; + if (stat(Path.c_str(),&Buf) != 0) + return false; + return ((Buf.st_mode & S_IFDIR) != 0); +} + /*}}}*/ +// CreateDirectory - poor man's mkdir -p guarded by a parent directory /*{{{*/ +// --------------------------------------------------------------------- +/* This method will create all directories needed for path in good old + mkdir -p style but refuses to do this if Parent is not a prefix of + this Path. Example: /var/cache/ and /var/cache/apt/archives are given, + so it will create apt/archives if /var/cache exists - on the other + hand if the parent is /var/lib the creation will fail as this path + is not a parent of the path to be generated. */ +bool CreateDirectory(string const &Parent, string const &Path) +{ + if (Parent.empty() == true || Path.empty() == true) + return false; + + if (DirectoryExists(Path) == true) + return true; + + if (DirectoryExists(Parent) == false) + return false; + + // we are not going to create directories "into the blue" + if (Path.find(Parent, 0) != 0) + return false; + + vector<string> const dirs = VectorizeString(Path.substr(Parent.size()), '/'); + string progress = Parent; + for (vector<string>::const_iterator d = dirs.begin(); d != dirs.end(); ++d) + { + if (d->empty() == true) + continue; + + progress.append("/").append(*d); + if (DirectoryExists(progress) == true) + continue; + + if (mkdir(progress.c_str(), 0755) != 0) + return false; + } + return true; +} + /*}}}*/ // GetListOfFilesInDir - returns a vector of files in the given dir /*{{{*/ // --------------------------------------------------------------------- /* If an extension is given only files with this extension are included in the returned vector, otherwise every "normal" file is included. */ std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext, - bool const &SortList) -{ - return GetListOfFilesInDir(Dir, Ext, SortList, false); -} -std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext, bool const &SortList, bool const &AllowNoExt) { std::vector<string> ext; diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index 85a94898c..003bd9b83 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -21,6 +21,7 @@ #ifndef PKGLIB_FILEUTL_H #define PKGLIB_FILEUTL_H +#include <apt-pkg/macros.h> #include <string> #include <vector> @@ -82,11 +83,10 @@ bool RunScripts(const char *Cnf); bool CopyFile(FileFd &From,FileFd &To); int GetLock(string File,bool Errors = true); bool FileExists(string File); -// FIXME: next ABI-Break: merge the two method-headers +bool DirectoryExists(string const &Path) __attrib_const; +bool CreateDirectory(string const &Parent, string const &Path); std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext, - bool const &SortList); -std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext, - bool const &SortList, bool const &AllowNoExt); + bool const &SortList, bool const &AllowNoExt=false); std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> const &Ext, bool const &SortList); string SafeGetCWD(); diff --git a/apt-pkg/contrib/macros.h b/apt-pkg/contrib/macros.h index 9aeb77b81..62e7b65db 100644 --- a/apt-pkg/contrib/macros.h +++ b/apt-pkg/contrib/macros.h @@ -56,33 +56,35 @@ // some nice optional GNUC features #if __GNUC__ >= 3 - #define __must_check __attribute__ ((warn_unused_result)) - #define __deprecated __attribute__ ((deprecated)) - /* likely() and unlikely() can be used to mark boolean expressions - as (not) likely true which will help the compiler to optimise */ - #define likely(x) __builtin_expect (!!(x), 1) - #define unlikely(x) __builtin_expect (!!(x), 0) + #define __must_check __attribute__ ((warn_unused_result)) + #define __deprecated __attribute__ ((deprecated)) + #define __attrib_const __attribute__ ((__const__)) + /* likely() and unlikely() can be used to mark boolean expressions + as (not) likely true which will help the compiler to optimise */ + #define likely(x) __builtin_expect (!!(x), 1) + #define unlikely(x) __builtin_expect (!!(x), 0) #else - #define __must_check /* no warn_unused_result */ - #define __deprecated /* no deprecated */ - #define likely(x) (x) - #define unlikely(x) (x) + #define __must_check /* no warn_unused_result */ + #define __deprecated /* no deprecated */ + #define __attrib_const /* no const attribute */ + #define likely(x) (x) + #define unlikely(x) (x) #endif // cold functions are unlikely() to be called #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4 - #define __cold __attribute__ ((__cold__)) + #define __cold __attribute__ ((__cold__)) + #define __hot __attribute__ ((__hot__)) #else - #define __cold /* no cold marker */ + #define __cold /* no cold marker */ + #define __hot /* no hot marker */ #endif #ifdef __GNUG__ // Methods have a hidden this parameter that is visible to this attribute - #define __like_printf_1 __attribute__ ((format (printf, 2, 3))) - #define __like_printf_2 __attribute__ ((format (printf, 3, 4))) + #define __like_printf(n) __attribute__((format(printf, n, n + 1))) #else - #define __like_printf_1 - #define __like_printf_2 + #define __like_printf(n) /* no like-printf */ #endif #endif diff --git a/apt-pkg/contrib/mmap.cc b/apt-pkg/contrib/mmap.cc index 4d5fcf71e..d233e51bc 100644 --- a/apt-pkg/contrib/mmap.cc +++ b/apt-pkg/contrib/mmap.cc @@ -27,6 +27,7 @@ #include <unistd.h> #include <fcntl.h> #include <stdlib.h> +#include <errno.h> #include <cstring> /*}}}*/ @@ -35,7 +36,7 @@ // --------------------------------------------------------------------- /* */ MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0), - Base(0) + Base(0), SyncToFd(NULL) { if ((Flags & NoImmMap) != NoImmMap) Map(F); @@ -45,7 +46,7 @@ MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0), // --------------------------------------------------------------------- /* */ MMap::MMap(unsigned long Flags) : Flags(Flags), iSize(0), - Base(0) + Base(0), SyncToFd(NULL) { } /*}}}*/ @@ -78,7 +79,24 @@ bool MMap::Map(FileFd &Fd) // Map it. Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0); if (Base == (void *)-1) - return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),iSize); + { + if (errno == ENODEV || errno == EINVAL) + { + // The filesystem doesn't support this particular kind of mmap. + // So we allocate a buffer and read the whole file into it. + int const dupped_fd = dup(Fd.Fd()); + if (dupped_fd == -1) + return _error->Errno("mmap", _("Couldn't duplicate file descriptor %i"), Fd.Fd()); + + Base = new unsigned char[iSize]; + SyncToFd = new FileFd (dupped_fd); + if (!SyncToFd->Seek(0L) || !SyncToFd->Read(Base, iSize)) + return false; + } + else + return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"), + iSize); + } return true; } @@ -93,10 +111,19 @@ bool MMap::Close(bool DoSync) if (DoSync == true) Sync(); - - if (munmap((char *)Base,iSize) != 0) - _error->Warning("Unable to munmap"); - + + if (SyncToFd != NULL) + { + delete[] (char *)Base; + delete SyncToFd; + SyncToFd = NULL; + } + else + { + if (munmap((char *)Base, iSize) != 0) + _error->WarningE("mmap", _("Unable to close mmap")); + } + iSize = 0; Base = 0; return true; @@ -113,8 +140,18 @@ bool MMap::Sync() #ifdef _POSIX_SYNCHRONIZED_IO if ((Flags & ReadOnly) != ReadOnly) - if (msync((char *)Base,iSize,MS_SYNC) < 0) - return _error->Errno("msync","Unable to write mmap"); + { + if (SyncToFd != NULL) + { + if (!SyncToFd->Seek(0) || !SyncToFd->Write(Base, iSize)) + return false; + } + else + { + if (msync((char *)Base, iSize, MS_SYNC) < 0) + return _error->Errno("msync", _("Unable to synchronize mmap")); + } + } #endif return true; } @@ -130,8 +167,19 @@ bool MMap::Sync(unsigned long Start,unsigned long Stop) #ifdef _POSIX_SYNCHRONIZED_IO unsigned long PSize = sysconf(_SC_PAGESIZE); if ((Flags & ReadOnly) != ReadOnly) - if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) < 0) - return _error->Errno("msync","Unable to write mmap"); + { + if (SyncToFd != 0) + { + if (!SyncToFd->Seek(0) || + !SyncToFd->Write (((char *)Base)+Start, Stop-Start)) + return false; + } + else + { + if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) < 0) + return _error->Errno("msync", _("Unable to synchronize mmap")); + } + } #endif return true; } @@ -140,8 +188,10 @@ bool MMap::Sync(unsigned long Start,unsigned long Stop) // DynamicMMap::DynamicMMap - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace) : - MMap(F,Flags | NoImmMap), Fd(&F), WorkSpace(WorkSpace) +DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long const &Workspace, + unsigned long const &Grow, unsigned long const &Limit) : + MMap(F,Flags | NoImmMap), Fd(&F), WorkSpace(Workspace), + GrowFactor(Grow), Limit(Limit) { if (_error->PendingError() == true) return; @@ -165,32 +215,48 @@ DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace) /* We try here to use mmap to reserve some space - this is much more cooler than the fallback solution to simply allocate a char array and could come in handy later than we are able to grow such an mmap */ -DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long WorkSpace) : - MMap(Flags | NoImmMap | UnMapped), Fd(0), WorkSpace(WorkSpace) +DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long const &WorkSpace, + unsigned long const &Grow, unsigned long const &Limit) : + MMap(Flags | NoImmMap | UnMapped), Fd(0), WorkSpace(WorkSpace), + GrowFactor(Grow), Limit(Limit) { - if (_error->PendingError() == true) - return; + if (_error->PendingError() == true) + return; + + // disable Moveable if we don't grow + if (Grow == 0) + Flags &= ~Moveable; + +#ifndef __linux__ + // kfreebsd doesn't have mremap, so we use the fallback + if ((Flags & Moveable) == Moveable) + Flags |= Fallback; +#endif #ifdef _POSIX_MAPPED_FILES - // Set the permissions. - int Prot = PROT_READ; - int Map = MAP_PRIVATE | MAP_ANONYMOUS; - if ((Flags & ReadOnly) != ReadOnly) - Prot |= PROT_WRITE; - if ((Flags & Public) == Public) - Map = MAP_SHARED | MAP_ANONYMOUS; + if ((Flags & Fallback) != Fallback) { + // Set the permissions. + int Prot = PROT_READ; + int Map = MAP_PRIVATE | MAP_ANONYMOUS; + if ((Flags & ReadOnly) != ReadOnly) + Prot |= PROT_WRITE; + if ((Flags & Public) == Public) + Map = MAP_SHARED | MAP_ANONYMOUS; - // use anonymous mmap() to get the memory - Base = (unsigned char*) mmap(0, WorkSpace, Prot, Map, -1, 0); + // use anonymous mmap() to get the memory + Base = (unsigned char*) mmap(0, WorkSpace, Prot, Map, -1, 0); - if(Base == MAP_FAILED) - _error->Errno("DynamicMMap",_("Couldn't make mmap of %lu bytes"),WorkSpace); -#else - // fallback to a static allocated space - Base = new unsigned char[WorkSpace]; - memset(Base,0,WorkSpace); + if(Base == MAP_FAILED) + _error->Errno("DynamicMMap",_("Couldn't make mmap of %lu bytes"),WorkSpace); + + iSize = 0; + return; + } #endif - iSize = 0; + // fallback to a static allocated space + Base = new unsigned char[WorkSpace]; + memset(Base,0,WorkSpace); + iSize = 0; } /*}}}*/ // DynamicMMap::~DynamicMMap - Destructor /*{{{*/ @@ -311,30 +377,55 @@ unsigned long DynamicMMap::WriteString(const char *String, /*}}}*/ // DynamicMMap::Grow - Grow the mmap /*{{{*/ // --------------------------------------------------------------------- -/* This method will try to grow the mmap we currently use. This doesn't - work most of the time because we can't move the mmap around in the - memory for now as this would require to adjust quite a lot of pointers - but why we should not at least try to grow it before we give up? */ -bool DynamicMMap::Grow() -{ -#if defined(_POSIX_MAPPED_FILES) && defined(__linux__) - unsigned long newSize = WorkSpace + 1024*1024; +/* This method is a wrapper around different methods to (try to) grow + a mmap (or our char[]-fallback). Encounterable environments: + 1. Moveable + !Fallback + linux -> mremap with MREMAP_MAYMOVE + 2. Moveable + !Fallback + !linux -> not possible (forbidden by constructor) + 3. Moveable + Fallback -> realloc + 4. !Moveable + !Fallback + linux -> mremap alone - which will fail in 99,9% + 5. !Moveable + !Fallback + !linux -> not possible (forbidden by constructor) + 6. !Moveable + Fallback -> not possible + [ While Moveable and Fallback stands for the equally named flags and + "linux" indicates a linux kernel instead of a freebsd kernel. ] + So what you can see here is, that a MMAP which want to be growable need + to be moveable to have a real chance but that this method will at least try + the nearly impossible 4 to grow it before it finally give up: Never say never. */ +bool DynamicMMap::Grow() { + if (Limit != 0 && WorkSpace >= Limit) + return _error->Error(_("Unable to increase the size of the MMap as the " + "limit of %lu bytes is already reached."), Limit); - if(Fd != 0) - { - Fd->Seek(newSize - 1); - char C = 0; - Fd->Write(&C,sizeof(C)); - } + unsigned long const newSize = WorkSpace + 1024*1024; - Base = mremap(Base, WorkSpace, newSize, 0); - if(Base == MAP_FAILED) - return false; + if(Fd != 0) { + Fd->Seek(newSize - 1); + char C = 0; + Fd->Write(&C,sizeof(C)); + } + if ((Flags & Fallback) != Fallback) { +#if defined(_POSIX_MAPPED_FILES) && defined(__linux__) + #ifdef MREMAP_MAYMOVE + if ((Flags & Moveable) == Moveable) + Base = mremap(Base, WorkSpace, newSize, MREMAP_MAYMOVE); + else + #endif + Base = mremap(Base, WorkSpace, newSize, 0); - WorkSpace = newSize; - return true; + if(Base == MAP_FAILED) + return false; #else - return false; + return false; #endif + } else { + if ((Flags & Moveable) != Moveable) + return false; + + Base = realloc(Base, newSize); + if (Base == NULL) + return false; + } + + WorkSpace = newSize; + return true; } /*}}}*/ diff --git a/apt-pkg/contrib/mmap.h b/apt-pkg/contrib/mmap.h index bde62217d..5ca951204 100644 --- a/apt-pkg/contrib/mmap.h +++ b/apt-pkg/contrib/mmap.h @@ -44,13 +44,18 @@ class MMap unsigned long iSize; void *Base; + // In case mmap can not be used, we keep a dup of the file + // descriptor that should have been mmaped so that we can write to + // the file in Sync(). + FileFd *SyncToFd; + bool Map(FileFd &Fd); bool Close(bool DoSync = true); public: enum OpenFlags {NoImmMap = (1<<0),Public = (1<<1),ReadOnly = (1<<2), - UnMapped = (1<<3)}; + UnMapped = (1<<3), Moveable = (1<<4), Fallback = (1 << 5)}; // Simple accessors inline operator void *() {return Base;}; @@ -82,6 +87,8 @@ class DynamicMMap : public MMap FileFd *Fd; unsigned long WorkSpace; + unsigned long const GrowFactor; + unsigned long const Limit; Pool *Pools; unsigned int PoolCount; @@ -96,8 +103,10 @@ class DynamicMMap : public MMap inline unsigned long WriteString(const string &S) {return WriteString(S.c_str(),S.length());}; void UsePools(Pool &P,unsigned int Count) {Pools = &P; PoolCount = Count;}; - DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace = 2*1024*1024); - DynamicMMap(unsigned long Flags,unsigned long WorkSpace = 2*1024*1024); + DynamicMMap(FileFd &F,unsigned long Flags,unsigned long const &WorkSpace = 2*1024*1024, + unsigned long const &Grow = 1024*1024, unsigned long const &Limit = 0); + DynamicMMap(unsigned long Flags,unsigned long const &WorkSpace = 2*1024*1024, + unsigned long const &Grow = 1024*1024, unsigned long const &Limit = 0); virtual ~DynamicMMap(); }; diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index b54758632..c7d63ce8a 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -574,7 +574,7 @@ int stringcmp(string::const_iterator A,string::const_iterator AEnd, int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd) { for (; A != AEnd && B != BEnd; A++, B++) - if (toupper(*A) != toupper(*B)) + if (tolower_ascii(*A) != tolower_ascii(*B)) break; if (A == AEnd && B == BEnd) @@ -583,7 +583,7 @@ int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd) return 1; if (B == BEnd) return -1; - if (toupper(*A) < toupper(*B)) + if (tolower_ascii(*A) < tolower_ascii(*B)) return -1; return 1; } @@ -592,7 +592,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd, const char *B,const char *BEnd) { for (; A != AEnd && B != BEnd; A++, B++) - if (toupper(*A) != toupper(*B)) + if (tolower_ascii(*A) != tolower_ascii(*B)) break; if (A == AEnd && B == BEnd) @@ -601,7 +601,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd, return 1; if (B == BEnd) return -1; - if (toupper(*A) < toupper(*B)) + if (tolower_ascii(*A) < tolower_ascii(*B)) return -1; return 1; } @@ -609,7 +609,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd, string::const_iterator B,string::const_iterator BEnd) { for (; A != AEnd && B != BEnd; A++, B++) - if (toupper(*A) != toupper(*B)) + if (tolower_ascii(*A) != tolower_ascii(*B)) break; if (A == AEnd && B == BEnd) @@ -618,7 +618,7 @@ int stringcasecmp(string::const_iterator A,string::const_iterator AEnd, return 1; if (B == BEnd) return -1; - if (toupper(*A) < toupper(*B)) + if (tolower_ascii(*A) < tolower_ascii(*B)) return -1; return 1; } @@ -797,28 +797,28 @@ bool ReadMessages(int Fd, vector<string> &List) // MonthConv - Converts a month string into a number /*{{{*/ // --------------------------------------------------------------------- /* This was lifted from the boa webserver which lifted it from 'wn-v1.07' - Made it a bit more robust with a few touppers though. */ + Made it a bit more robust with a few tolower_ascii though. */ static int MonthConv(char *Month) { - switch (toupper(*Month)) + switch (tolower_ascii(*Month)) { - case 'A': - return toupper(Month[1]) == 'P'?3:7; - case 'D': + case 'a': + return tolower_ascii(Month[1]) == 'p'?3:7; + case 'd': return 11; - case 'F': + case 'f': return 1; - case 'J': - if (toupper(Month[1]) == 'A') + case 'j': + if (tolower_ascii(Month[1]) == 'a') return 0; - return toupper(Month[2]) == 'N'?5:6; - case 'M': - return toupper(Month[2]) == 'R'?2:4; - case 'N': + return tolower_ascii(Month[2]) == 'n'?5:6; + case 'm': + return tolower_ascii(Month[2]) == 'r'?2:4; + case 'n': return 10; - case 'O': + case 'o': return 9; - case 'S': + case 's': return 8; // Pretend it is January.. @@ -1008,6 +1008,24 @@ bool TokSplitString(char Tok,char *Input,char **List, return true; } /*}}}*/ +// VectorizeString - Split a string up into a vector of strings /*{{{*/ +// --------------------------------------------------------------------- +/* This can be used to split a given string up into a vector, so the + propose is the same as in the method above and this one is a bit slower + also, but the advantage is that we have an iteratable vector */ +vector<string> VectorizeString(string const &haystack, char const &split) +{ + string::const_iterator start = haystack.begin(); + string::const_iterator end = start; + vector<string> exploded; + do { + for (; end != haystack.end() && *end != split; ++end); + exploded.push_back(string(start, end)); + start = end + 1; + } while (end != haystack.end() && (++end) != haystack.end()); + return exploded; +} + /*}}}*/ // RegexChoice - Simple regex list/list matcher /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -1123,10 +1141,13 @@ char *safe_snprintf(char *Buffer,char *End,const char *Format,...) // tolower_ascii - tolower() function that ignores the locale /*{{{*/ // --------------------------------------------------------------------- -/* */ -int tolower_ascii(int c) +/* This little function is the most called method we have and tries + therefore to do the absolut minimum - and is noteable faster than + standard tolower/toupper and as a bonus avoids problems with different + locales - we only operate on ascii chars anyway. */ +int tolower_ascii(int const c) { - if (c >= 'A' and c <= 'Z') + if (c >= 'A' && c <= 'Z') return c + 32; return c; } diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h index a92c0a78f..e509145f9 100644 --- a/apt-pkg/contrib/strutl.h +++ b/apt-pkg/contrib/strutl.h @@ -25,19 +25,12 @@ #include <iostream> #include <time.h> +#include "macros.h" + using std::string; using std::vector; using std::ostream; -#ifdef __GNUG__ -// Methods have a hidden this parameter that is visible to this attribute -#define APT_FORMAT2 __attribute__ ((format (printf, 2, 3))) -#define APT_FORMAT3 __attribute__ ((format (printf, 3, 4))) -#else -#define APT_FORMAT2 -#define APT_FORMAT3 -#endif - bool UTF8ToCodeset(const char *codeset, const string &orig, string *dest); char *_strstrip(char *String); char *_strtabexpand(char *String,size_t Len); @@ -60,11 +53,12 @@ bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0) bool Hex2Num(const string &Str,unsigned char *Num,unsigned int Length); bool TokSplitString(char Tok,char *Input,char **List, unsigned long ListMax); -void ioprintf(ostream &out,const char *format,...) APT_FORMAT2; -void strprintf(string &out,const char *format,...) APT_FORMAT2; -char *safe_snprintf(char *Buffer,char *End,const char *Format,...) APT_FORMAT3; +vector<string> VectorizeString(string const &haystack, char const &split) __attrib_const; +void ioprintf(ostream &out,const char *format,...) __like_printf(2); +void strprintf(string &out,const char *format,...) __like_printf(2); +char *safe_snprintf(char *Buffer,char *End,const char *Format,...) __like_printf(3); bool CheckDomainList(const string &Host, const string &List); -int tolower_ascii(int c); +int tolower_ascii(int const c) __attrib_const __hot; #define APT_MKSTRCMP(name,func) \ inline int name(const char *A,const char *B) {return func(A,A+strlen(A),B,B+strlen(B));}; \ @@ -144,6 +138,4 @@ struct RxChoiceList unsigned long RegexChoice(RxChoiceList *Rxs,const char **ListBegin, const char **ListEnd); -#undef APT_FORMAT2 - #endif diff --git a/apt-pkg/contrib/weakptr.h b/apt-pkg/contrib/weakptr.h new file mode 100644 index 000000000..5158e393c --- /dev/null +++ b/apt-pkg/contrib/weakptr.h @@ -0,0 +1,62 @@ +/* weakptr.h - An object which supports weak pointers. + * + * Copyright (C) 2010 Julian Andres Klode <jak@debian.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef WEAK_POINTER_H +#define WEAK_POINTER_H + +#include <set> +/** + * Class for objects providing support for weak pointers. + * + * This class allows for the registration of certain pointers as weak, + * which will cause them to be set to NULL when the destructor of the + * object is called. + */ +class WeakPointable { +private: + std::set<WeakPointable**> pointers; + +public: + + /** + * Add a new weak pointer. + */ + inline void AddWeakPointer(WeakPointable** weakptr) { + pointers.insert(weakptr); + } + + /** + * Remove the weak pointer from the list of weak pointers. + */ + inline void RemoveWeakPointer(WeakPointable **weakptr) { + pointers.erase(weakptr); + } + + /** + * Deconstruct the object, set all weak pointers to NULL. + */ + ~WeakPointable() { + std::set<WeakPointable**>::iterator iter = pointers.begin(); + while (iter != pointers.end()) + **(iter++) = NULL; + } +}; + +#endif // WEAK_POINTER_H diff --git a/apt-pkg/deb/debindexfile.cc b/apt-pkg/deb/debindexfile.cc index 3b11ad2eb..b89429d86 100644 --- a/apt-pkg/deb/debindexfile.cc +++ b/apt-pkg/deb/debindexfile.cc @@ -149,9 +149,12 @@ unsigned long debSourcesIndex::Size() const // PackagesIndex::debPackagesIndex - Contructor /*{{{*/ // --------------------------------------------------------------------- /* */ -debPackagesIndex::debPackagesIndex(string URI,string Dist,string Section,bool Trusted) : - pkgIndexFile(Trusted), URI(URI), Dist(Dist), Section(Section) +debPackagesIndex::debPackagesIndex(string const &URI, string const &Dist, string const &Section, + bool const &Trusted, string const &Arch) : + pkgIndexFile(Trusted), URI(URI), Dist(Dist), Section(Section), Architecture(Arch) { + if (Architecture == "native") + Architecture = _config->Find("APT::Architecture"); } /*}}}*/ // PackagesIndex::ArchiveInfo - Short version of the archive url /*{{{*/ @@ -171,6 +174,8 @@ string debPackagesIndex::ArchiveInfo(pkgCache::VerIterator Ver) const Res += " "; Res += Ver.ParentPkg().Name(); Res += " "; + Res += Ver.Arch(); + Res += " "; Res += Ver.VerStr(); return Res; } @@ -204,6 +209,8 @@ string debPackagesIndex::Info(const char *Type) const else Info += Dist + '/' + Section; Info += " "; + Info += Architecture; + Info += " "; Info += Type; return Info; } @@ -227,7 +234,7 @@ string debPackagesIndex::IndexURI(const char *Type) const } else Res = URI + "dists/" + Dist + '/' + Section + - "/binary-" + _config->Find("APT::Architecture") + '/'; + "/binary-" + Architecture + '/'; Res += Type; return Res; @@ -259,7 +266,7 @@ bool debPackagesIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const { string PackageFile = IndexFile("Packages"); FileFd Pkg(PackageFile,FileFd::ReadOnly); - debListParser Parser(&Pkg); + debListParser Parser(&Pkg, Architecture); if (_error->PendingError() == true) return _error->Error("Problem opening %s",PackageFile.c_str()); @@ -329,10 +336,11 @@ pkgCache::PkgFileIterator debPackagesIndex::FindInCache(pkgCache &Cache) const // TranslationsIndex::debTranslationsIndex - Contructor /*{{{*/ // --------------------------------------------------------------------- /* */ -debTranslationsIndex::debTranslationsIndex(string URI,string Dist,string Section) : - pkgIndexFile(true), URI(URI), Dist(Dist), Section(Section) -{ -} +debTranslationsIndex::debTranslationsIndex(string URI,string Dist,string Section, + char const * const Translation) : + pkgIndexFile(true), URI(URI), Dist(Dist), Section(Section), + Language(Translation) +{} /*}}}*/ // TranslationIndex::Trans* - Return the URI to the translation files /*{{{*/ // --------------------------------------------------------------------- @@ -365,8 +373,8 @@ string debTranslationsIndex::IndexURI(const char *Type) const bool debTranslationsIndex::GetIndexes(pkgAcquire *Owner) const { if (TranslationsAvailable()) { - string TranslationFile = "Translation-" + LanguageCode(); - new pkgAcqIndexTrans(Owner, IndexURI(LanguageCode().c_str()), + string const TranslationFile = string("Translation-").append(Language); + new pkgAcqIndexTrans(Owner, IndexURI(Language), Info(TranslationFile.c_str()), TranslationFile); } @@ -385,7 +393,7 @@ string debTranslationsIndex::Describe(bool Short) const snprintf(S,sizeof(S),"%s",Info(TranslationFile().c_str()).c_str()); else snprintf(S,sizeof(S),"%s (%s)",Info(TranslationFile().c_str()).c_str(), - IndexFile(LanguageCode().c_str()).c_str()); + IndexFile(Language).c_str()); return S; } /*}}}*/ @@ -407,20 +415,20 @@ string debTranslationsIndex::Info(const char *Type) const return Info; } /*}}}*/ -bool debTranslationsIndex::HasPackages() const +bool debTranslationsIndex::HasPackages() const /*{{{*/ { if(!TranslationsAvailable()) return false; - return FileExists(IndexFile(LanguageCode().c_str())); + return FileExists(IndexFile(Language)); } - + /*}}}*/ // TranslationsIndex::Exists - Check if the index is available /*{{{*/ // --------------------------------------------------------------------- /* */ bool debTranslationsIndex::Exists() const { - return FileExists(IndexFile(LanguageCode().c_str())); + return FileExists(IndexFile(Language)); } /*}}}*/ // TranslationsIndex::Size - Return the size of the index /*{{{*/ @@ -429,7 +437,7 @@ bool debTranslationsIndex::Exists() const unsigned long debTranslationsIndex::Size() const { struct stat S; - if (stat(IndexFile(LanguageCode().c_str()).c_str(),&S) != 0) + if (stat(IndexFile(Language).c_str(),&S) != 0) return 0; return S.st_size; } @@ -440,7 +448,7 @@ unsigned long debTranslationsIndex::Size() const bool debTranslationsIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const { // Check the translation file, if in use - string TranslationFile = IndexFile(LanguageCode().c_str()); + string TranslationFile = IndexFile(Language); if (TranslationsAvailable() && FileExists(TranslationFile)) { FileFd Trans(TranslationFile,FileFd::ReadOnly); @@ -472,7 +480,7 @@ bool debTranslationsIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const /* */ pkgCache::PkgFileIterator debTranslationsIndex::FindInCache(pkgCache &Cache) const { - string FileName = IndexFile(LanguageCode().c_str()); + string FileName = IndexFile(Language); pkgCache::PkgFileIterator File = Cache.FileBegin(); for (; File.end() == false; File++) diff --git a/apt-pkg/deb/debindexfile.h b/apt-pkg/deb/debindexfile.h index b0012c96b..766e8b214 100644 --- a/apt-pkg/deb/debindexfile.h +++ b/apt-pkg/deb/debindexfile.h @@ -46,6 +46,7 @@ class debPackagesIndex : public pkgIndexFile string URI; string Dist; string Section; + string Architecture; string Info(const char *Type) const; string IndexFile(const char *Type) const; @@ -69,7 +70,8 @@ class debPackagesIndex : public pkgIndexFile virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const; virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const; - debPackagesIndex(string URI,string Dist,string Section,bool Trusted); + debPackagesIndex(string const &URI, string const &Dist, string const &Section, + bool const &Trusted, string const &Arch = "native"); }; class debTranslationsIndex : public pkgIndexFile @@ -77,12 +79,13 @@ class debTranslationsIndex : public pkgIndexFile string URI; string Dist; string Section; + const char * const Language; string Info(const char *Type) const; string IndexFile(const char *Type) const; string IndexURI(const char *Type) const; - inline string TranslationFile() const {return "Translation-" + LanguageCode();}; + inline string TranslationFile() const {return string("Translation-").append(Language);}; public: @@ -99,7 +102,7 @@ class debTranslationsIndex : public pkgIndexFile virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const; virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const; - debTranslationsIndex(string URI,string Dist,string Section); + debTranslationsIndex(string URI,string Dist,string Section, char const * const Language); }; class debSourcesIndex : public pkgIndexFile diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index 25b0953e0..0551a5f7c 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -13,6 +13,7 @@ #include <apt-pkg/deblistparser.h> #include <apt-pkg/error.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/aptconfiguration.h> #include <apt-pkg/strutl.h> #include <apt-pkg/crc-16.h> #include <apt-pkg/md5.h> @@ -30,10 +31,13 @@ static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Impor // ListParser::debListParser - Constructor /*{{{*/ // --------------------------------------------------------------------- -/* */ -debListParser::debListParser(FileFd *File) : Tags(File) -{ - Arch = _config->Find("APT::architecture"); +/* Provide an architecture and only this one and "all" will be accepted + in Step(), if no Architecture is given we will accept every arch + we would accept in general with checkArchitecture() */ +debListParser::debListParser(FileFd *File, string const &Arch) : Tags(File), + Arch(Arch) { + if (Arch == "native") + this->Arch = _config->Find("APT::Architecture"); } /*}}}*/ // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/ @@ -51,14 +55,41 @@ unsigned long debListParser::UniqFindTagWrite(const char *Tag) // ListParser::Package - Return the package name /*{{{*/ // --------------------------------------------------------------------- /* This is to return the name of the package this section describes */ -string debListParser::Package() -{ - string Result = Section.FindS("Package"); - if (Result.empty() == true) +string debListParser::Package() { + string const Result = Section.FindS("Package"); + if(unlikely(Result.empty() == true)) _error->Error("Encountered a section with no Package: header"); return Result; } /*}}}*/ +// ListParser::Architecture - Return the package arch /*{{{*/ +// --------------------------------------------------------------------- +/* This will return the Architecture of the package this section describes + Note that architecture "all" packages will get the architecture of the + Packages file parsed here. */ +string debListParser::Architecture() { + string const Result = Section.FindS("Architecture"); + if (Result.empty() == true || Result == "all") + { + if (Arch.empty() == true) + /* FIXME: this is a problem for installed arch all + packages as we don't know from which arch this + package was installed - and therefore which + dependency this package resolves. */ + return _config->Find("APT::Architecture"); + else + return Arch; + } + return Result; +} + /*}}}*/ +// ListParser::ArchitectureAll /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool debListParser::ArchitectureAll() { + return Section.FindS("Architecture") == "all"; +} + /*}}}*/ // ListParser::Version - Return the version string /*{{{*/ // --------------------------------------------------------------------- /* This is to return the string describing the version in debian form, @@ -76,8 +107,31 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver) { // Parse the section Ver->Section = UniqFindTagWrite("Section"); - Ver->Arch = UniqFindTagWrite("Architecture"); - + + // Parse multi-arch + if (Section.FindS("Architecture") == "all") + /* Arch all packages can't have a Multi-Arch field, + but we need a special treatment for them nonetheless */ + Ver->MultiArch = pkgCache::Version::All; + else + { + string const MultiArch = Section.FindS("Multi-Arch"); + if (MultiArch.empty() == true) + Ver->MultiArch = pkgCache::Version::None; + else if (MultiArch == "same") + Ver->MultiArch = pkgCache::Version::Same; + else if (MultiArch == "foreign") + Ver->MultiArch = pkgCache::Version::Foreign; + else if (MultiArch == "allowed") + Ver->MultiArch = pkgCache::Version::Allowed; + else + { + _error->Warning("Unknown Multi-Arch type »%s« for package »%s«", + MultiArch.c_str(), Section.FindS("Package").c_str()); + Ver->MultiArch = pkgCache::Version::None; + } + } + // Archive Size Ver->Size = (unsigned)Section.FindI("Size"); @@ -94,6 +148,25 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver) Ver->Priority = pkgCache::State::Extra; } + if (Ver->MultiArch == pkgCache::Version::All) + { + /* We maintain a "pseudo" arch=all package for architecture all versions + on which these versions can depend on. This pseudo package is many used + for downloading/installing: The other pseudo-packages will degenerate + to a NOP in the download/install step - this package will ensure that + it is downloaded only one time and installed only one time -- even if + the architecture bound versions coming in and out on regular basis. */ + bool const static multiArch = APT::Configuration::getArchitectures().size() > 1; + if (strcmp(Ver.Arch(true),"all") == 0) + return true; + else if (multiArch == true) + { + // our pseudo packages have no size to not confuse the fetcher + Ver->Size = 0; + Ver->InstalledSize = 0; + } + } + if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false) return false; if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false) @@ -128,10 +201,11 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver) only describe package properties */ string debListParser::Description() { - if (DescriptionLanguage().empty()) + string const lang = DescriptionLanguage(); + if (lang.empty()) return Section.FindS("Description"); else - return Section.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str()); + return Section.FindS(string("Description-").append(lang).c_str()); } /*}}}*/ // ListParser::DescriptionLanguage - Return the description lang string /*{{{*/ @@ -141,7 +215,16 @@ string debListParser::Description() assumed to describe original description. */ string debListParser::DescriptionLanguage() { - return Section.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : ""; + if (Section.FindS("Description").empty() == false) + return ""; + + std::vector<string> const lang = APT::Configuration::getLanguages(); + for (std::vector<string>::const_iterator l = lang.begin(); + l != lang.end(); l++) + if (Section.FindS(string("Description-").append(*l).c_str()).empty() == false) + return *l; + + return ""; } /*}}}*/ // ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/ @@ -172,8 +255,16 @@ bool debListParser::UsePackage(pkgCache::PkgIterator Pkg, { if (Pkg->Section == 0) Pkg->Section = UniqFindTagWrite("Section"); - if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false) - return false; + + // Packages which are not from the "native" arch doesn't get the essential flag + // in the default "native" mode - it is also possible to mark "all" or "none". + // The "installed" mode is handled by ParseStatus(), See #544481 and friends. + string const static myArch = _config->Find("APT::Architecture"); + string const static essential = _config->Find("pkgCacheGen::Essential", "native"); + if ((essential == "native" && Pkg->Arch != 0 && myArch == Pkg.Arch()) || + essential == "all") + if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false) + return false; if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false) return false; @@ -247,7 +338,13 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg, const char *Stop; if (Section.Find("Status",Start,Stop) == false) return true; - + + // UsePackage() is responsible for setting the flag in the default case + bool const static essential = _config->Find("pkgCacheGen::Essential", "") == "installed"; + if (essential == true && + Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false) + return false; + // Isolate the first word const char *I = Start; for(; I < Stop && *I != ' '; I++); @@ -383,7 +480,8 @@ const char *debListParser::ConvertRelation(const char *I,unsigned int &Op) bit by bit. */ const char *debListParser::ParseDepends(const char *Start,const char *Stop, string &Package,string &Ver, - unsigned int &Op, bool ParseArchFlags) + unsigned int &Op, bool const &ParseArchFlags, + bool const &StripMultiArch) { // Strip off leading space for (;Start != Stop && isspace(*Start) != 0; Start++); @@ -402,7 +500,14 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop, // Stash the package name Package.assign(Start,I - Start); - + + // We don't want to confuse library users which can't handle MultiArch + if (StripMultiArch == true) { + size_t const found = Package.rfind(':'); + if (found != string::npos) + Package = Package.substr(0,found); + } + // Skip white space to the '(' for (;I != Stop && isspace(*I) != 0 ; I++); @@ -515,8 +620,12 @@ bool debListParser::ParseDepends(pkgCache::VerIterator Ver, const char *Stop; if (Section.Find(Tag,Start,Stop) == false) return true; - + + static std::vector<std::string> const archs = APT::Configuration::getArchitectures(); + static bool const multiArch = archs.size() <= 1; + string Package; + string const pkgArch = Ver.Arch(true); string Version; unsigned int Op; @@ -525,8 +634,18 @@ bool debListParser::ParseDepends(pkgCache::VerIterator Ver, Start = ParseDepends(Start,Stop,Package,Version,Op); if (Start == 0) return _error->Error("Problem parsing dependency %s",Tag); - - if (NewDepends(Ver,Package,Version,Op,Type) == false) + + if (multiArch == true && + (Type == pkgCache::Dep::Conflicts || + Type == pkgCache::Dep::DpkgBreaks || + Type == pkgCache::Dep::Replaces)) + { + for (std::vector<std::string>::const_iterator a = archs.begin(); + a != archs.end(); ++a) + if (NewDepends(Ver,Package,*a,Version,Op,Type) == false) + return false; + } + else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false) return false; if (Start == Stop) break; @@ -541,29 +660,52 @@ bool debListParser::ParseProvides(pkgCache::VerIterator Ver) { const char *Start; const char *Stop; - if (Section.Find("Provides",Start,Stop) == false) - return true; - - string Package; - string Version; - unsigned int Op; - - while (1) + if (Section.Find("Provides",Start,Stop) == true) { - Start = ParseDepends(Start,Stop,Package,Version,Op); - if (Start == 0) - return _error->Error("Problem parsing Provides line"); - if (Op != pkgCache::Dep::NoOp) { - _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str()); - } else { - if (NewProvides(Ver,Package,Version) == false) - return false; + string Package; + string Version; + string const Arch = Ver.Arch(true); + unsigned int Op; + + while (1) + { + Start = ParseDepends(Start,Stop,Package,Version,Op); + if (Start == 0) + return _error->Error("Problem parsing Provides line"); + if (Op != pkgCache::Dep::NoOp) { + _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str()); + } else { + if (NewProvides(Ver, Package, Arch, Version) == false) + return false; + } + + if (Start == Stop) + break; } + } - if (Start == Stop) - break; + if (Ver->MultiArch == pkgCache::Version::Allowed) + { + string const Package = string(Ver.ParentPkg().Name()).append(":").append("any"); + NewProvides(Ver, Package, "any", Ver.VerStr()); } - + + if (Ver->MultiArch != pkgCache::Version::Foreign) + return true; + + std::vector<string> const archs = APT::Configuration::getArchitectures(); + if (archs.size() <= 1) + return true; + + string const Package = Ver.ParentPkg().Name(); + string const Version = Ver.VerStr(); + for (std::vector<string>::const_iterator a = archs.begin(); + a != archs.end(); ++a) + { + if (NewProvides(Ver, Package, *a, Version) == false) + return false; + } + return true; } /*}}}*/ @@ -594,16 +736,23 @@ bool debListParser::Step() /* See if this is the correct Architecture, if it isn't then we drop the whole section. A missing arch tag only happens (in theory) inside the Status file, so that is a positive return */ - const char *Start; - const char *Stop; - if (Section.Find("Architecture",Start,Stop) == false) + string const Architecture = Section.FindS("Architecture"); + if (Architecture.empty() == true) return true; - if (stringcmp(Arch,Start,Stop) == 0) - return true; + if (Arch.empty() == true) + { + if (APT::Configuration::checkArchitecture(Architecture) == true) + return true; + } + else + { + if (Architecture == Arch) + return true; - if (stringcmp(Start,Stop,"all") == 0) - return true; + if (Architecture == "all") + return true; + } iOffset = Tags.Offset(); } @@ -621,8 +770,9 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI, if (Tags.Step(Section) == false) return false; - //mvo: I don't think we need to fill that in (it's unused since apt-0.6) - //FileI->Architecture = WriteUniqString(Arch); + // FIXME: Do we need it now for multi-arch? + // mvo: I don't think we need to fill that in (it's unused since apt-0.6) +// FileI->Architecture = WriteUniqString(Arch); // apt-secure does no longer download individual (per-section) Release // file. to provide Component pinning we use the section name now diff --git a/apt-pkg/deb/deblistparser.h b/apt-pkg/deb/deblistparser.h index 34bb29c72..8da051530 100644 --- a/apt-pkg/deb/deblistparser.h +++ b/apt-pkg/deb/deblistparser.h @@ -46,6 +46,8 @@ class debListParser : public pkgCacheGenerator::ListParser // These all operate against the current section virtual string Package(); + virtual string Architecture(); + virtual bool ArchitectureAll(); virtual string Version(); virtual bool NewVersion(pkgCache::VerIterator Ver); virtual string Description(); @@ -64,10 +66,11 @@ class debListParser : public pkgCacheGenerator::ListParser static const char *ParseDepends(const char *Start,const char *Stop, string &Package,string &Ver,unsigned int &Op, - bool ParseArchFlags = false); + bool const &ParseArchFlags = false, + bool const &StripMultiArch = false); static const char *ConvertRelation(const char *I,unsigned int &Op); - debListParser(FileFd *File); + debListParser(FileFd *File, string const &Arch = ""); }; #endif diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc index f3ab6960c..8df3ed18d 100644 --- a/apt-pkg/deb/debmetaindex.cc +++ b/apt-pkg/deb/debmetaindex.cc @@ -5,11 +5,14 @@ #include <apt-pkg/strutl.h> #include <apt-pkg/acquire-item.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/aptconfiguration.h> #include <apt-pkg/error.h> +#include <set> + using namespace std; -string debReleaseIndex::Info(const char *Type, const string Section) const +string debReleaseIndex::Info(const char *Type, string const &Section, string const &Arch) const { string Info = ::URI::SiteOnly(URI) + ' '; if (Dist[Dist.size() - 1] == '/') @@ -18,7 +21,11 @@ string debReleaseIndex::Info(const char *Type, const string Section) const Info += Dist; } else - Info += Dist + '/' + Section; + { + Info += Dist + '/' + Section; + if (Arch.empty() == true) + Info += " " + Arch; + } Info += " "; Info += Type; return Info; @@ -60,16 +67,21 @@ string debReleaseIndex::MetaIndexURI(const char *Type) const return Res; } -string debReleaseIndex::IndexURISuffix(const char *Type, const string Section) const +string debReleaseIndex::IndexURISuffix(const char *Type, string const &Section, string const &Arch) const { string Res =""; if (Dist[Dist.size() - 1] != '/') - Res += Section + "/binary-" + _config->Find("APT::Architecture") + '/'; + { + if (Arch == "native") + Res += Section + "/binary-" + _config->Find("APT::Architecture") + '/'; + else + Res += Section + "/binary-" + Arch + '/'; + } return Res + Type; } -string debReleaseIndex::IndexURI(const char *Type, const string Section) const +string debReleaseIndex::IndexURI(const char *Type, string const &Section, string const &Arch) const { if (Dist[Dist.size() - 1] == '/') { @@ -81,10 +93,10 @@ string debReleaseIndex::IndexURI(const char *Type, const string Section) const return Res + Type; } else - return URI + "dists/" + Dist + '/' + IndexURISuffix(Type, Section); + return URI + "dists/" + Dist + '/' + IndexURISuffix(Type, Section, Arch); } -string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string Section) const +string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string &Section) const { string Res =""; if (Dist[Dist.size() - 1] != '/') @@ -92,7 +104,7 @@ string debReleaseIndex::SourceIndexURISuffix(const char *Type, const string Sect return Res + Type; } -string debReleaseIndex::SourceIndexURI(const char *Type, const string Section) const +string debReleaseIndex::SourceIndexURI(const char *Type, const string &Section) const { string Res; if (Dist[Dist.size() - 1] == '/') @@ -107,44 +119,61 @@ string debReleaseIndex::SourceIndexURI(const char *Type, const string Section) c return URI + "dists/" + Dist + "/" + SourceIndexURISuffix(Type, Section); } -debReleaseIndex::debReleaseIndex(string URI,string Dist) -{ - this->URI = URI; - this->Dist = Dist; - this->Indexes = NULL; - this->Type = "deb"; +debReleaseIndex::debReleaseIndex(string const &URI, string const &Dist) { + this->URI = URI; + this->Dist = Dist; + this->Indexes = NULL; + this->Type = "deb"; } -debReleaseIndex::~debReleaseIndex() -{ - for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin(); - I != SectionEntries.end(); I++) - delete *I; +debReleaseIndex::~debReleaseIndex() { + for (map<string, vector<debSectionEntry const*> >::const_iterator A = ArchEntries.begin(); + A != ArchEntries.end(); ++A) + for (vector<const debSectionEntry *>::const_iterator S = A->second.begin(); + S != A->second.end(); ++S) + delete *S; } -vector <struct IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const -{ - vector <struct IndexTarget *>* IndexTargets = new vector <IndexTarget *>; - for (vector <const debSectionEntry *>::const_iterator I = SectionEntries.begin(); - I != SectionEntries.end(); - I++) - { - IndexTarget * Target = new IndexTarget(); - Target->ShortDesc = (*I)->IsSrc ? "Sources" : "Packages"; - Target->MetaKey - = (*I)->IsSrc ? SourceIndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section) - : IndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section); - Target->URI - = (*I)->IsSrc ? SourceIndexURI(Target->ShortDesc.c_str(), (*I)->Section) - : IndexURI(Target->ShortDesc.c_str(), (*I)->Section); - - Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section); - IndexTargets->push_back (Target); - } - return IndexTargets; +vector <struct IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const { + vector <struct IndexTarget *>* IndexTargets = new vector <IndexTarget *>; + + map<string, vector<debSectionEntry const*> >::const_iterator const src = ArchEntries.find("source"); + if (src != ArchEntries.end()) { + vector<debSectionEntry const*> const SectionEntries = src->second; + for (vector<debSectionEntry const*>::const_iterator I = SectionEntries.begin(); + I != SectionEntries.end(); ++I) { + IndexTarget * Target = new IndexTarget(); + Target->ShortDesc = "Sources"; + Target->MetaKey = SourceIndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section); + Target->URI = SourceIndexURI(Target->ShortDesc.c_str(), (*I)->Section); + Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section); + IndexTargets->push_back (Target); + } + } + + // Only source release + if (IndexTargets->empty() == false && ArchEntries.size() == 1) + return IndexTargets; + + for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin(); + a != ArchEntries.end(); ++a) { + if (a->first == "source") + continue; + for (vector <const debSectionEntry *>::const_iterator I = a->second.begin(); + I != a->second.end(); ++I) { + IndexTarget * Target = new IndexTarget(); + Target->ShortDesc = "Packages"; + Target->MetaKey = IndexURISuffix(Target->ShortDesc.c_str(), (*I)->Section, a->first); + Target->URI = IndexURI(Target->ShortDesc.c_str(), (*I)->Section, a->first); + Target->Description = Info (Target->ShortDesc.c_str(), (*I)->Section, a->first); + IndexTargets->push_back (Target); + } + } + + return IndexTargets; } /*}}}*/ -bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const +bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const { // special case for --print-uris if (GetAll) { @@ -169,17 +198,28 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const ComputeIndexTargets(), new indexRecords (Dist)); - // Queue the translations - for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin(); - I != SectionEntries.end(); I++) { - - if((*I)->IsSrc) - continue; - debTranslationsIndex i = debTranslationsIndex(URI,Dist,(*I)->Section); - i.GetIndexes(Owner); - } - - return true; + // Queue the translations + std::vector<std::string> const lang = APT::Configuration::getLanguages(true); + map<string, set<string> > sections; + for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin(); + a != ArchEntries.end(); ++a) { + if (a->first == "source") + continue; + for (vector<debSectionEntry const*>::const_iterator I = a->second.begin(); + I != a->second.end(); I++) + sections[(*I)->Section].insert(lang.begin(), lang.end()); + } + + for (map<string, set<string> >::const_iterator s = sections.begin(); + s != sections.end(); ++s) + for (set<string>::const_iterator l = s->second.begin(); + l != s->second.end(); l++) { + if (*l == "none") continue; + debTranslationsIndex i = debTranslationsIndex(URI,Dist,s->first,(*l).c_str()); + i.GetIndexes(Owner); + } + + return true; } bool debReleaseIndex::IsTrusted() const @@ -196,67 +236,113 @@ bool debReleaseIndex::IsTrusted() const return false; } -vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles() -{ - if (Indexes != NULL) - return Indexes; - - Indexes = new vector <pkgIndexFile*>; - for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin(); - I != SectionEntries.end(); I++) { - if ((*I)->IsSrc) - Indexes->push_back(new debSourcesIndex (URI, Dist, (*I)->Section, IsTrusted())); - else - { - Indexes->push_back(new debPackagesIndex (URI, Dist, (*I)->Section, IsTrusted())); - Indexes->push_back(new debTranslationsIndex(URI, Dist, (*I)->Section)); - } - } +vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles() { + if (Indexes != NULL) + return Indexes; + + Indexes = new vector <pkgIndexFile*>; + map<string, vector<debSectionEntry const*> >::const_iterator const src = ArchEntries.find("source"); + if (src != ArchEntries.end()) { + vector<debSectionEntry const*> const SectionEntries = src->second; + for (vector<debSectionEntry const*>::const_iterator I = SectionEntries.begin(); + I != SectionEntries.end(); I++) + Indexes->push_back(new debSourcesIndex (URI, Dist, (*I)->Section, IsTrusted())); + } + + // Only source release + if (Indexes->empty() == false && ArchEntries.size() == 1) + return Indexes; + + std::vector<std::string> const lang = APT::Configuration::getLanguages(true); + map<string, set<string> > sections; + for (map<string, vector<debSectionEntry const*> >::const_iterator a = ArchEntries.begin(); + a != ArchEntries.end(); ++a) { + if (a->first == "source") + continue; + for (vector<debSectionEntry const*>::const_iterator I = a->second.begin(); + I != a->second.end(); I++) { + Indexes->push_back(new debPackagesIndex (URI, Dist, (*I)->Section, IsTrusted(), a->first)); + sections[(*I)->Section].insert(lang.begin(), lang.end()); + } + } + + for (map<string, set<string> >::const_iterator s = sections.begin(); + s != sections.end(); ++s) + for (set<string>::const_iterator l = s->second.begin(); + l != s->second.end(); l++) { + if (*l == "none") continue; + Indexes->push_back(new debTranslationsIndex(URI,Dist,s->first,(*l).c_str())); + } + + return Indexes; +} - return Indexes; +void debReleaseIndex::PushSectionEntry(vector<string> const &Archs, const debSectionEntry *Entry) { + for (vector<string>::const_iterator a = Archs.begin(); + a != Archs.end(); ++a) + ArchEntries[*a].push_back(new debSectionEntry(Entry->Section, Entry->IsSrc)); + delete Entry; } -void debReleaseIndex::PushSectionEntry(const debSectionEntry *Entry) -{ - SectionEntries.push_back(Entry); +void debReleaseIndex::PushSectionEntry(string const &Arch, const debSectionEntry *Entry) { + ArchEntries[Arch].push_back(Entry); } -debReleaseIndex::debSectionEntry::debSectionEntry (string Section, bool IsSrc): Section(Section) -{ - this->IsSrc = IsSrc; +void debReleaseIndex::PushSectionEntry(const debSectionEntry *Entry) { + if (Entry->IsSrc == true) + PushSectionEntry("source", Entry); + else { + for (map<string, vector<const debSectionEntry *> >::iterator a = ArchEntries.begin(); + a != ArchEntries.end(); ++a) { + a->second.push_back(Entry); + } + } } +debReleaseIndex::debSectionEntry::debSectionEntry (string const &Section, + bool const &IsSrc): Section(Section), IsSrc(IsSrc) +{} + class debSLTypeDebian : public pkgSourceList::Type { protected: - bool CreateItemInternal(vector<metaIndex *> &List,string URI, - string Dist,string Section, - bool IsSrc) const + bool CreateItemInternal(vector<metaIndex *> &List, string const &URI, + string const &Dist, string const &Section, + bool const &IsSrc, map<string, string> const &Options) const { - for (vector<metaIndex *>::const_iterator I = List.begin(); + map<string, string>::const_iterator const arch = Options.find("arch"); + vector<string> const Archs = + (arch != Options.end()) ? VectorizeString(arch->second, ',') : + APT::Configuration::getArchitectures(); + + for (vector<metaIndex *>::const_iterator I = List.begin(); I != List.end(); I++) { - // This check insures that there will be only one Release file - // queued for all the Packages files and Sources files it - // corresponds to. - if (strcmp((*I)->GetType(), "deb") == 0) + // We only worry about debian entries here + if (strcmp((*I)->GetType(), "deb") != 0) + continue; + + debReleaseIndex *Deb = (debReleaseIndex *) (*I); + /* This check insures that there will be only one Release file + queued for all the Packages files and Sources files it + corresponds to. */ + if (Deb->GetURI() == URI && Deb->GetDist() == Dist) { - debReleaseIndex *Deb = (debReleaseIndex *) (*I); - // This check insures that there will be only one Release file - // queued for all the Packages files and Sources files it - // corresponds to. - if (Deb->GetURI() == URI && Deb->GetDist() == Dist) - { - Deb->PushSectionEntry(new debReleaseIndex::debSectionEntry(Section, IsSrc)); - return true; - } + if (IsSrc == true) + Deb->PushSectionEntry("source", new debReleaseIndex::debSectionEntry(Section, IsSrc)); + else + Deb->PushSectionEntry(Archs, new debReleaseIndex::debSectionEntry(Section, IsSrc)); + return true; } } // No currently created Release file indexes this entry, so we create a new one. // XXX determine whether this release is trusted or not - debReleaseIndex *Deb = new debReleaseIndex(URI,Dist); - Deb->PushSectionEntry (new debReleaseIndex::debSectionEntry(Section, IsSrc)); + debReleaseIndex *Deb = new debReleaseIndex(URI, Dist); + if (IsSrc == true) + Deb->PushSectionEntry ("source", new debReleaseIndex::debSectionEntry(Section, IsSrc)); + else + Deb->PushSectionEntry (Archs, new debReleaseIndex::debSectionEntry(Section, IsSrc)); List.push_back(Deb); return true; } @@ -266,10 +352,11 @@ class debSLTypeDeb : public debSLTypeDebian { public: - bool CreateItem(vector<metaIndex *> &List,string URI, - string Dist,string Section) const + bool CreateItem(vector<metaIndex *> &List, string const &URI, + string const &Dist, string const &Section, + std::map<string, string> const &Options) const { - return CreateItemInternal(List, URI, Dist, Section, false); + return CreateItemInternal(List, URI, Dist, Section, false, Options); } debSLTypeDeb() @@ -283,10 +370,11 @@ class debSLTypeDebSrc : public debSLTypeDebian { public: - bool CreateItem(vector<metaIndex *> &List,string URI, - string Dist,string Section) const + bool CreateItem(vector<metaIndex *> &List, string const &URI, + string const &Dist, string const &Section, + std::map<string, string> const &Options) const { - return CreateItemInternal(List, URI, Dist, Section, true); + return CreateItemInternal(List, URI, Dist, Section, true, Options); } debSLTypeDebSrc() diff --git a/apt-pkg/deb/debmetaindex.h b/apt-pkg/deb/debmetaindex.h index 8e6a1463b..360fa5419 100644 --- a/apt-pkg/deb/debmetaindex.h +++ b/apt-pkg/deb/debmetaindex.h @@ -5,40 +5,44 @@ #include <apt-pkg/metaindex.h> #include <apt-pkg/sourcelist.h> +#include <map> + class debReleaseIndex : public metaIndex { public: class debSectionEntry { public: - debSectionEntry (string Section, bool IsSrc); - bool IsSrc; - string Section; + debSectionEntry (string const &Section, bool const &IsSrc); + string const Section; + bool const IsSrc; }; private: - vector <const debSectionEntry *> SectionEntries; + std::map<string, vector<debSectionEntry const*> > ArchEntries; public: - debReleaseIndex(string URI, string Dist); + debReleaseIndex(string const &URI, string const &Dist); ~debReleaseIndex(); - virtual string ArchiveURI(string File) const {return URI + File;}; - virtual bool GetIndexes(pkgAcquire *Owner, bool GetAll=false) const; + virtual string ArchiveURI(string const &File) const {return URI + File;}; + virtual bool GetIndexes(pkgAcquire *Owner, bool const &GetAll=false) const; vector <struct IndexTarget *>* ComputeIndexTargets() const; - string Info(const char *Type, const string Section) const; + string Info(const char *Type, string const &Section, string const &Arch="") const; string MetaIndexInfo(const char *Type) const; string MetaIndexFile(const char *Types) const; string MetaIndexURI(const char *Type) const; - string IndexURI(const char *Type, const string Section) const; - string IndexURISuffix(const char *Type, const string Section) const; - string SourceIndexURI(const char *Type, const string Section) const; - string SourceIndexURISuffix(const char *Type, const string Section) const; + string IndexURI(const char *Type, string const &Section, string const &Arch="native") const; + string IndexURISuffix(const char *Type, string const &Section, string const &Arch="native") const; + string SourceIndexURI(const char *Type, const string &Section) const; + string SourceIndexURISuffix(const char *Type, const string &Section) const; virtual vector <pkgIndexFile *> *GetIndexFiles(); virtual bool IsTrusted() const; + void PushSectionEntry(vector<string> const &Archs, const debSectionEntry *Entry); + void PushSectionEntry(string const &Arch, const debSectionEntry *Entry); void PushSectionEntry(const debSectionEntry *Entry); }; diff --git a/apt-pkg/deb/debrecords.cc b/apt-pkg/deb/debrecords.cc index 57d30dc62..34ef0d8f2 100644 --- a/apt-pkg/deb/debrecords.cc +++ b/apt-pkg/deb/debrecords.cc @@ -11,6 +11,7 @@ #include <apt-pkg/debrecords.h> #include <apt-pkg/strutl.h> #include <apt-pkg/error.h> +#include <apt-pkg/aptconfiguration.h> #include <langinfo.h> /*}}}*/ @@ -110,13 +111,18 @@ string debRecordParser::ShortDesc() string debRecordParser::LongDesc() { string orig, dest; - char *codeset = nl_langinfo(CODESET); if (!Section.FindS("Description").empty()) orig = Section.FindS("Description").c_str(); - else - orig = Section.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str()).c_str(); + else + { + vector<string> const lang = APT::Configuration::getLanguages(); + for (vector<string>::const_iterator l = lang.begin(); + orig.empty() && l != lang.end(); l++) + orig = Section.FindS(string("Description-").append(*l).c_str()); + } + char const * const codeset = nl_langinfo(CODESET); if (strcmp(codeset,"UTF-8") != 0) { UTF8ToCodeset(codeset, orig, &dest); orig = dest; diff --git a/apt-pkg/deb/debsrcrecords.cc b/apt-pkg/deb/debsrcrecords.cc index bde10aa6d..21336e1af 100644 --- a/apt-pkg/deb/debsrcrecords.cc +++ b/apt-pkg/deb/debsrcrecords.cc @@ -54,7 +54,8 @@ const char **debSrcRecordParser::Binaries() package/version records representing the build dependency. The returned array need not be freed and will be reused by the next call to this function */ -bool debSrcRecordParser::BuildDepends(vector<pkgSrcRecords::Parser::BuildDepRec> &BuildDeps, bool ArchOnly) +bool debSrcRecordParser::BuildDepends(vector<pkgSrcRecords::Parser::BuildDepRec> &BuildDeps, + bool const &ArchOnly, bool const &StripMultiArch) { unsigned int I; const char *Start, *Stop; @@ -77,7 +78,7 @@ bool debSrcRecordParser::BuildDepends(vector<pkgSrcRecords::Parser::BuildDepRec> while (1) { Start = debListParser::ParseDepends(Start, Stop, - rec.Package,rec.Version,rec.Op,true); + rec.Package,rec.Version,rec.Op,true, StripMultiArch); if (Start == 0) return _error->Error("Problem parsing dependency: %s", fields[I]); diff --git a/apt-pkg/deb/debsrcrecords.h b/apt-pkg/deb/debsrcrecords.h index a3b5a8286..c39d78bae 100644 --- a/apt-pkg/deb/debsrcrecords.h +++ b/apt-pkg/deb/debsrcrecords.h @@ -30,14 +30,14 @@ class debSrcRecordParser : public pkgSrcRecords::Parser virtual bool Restart() {return Tags.Jump(Sect,0);}; virtual bool Step() {iOffset = Tags.Offset(); return Tags.Step(Sect);}; - virtual bool Jump(unsigned long Off) {iOffset = Off; return Tags.Jump(Sect,Off);}; + virtual bool Jump(unsigned long const &Off) {iOffset = Off; return Tags.Jump(Sect,Off);}; virtual string Package() const {return Sect.FindS("Package");}; virtual string Version() const {return Sect.FindS("Version");}; virtual string Maintainer() const {return Sect.FindS("Maintainer");}; virtual string Section() const {return Sect.FindS("Section");}; virtual const char **Binaries(); - virtual bool BuildDepends(vector<BuildDepRec> &BuildDeps, bool ArchOnly); + virtual bool BuildDepends(vector<BuildDepRec> &BuildDeps, bool const &ArchOnly, bool const &StripMultiArch = true); virtual unsigned long Offset() {return iOffset;}; virtual string AsStr() { @@ -47,7 +47,7 @@ class debSrcRecordParser : public pkgSrcRecords::Parser }; virtual bool Files(vector<pkgSrcRecords::File> &F); - debSrcRecordParser(string File,pkgIndexFile const *Index) + debSrcRecordParser(string const &File,pkgIndexFile const *Index) : Parser(Index), Fd(File,FileFd::ReadOnly), Tags(&Fd,102400), Buffer(0), BufSize(0) {} ~debSrcRecordParser(); diff --git a/apt-pkg/deb/debsystem.cc b/apt-pkg/deb/debsystem.cc index 089a465c1..ef5ec9703 100644 --- a/apt-pkg/deb/debsystem.cc +++ b/apt-pkg/deb/debsystem.cc @@ -78,8 +78,15 @@ bool debSystem::Lock() { close(LockFD); LockFD = -1; + const char *cmd; + if (getenv("SUDO_USER") != NULL) + cmd = "sudo dpkg --configure -a"; + else + cmd = "dpkg --configure -a"; + // TRANSLATORS: the %s contains the recovery command, usually + // dpkg --configure -a return _error->Error(_("dpkg was interrupted, you must manually " - "run 'sudo dpkg --configure -a' to correct the problem. ")); + "run '%s' to correct the problem. "), cmd); } LockCount++; diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 18c731788..c724c69a9 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -52,6 +52,7 @@ namespace std::make_pair("configure", N_("Configuring %s")), std::make_pair("remove", N_("Removing %s")), std::make_pair("purge", N_("Completely removing %s")), + std::make_pair("disappear", N_("Noting disappearance of %s")), std::make_pair("trigproc", N_("Running post-installation trigger %s")) }; @@ -107,7 +108,7 @@ ionice(int PID) /* */ pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache) : pkgPackageManager(Cache), dpkgbuf_pos(0), - term_out(NULL), PackagesDone(0), PackagesTotal(0), pkgFailures(0) + term_out(NULL), history_out(NULL), PackagesDone(0), PackagesTotal(0) { } /*}}}*/ @@ -126,7 +127,19 @@ bool pkgDPkgPM::Install(PkgIterator Pkg,string File) if (File.empty() == true || Pkg.end() == true) return _error->Error("Internal Error, No file name for %s",Pkg.Name()); - List.push_back(Item(Item::Install,Pkg,File)); + // If the filename string begins with DPkg::Chroot-Directory, return the + // substr that is within the chroot so dpkg can access it. + string const chrootdir = _config->FindDir("DPkg::Chroot-Directory","/"); + if (chrootdir != "/" && File.find(chrootdir) == 0) + { + size_t len = chrootdir.length(); + if (chrootdir.at(len - 1) == '/') + len--; + List.push_back(Item(Item::Install,Pkg,File.substr(len))); + } + else + List.push_back(Item(Item::Install,Pkg,File)); + return true; } /*}}}*/ @@ -408,7 +421,8 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) 'processing: install: pkg' 'processing: configure: pkg' 'processing: remove: pkg' - 'processing: purge: pkg' - but for apt is it a ignored "unknown" action + 'processing: purge: pkg' + 'processing: disappear: pkg' 'processing: trigproc: trigger' */ @@ -455,6 +469,9 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) write(OutStatusFd, status.str().c_str(), status.str().size()); if (Debug == true) std::clog << "send: '" << status.str() << "'" << endl; + + if (strncmp(action, "disappear", strlen("disappear")) == 0) + disappearedPkgs.insert(string(pkg_or_trigger)); return; } @@ -562,7 +579,7 @@ void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd) } /*}}}*/ // DPkgPM::WriteHistoryTag /*{{{*/ -void pkgDPkgPM::WriteHistoryTag(FILE *history_out, string tag, string value) +void pkgDPkgPM::WriteHistoryTag(string tag, string value) { if (value.size() > 0) { @@ -603,7 +620,7 @@ bool pkgDPkgPM::OpenLog() _config->Find("Dir::Log::History")); if (!history_name.empty()) { - FILE *history_out = fopen(history_name.c_str(),"a"); + history_out = fopen(history_name.c_str(),"a"); if (history_out == NULL) return _error->WarningE("OpenLog", _("Could not open file '%s'"), history_name.c_str()); chmod(history_name.c_str(), 0644); @@ -625,12 +642,14 @@ bool pkgDPkgPM::OpenLog() remove += I.Name() + string(" (") + Cache[I].CurVersion + string("), "); } } - WriteHistoryTag(history_out, "Install", install); - WriteHistoryTag(history_out, "Upgrade", upgrade); - WriteHistoryTag(history_out, "Downgrade",downgrade); - WriteHistoryTag(history_out, "Remove",remove); - WriteHistoryTag(history_out, "Purge",purge); - fclose(history_out); + if (_config->Exists("Commandline::AsString") == true) + WriteHistoryTag("Commandline", _config->Find("Commandline::AsString")); + WriteHistoryTag("Install", install); + WriteHistoryTag("Upgrade", upgrade); + WriteHistoryTag("Downgrade",downgrade); + WriteHistoryTag("Remove",remove); + WriteHistoryTag("Purge",purge); + fflush(history_out); } return true; @@ -653,14 +672,14 @@ bool pkgDPkgPM::CloseLog() } term_out = NULL; - string history_name = flCombine(_config->FindDir("Dir::Log"), - _config->Find("Dir::Log::History")); - if (!history_name.empty()) + if(history_out) { - FILE *history_out = fopen(history_name.c_str(),"a"); + if (dpkg_error.size() > 0) + fprintf(history_out, "Error: %s\n", dpkg_error.c_str()); fprintf(history_out, "End-Date: %s\n", timestr); fclose(history_out); } + history_out = NULL; return true; } @@ -908,6 +927,8 @@ bool pkgDPkgPM::Go(int OutStatusFd) { if((*I).Pkg.end() == true) continue; + if (I->Op == Item::Configure && disappearedPkgs.find(I->Pkg.Name()) != disappearedPkgs.end()) + continue; Args[n++] = I->Pkg.Name(); Size += strlen(Args[n-1]); } @@ -1075,9 +1096,10 @@ bool pkgDPkgPM::Go(int OutStatusFd) signal(SIGHUP,old_SIGHUP); return _error->Errno("waitpid","Couldn't wait for subprocess"); } + // wait for input or output here FD_ZERO(&rfds); - if (!stdin_is_dev_null) + if (master >= 0 && !stdin_is_dev_null) FD_SET(0, &rfds); FD_SET(_dpkgin, &rfds); if(master >= 0) @@ -1130,7 +1152,6 @@ bool pkgDPkgPM::Go(int OutStatusFd) if(stopOnError) RunScripts("DPkg::Post-Invoke"); - string dpkg_error; if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV) strprintf(dpkg_error, "Sub-process %s received a segmentation fault.",Args[0]); else if (WIFEXITED(Status) != 0) @@ -1139,17 +1160,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) strprintf(dpkg_error, "Sub-process %s exited unexpectedly",Args[0]); if(dpkg_error.size() > 0) - { _error->Error(dpkg_error.c_str()); - string history_name = flCombine(_config->FindDir("Dir::Log"), - _config->Find("Dir::Log::History")); - if (!history_name.empty()) - { - FILE *history_out = fopen(history_name.c_str(),"a"); - fprintf(history_out, "Error: %s\n", dpkg_error.c_str()); - fclose(history_out); - } - } if(stopOnError) { @@ -1184,7 +1195,7 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg) string::size_type pos; FILE *report; - if (_config->FindB("Dpkg::ApportFailureReport",true) == false) + if (_config->FindB("Dpkg::ApportFailureReport", false) == false) { std::clog << "configured to not write apport reports" << std::endl; return; diff --git a/apt-pkg/deb/dpkgpm.h b/apt-pkg/deb/dpkgpm.h index 160486bf9..ce3e20f2e 100644 --- a/apt-pkg/deb/dpkgpm.h +++ b/apt-pkg/deb/dpkgpm.h @@ -29,6 +29,8 @@ class pkgDPkgPM : public pkgPackageManager char dpkgbuf[1024]; int dpkgbuf_pos; FILE *term_out; + FILE *history_out; + string dpkg_error; protected: int pkgFailures; @@ -68,7 +70,7 @@ class pkgDPkgPM : public pkgPackageManager // Helpers bool RunScriptsWithPkgs(const char *Cnf); bool SendV2Pkgs(FILE *F); - void WriteHistoryTag(FILE* history_out, string tag, string value); + void WriteHistoryTag(string tag, string value); // apport integration void WriteApportReport(const char *pkgpath, const char *errormsg); diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index ec7a5de64..411ae5f62 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -17,6 +17,7 @@ #include <apt-pkg/fileutl.h> #include <apt-pkg/strutl.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/aptconfiguration.h> #include <apt-pkg/pkgsystem.h> #include <apt-pkg/tagfile.h> @@ -164,38 +165,50 @@ bool pkgDepCache::Init(OpProgress *Prog) bool pkgDepCache::readStateFile(OpProgress *Prog) /*{{{*/ { FileFd state_file; - string state = _config->FindDir("Dir::State") + "extended_states"; + string const state = _config->FindDir("Dir::State") + "extended_states"; if(FileExists(state)) { state_file.Open(state, FileFd::ReadOnly); - int file_size = state_file.Size(); + int const file_size = state_file.Size(); if(Prog != NULL) Prog->OverallProgress(0, file_size, 1, _("Reading state information")); pkgTagFile tagfile(&state_file); pkgTagSection section; - int amt=0; - bool debug_autoremove=_config->FindB("Debug::pkgAutoRemove",false); + int amt = 0; + bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false); while(tagfile.Step(section)) { - string pkgname = section.FindS("Package"); - pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname); - // Silently ignore unknown packages and packages with no actual - // version. - if(!pkg.end() && !pkg.VersionList().end()) { - short reason = section.FindI("Auto-Installed", 0); - if(reason > 0) - PkgState[pkg->ID].Flags |= Flag::Auto; - if(debug_autoremove) - std::cout << "Auto-Installed : " << pkgname << std::endl; - amt+=section.size(); - if(Prog != NULL) - Prog->OverallProgress(amt, file_size, 1, - _("Reading state information")); + string const pkgname = section.FindS("Package"); + string pkgarch = section.FindS("Architecture"); + if (pkgarch.empty() == true) + pkgarch = "any"; + pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch); + // Silently ignore unknown packages and packages with no actual version. + if(pkg.end() == true || pkg->VersionList == 0) + continue; + + short const reason = section.FindI("Auto-Installed", 0); + if(reason > 0) + { + PkgState[pkg->ID].Flags |= Flag::Auto; + if (unlikely(debug_autoremove)) + std::clog << "Auto-Installed : " << pkg.FullName() << std::endl; + if (pkgarch == "any") + { + pkgCache::GrpIterator G = pkg.Group(); + for (pkg = G.NextPkg(pkg); pkg.end() != true; pkg = G.NextPkg(pkg)) + if (pkg->VersionList != 0) + PkgState[pkg->ID].Flags |= Flag::Auto; + } } + amt += section.size(); if(Prog != NULL) - Prog->OverallProgress(file_size, file_size, 1, + Prog->OverallProgress(amt, file_size, 1, _("Reading state information")); } + if(Prog != NULL) + Prog->OverallProgress(file_size, file_size, 1, + _("Reading state information")); } return true; @@ -203,13 +216,13 @@ bool pkgDepCache::readStateFile(OpProgress *Prog) /*{{{*/ /*}}}*/ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/ { - bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false); + bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false); if(debug_autoremove) std::clog << "pkgDepCache::writeStateFile()" << std::endl; FileFd StateFile; - string state = _config->FindDir("Dir::State") + "extended_states"; + string const state = _config->FindDir("Dir::State") + "extended_states"; // if it does not exist, create a empty one if(!FileExists(state)) @@ -224,7 +237,7 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/ state.c_str()); FILE *OutFile; - string outfile = state + ".tmp"; + string const outfile = state + ".tmp"; if((OutFile = fopen(outfile.c_str(),"w")) == NULL) return _error->Error(_("Failed to write temporary StateFile %s"), outfile.c_str()); @@ -235,46 +248,72 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/ std::set<string> pkgs_seen; const char *nullreorderlist[] = {0}; while(tagfile.Step(section)) { - string pkgname = section.FindS("Package"); + string const pkgname = section.FindS("Package"); + string pkgarch = section.FindS("Architecture"); + if (pkgarch.empty() == true) + pkgarch = "native"; // Silently ignore unknown packages and packages with no actual // version. - pkgCache::PkgIterator pkg=Cache->FindPkg(pkgname); + pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch); if(pkg.end() || pkg.VersionList().end()) continue; - bool newAuto = (PkgState[pkg->ID].Flags & Flag::Auto); + StateCache const &P = PkgState[pkg->ID]; + bool newAuto = (P.Flags & Flag::Auto); + // skip not installed or now-removed ones if requested + if (InstalledOnly && ( + (pkg->CurrentVer == 0 && P.Mode != ModeInstall) || + (pkg->CurrentVer != 0 && P.Mode == ModeDelete))) + { + // The section is obsolete if it contains no other tag + unsigned int const count = section.Count(); + if (count < 2 || + (count == 2 && section.Exists("Auto-Installed")) || + (count == 3 && section.Exists("Auto-Installed") && section.Exists("Architecture"))) + continue; + else + newAuto = false; + } if(_config->FindB("Debug::pkgAutoRemove",false)) std::clog << "Update existing AutoInstall info: " - << pkg.Name() << std::endl; - TFRewriteData rewrite[2]; - rewrite[0].Tag = "Auto-Installed"; - rewrite[0].Rewrite = newAuto ? "1" : "0"; + << pkg.FullName() << std::endl; + TFRewriteData rewrite[3]; + rewrite[0].Tag = "Architecture"; + rewrite[0].Rewrite = pkg.Arch(); rewrite[0].NewTag = 0; - rewrite[1].Tag = 0; + rewrite[1].Tag = "Auto-Installed"; + rewrite[1].Rewrite = newAuto ? "1" : "0"; + rewrite[1].NewTag = 0; + rewrite[2].Tag = 0; TFRewrite(OutFile, section, nullreorderlist, rewrite); fprintf(OutFile,"\n"); - pkgs_seen.insert(pkgname); + pkgs_seen.insert(pkg.FullName()); } // then write the ones we have not seen yet std::ostringstream ostr; for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) { - if(PkgState[pkg->ID].Flags & Flag::Auto) { - if (pkgs_seen.find(pkg.Name()) != pkgs_seen.end()) { + StateCache const &P = PkgState[pkg->ID]; + if(P.Flags & Flag::Auto) { + if (pkgs_seen.find(pkg.FullName()) != pkgs_seen.end()) { if(debug_autoremove) - std::clog << "Skipping already written " << pkg.Name() << std::endl; + std::clog << "Skipping already written " << pkg.FullName() << std::endl; continue; } - // skip not installed ones if requested - if(InstalledOnly && pkg->CurrentVer == 0) - continue; + // skip not installed ones if requested + if (InstalledOnly && ( + (pkg->CurrentVer == 0 && P.Mode != ModeInstall) || + (pkg->CurrentVer != 0 && P.Mode == ModeDelete))) + continue; + const char* const pkgarch = pkg.Arch(); + if (strcmp(pkgarch, "all") == 0) + continue; if(debug_autoremove) - std::clog << "Writing new AutoInstall: " - << pkg.Name() << std::endl; + std::clog << "Writing new AutoInstall: " << pkg.FullName() << std::endl; ostr.str(string("")); - ostr << "Package: " << pkg.Name() + ostr << "Package: " << pkg.Name() + << "\nArchitecture: " << pkgarch << "\nAuto-Installed: 1\n\n"; fprintf(OutFile,"%s",ostr.str().c_str()); - fprintf(OutFile,"\n"); } } fclose(OutFile); @@ -596,6 +635,107 @@ void pkgDepCache::UpdateVerState(PkgIterator Pkg) } } /*}}}*/ +// DepCache::RemovePseudoInstalledPkg - MultiArch helper for Update() /*{{{*/ +// --------------------------------------------------------------------- +/* We "install" arch all packages for all archs if it is installed. Many + of these will be broken. This method will look at these broken Pkg and + "remove" it. */ +bool pkgDepCache::RemovePseudoInstalledPkg(PkgIterator &Pkg, std::set<unsigned long> &recheck) { + if (unlikely(Pkg->CurrentVer == 0)) + return false; + + VerIterator V = Pkg.CurrentVer(); + if (V->MultiArch != Version::All) + return false; + + // Never ever kill an "all" package - they have no dependency so they can't be broken + if (strcmp(Pkg.Arch(),"all") == 0) + return false; + + unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy); + if ((CurDepState & DepInstMin) == DepInstMin) { + // okay, the package isn't broken, but is the package also required? + // If it has no real dependencies, no installed rdepends and doesn't + // provide something of value, we will kill it as not required. + // These pseudopackages have otherwise interesting effects if they get + // a new dependency in a newer version… + for (pkgCache::DepIterator D = V.DependsList(); + D.end() != true; ++D) + if (D.IsCritical() == true && D.ParentPkg()->Group != Pkg->Group) + return false; + for (DepIterator D = Pkg.RevDependsList(); D.end() != true; ++D) + { + if (D.IsCritical() == false) + continue; + PkgIterator const P = D.ParentPkg(); + if (P->Group == Pkg->Group) + continue; + if (P->CurrentVer != 0) + return false; + } + for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++) + for (DepIterator d = Prv.ParentPkg().RevDependsList(); + d.end() != true; ++d) + { + PkgIterator const P = d.ParentPkg(); + if (P->CurrentVer != 0 && + P->Group != Pkg->Group) + return false; + } + } + + // Dependencies for this arch all package are not statisfied + // so we installed it only for our convenience: get right of it now. + RemoveSizes(Pkg); + RemoveStates(Pkg); + + Pkg->CurrentVer = 0; + PkgState[Pkg->ID].InstallVer = 0; + + AddStates(Pkg); + Update(Pkg); + AddSizes(Pkg); + + // After the remove previously satisfied pseudo pkg could be now + // no longer satisfied, so we need to recheck the reverse dependencies + for (DepIterator d = Pkg.RevDependsList(); d.end() != true; ++d) + { + PkgIterator const P = d.ParentPkg(); + if (P->CurrentVer != 0) + recheck.insert(P.Index()); + } + + for (DepIterator d = V.DependsList(); d.end() != true; ++d) + { + PkgIterator const P = d.TargetPkg(); + for (PrvIterator Prv = P.ProvidesList(); Prv.end() != true; ++Prv) + { + PkgIterator const O = Prv.OwnerPkg(); + if (O->CurrentVer != 0) + recheck.insert(O.Index()); + } + + if (P->CurrentVer != 0) + recheck.insert(P.Index()); + } + + for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++) + { + for (DepIterator d = Prv.ParentPkg().RevDependsList(); + d.end() != true; ++d) + { + PkgIterator const P = d.ParentPkg(); + if (P->CurrentVer == 0) + continue; + + recheck.insert(P.Index()); + } + } + + + return true; +} + /*}}}*/ // DepCache::Update - Figure out all the state information /*{{{*/ // --------------------------------------------------------------------- /* This will figure out the state of all the packages and all the @@ -609,9 +749,13 @@ void pkgDepCache::Update(OpProgress *Prog) iKeepCount = 0; iBrokenCount = 0; iBadCount = 0; - + + std::set<unsigned long> recheck; + // Perform the depends pass int Done = 0; + bool const checkMultiArch = APT::Configuration::getArchitectures().size() > 1; + unsigned long killed = 0; for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++) { if (Prog != 0 && Done%20 == 0) @@ -619,7 +763,7 @@ void pkgDepCache::Update(OpProgress *Prog) for (VerIterator V = I.VersionList(); V.end() != true; V++) { unsigned char Group = 0; - + for (DepIterator D = V.DependsList(); D.end() != true; D++) { // Build the dependency state. @@ -637,21 +781,158 @@ void pkgDepCache::Update(OpProgress *Prog) D->Type == Dep::DpkgBreaks || D->Type == Dep::Obsoletes) State = ~State; - } + } } - // Compute the pacakge dependency state and size additions + // Compute the package dependency state and size additions AddSizes(I); UpdateVerState(I); AddStates(I); + + if (checkMultiArch != true || I->CurrentVer == 0) + continue; + + VerIterator const V = I.CurrentVer(); + if (V->MultiArch != Version::All) + continue; + + recheck.insert(I.Index()); + --Done; // no progress if we need to recheck the package } - if (Prog != 0) + if (checkMultiArch == true) { + /* FIXME: recheck breaks proper progress reporting as we don't know + how many packages we need to recheck. To lower the effect + a bit we increase with a kill, but we should do something more clever… */ + while(recheck.empty() == false) + for (std::set<unsigned long>::const_iterator p = recheck.begin(); + p != recheck.end(); ++p) { + if (Prog != 0 && Done%20 == 0) + Prog->Progress(Done); + PkgIterator P = PkgIterator(*Cache, Cache->PkgP + *p); + if (RemovePseudoInstalledPkg(P, recheck) == true) { + ++killed; + ++Done; + } + recheck.erase(p); + } + + /* Okay, we have killed a great amount of pseudopackages - + we have killed so many that we have now arch "all" packages + without an installed pseudo package, but we NEED an installed + pseudo package, so we will search now for a pseudo package + we can install without breaking everything. */ + for (GrpIterator G = Cache->GrpBegin(); G.end() != true; ++G) + { + PkgIterator P = G.FindPkg("all"); + if (P.end() == true) + continue; + if (P->CurrentVer == 0) + continue; + bool installed = false; + for (P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P)) + { + if (strcmp(P.Arch(), "all") == 0) + continue; + if (P->CurrentVer == 0) + continue; + installed = true; + break; + } + if (installed == false) + recheck.insert(G.Index()); + } + + while (recheck.empty() != true) + { + std::set<unsigned long>::const_iterator g = recheck.begin(); + unsigned long const G = *g; + recheck.erase(g); + if (unlikely(ReInstallPseudoForGroup(G, recheck) == false)) + _error->Warning(_("Internal error, group '%s' has no installable pseudo package"), GrpIterator(*Cache, Cache->GrpP + *g).Name()); + } + } + + if (Prog != 0) Prog->Progress(Done); readStateFile(Prog); } /*}}}*/ +// DepCache::ReInstallPseudoForGroup - MultiArch helper for Update() /*{{{*/ +// --------------------------------------------------------------------- +/* RemovePseudoInstalledPkg() is very successful. It even kills packages + to an amount that no pseudo package is left, but we need a pseudo package + for upgrading senarios so we need to reinstall one pseudopackage which + doesn't break everything. Thankfully we can't have architecture depending + negative dependencies so this problem is already eliminated */ +bool pkgDepCache::ReInstallPseudoForGroup(pkgCache::PkgIterator const &P, std::set<unsigned long> &recheck) +{ + if (P->CurrentVer != 0) + return true; + // recursive call for packages which provide this package + for (pkgCache::PrvIterator Prv = P.ProvidesList(); Prv.end() != true; ++Prv) + ReInstallPseudoForGroup(Prv.OwnerPkg(), recheck); + // check if we actually need to look at this group + unsigned long const G = P->Group; + std::set<unsigned long>::const_iterator Pi = recheck.find(G); + if (Pi == recheck.end()) + return true; + recheck.erase(Pi); // remove here, so we can't fall into an endless loop + if (unlikely(ReInstallPseudoForGroup(G, recheck) == false)) + { + recheck.insert(G); + return false; + } + return true; +} +bool pkgDepCache::ReInstallPseudoForGroup(unsigned long const &G, std::set<unsigned long> &recheck) +{ + std::vector<std::string> static const Archs = APT::Configuration::getArchitectures(); + pkgCache::GrpIterator Grp(*Cache, Cache->GrpP + G); + if (unlikely(Grp.end() == true)) + return false; + for (std::vector<std::string>::const_iterator a = Archs.begin(); + a != Archs.end(); ++a) + { + pkgCache::PkgIterator P = Grp.FindPkg(*a); + if (P.end() == true) + continue; + pkgCache::VerIterator allV = Grp.FindPkg("all").CurrentVer(); + for (VerIterator V = P.VersionList(); V.end() != true; ++V) + { + // search for the same version as the all package + if (allV->Hash != V->Hash || strcmp(allV.VerStr(),V.VerStr()) != 0) + continue; + unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy); + // If it is broken, try to install dependencies first before retry + if ((CurDepState & DepInstMin) != DepInstMin) + { + for (pkgCache::DepIterator D = V.DependsList(); D.end() != true; ++D) + { + if (D->Type != pkgCache::Dep::PreDepends && D->Type != pkgCache::Dep::Depends) + continue; + ReInstallPseudoForGroup(D.TargetPkg(), recheck); + } + unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy); + // if package ist still broken… try another arch + if ((CurDepState & DepInstMin) != DepInstMin) + break; + } + // dependencies satisfied: reinstall the package + RemoveSizes(P); + RemoveStates(P); + P->CurrentVer = V.Index(); + PkgState[P->ID].InstallVer = V; + AddStates(P); + Update(P); + AddSizes(P); + return true; + } + } + return false; +} + /*}}}*/ // DepCache::Update - Update the deps list of a package /*{{{*/ // --------------------------------------------------------------------- /* This is a helper for update that only does the dep portion of the scan. @@ -813,6 +1094,10 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge, AddStates(Pkg); Update(Pkg); AddSizes(Pkg); + + // if we remove the pseudo package, we also need to remove the "real" + if (Pkg->CurrentVer != 0 && Pkg.CurrentVer().Pseudo() == true) + MarkDelete(Pkg.Group().FindPkg("all"), rPurge, Depth+1, FromUser); } /*}}}*/ // DepCache::IsDeleteOk - check if it is ok to remove this package /*{{{*/ @@ -1339,7 +1624,7 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc) // debug output if(debug_autoremove && PkgState[p->ID].Flags & Flag::Auto) - std::clog << "AutoDep: " << p.Name() << std::endl; + std::clog << "AutoDep: " << p.FullName() << std::endl; } // init vars @@ -1373,13 +1658,18 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc) // MarkPackage - mark a single package in Mark-and-Sweep /*{{{*/ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, const pkgCache::VerIterator &ver, - bool follow_recommends, - bool follow_suggests) + bool const &follow_recommends, + bool const &follow_suggests) { pkgDepCache::StateCache &state = PkgState[pkg->ID]; - VerIterator currver = pkg.CurrentVer(); - VerIterator candver = state.CandidateVerIter(*this); - VerIterator instver = state.InstVerIter(*this); + + // if we are marked already we are done + if(state.Marked) + return; + + VerIterator const currver = pkg.CurrentVer(); + VerIterator const candver = state.CandidateVerIter(*this); + VerIterator const instver = state.InstVerIter(*this); #if 0 // If a package was garbage-collected but is now being marked, we @@ -1405,15 +1695,11 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, !(ver == currver && instver.end() && !ver.end())) return; - // if we are marked already we are done - if(state.Marked) - return; + bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove", false); - bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove", false); - if(debug_autoremove) { - std::clog << "Marking: " << pkg.Name(); + std::clog << "Marking: " << pkg.FullName(); if(!ver.end()) std::clog << " " << ver.VerStr(); if(!currver.end()) @@ -1425,8 +1711,34 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, state.Marked=true; - if(!ver.end()) + if(ver.end() == true) + return; + + // If the version belongs to a Multi-Arch all package + // we will mark all others in this Group with this version also + // Beware: We compare versions here the lazy way: string comparision + // this is bad if multiple repositories provide different versions + // of the package with an identical version number - but even in this + // case the dependencies are likely the same. + if (ver->MultiArch == pkgCache::Version::All && + strcmp(ver.Arch(true), "all") == 0) { + GrpIterator G = pkg.Group(); + const char* const VerStr = ver.VerStr(); + for (PkgIterator P = G.FindPkg("any"); + P.end() != true; P = G.NextPkg(P)) + { + for (VerIterator V = P.VersionList(); + V.end() != true; ++V) + { + if (strcmp(VerStr, V.VerStr()) != 0) + continue; + MarkPackage(P, V, follow_recommends, follow_suggests); + break; + } + } + } + for(DepIterator d = ver.DependsList(); !d.end(); ++d) { if(d->Type == Dep::Depends || @@ -1444,10 +1756,9 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, { if(debug_autoremove) { - std::clog << "Following dep: " << d.ParentPkg().Name() + std::clog << "Following dep: " << d.ParentPkg().FullName() << " " << d.ParentVer().VerStr() << " " - << d.DepType() << " " - << d.TargetPkg().Name(); + << d.DepType() << " " << d.TargetPkg().FullName(); if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp) { std::clog << " (" << d.CompType() << " " @@ -1455,7 +1766,7 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, } std::clog << std::endl; } - MarkPackage(V.ParentPkg(), V, + MarkPackage(V.ParentPkg(), V, follow_recommends, follow_suggests); } } @@ -1468,17 +1779,16 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, { if(debug_autoremove) { - std::clog << "Following dep: " << d.ParentPkg().Name() - << " " << d.ParentVer().VerStr() << " " - << d.DepType() << " " - << d.TargetPkg().Name(); + std::clog << "Following dep: " << d.ParentPkg().FullName() << " " + << d.ParentVer().VerStr() << " " + << d.DepType() << " " << d.TargetPkg().FullName() << " "; if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp) { std::clog << " (" << d.CompType() << " " << d.TargetVer() << ")"; } std::clog << ", provided by " - << prv.OwnerPkg().Name() << " " + << prv.OwnerPkg().FullName() << " " << prv.OwnerVer().VerStr() << std::endl; } @@ -1489,7 +1799,6 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, } } } - } } /*}}}*/ bool pkgDepCache::Sweep() /*{{{*/ @@ -1511,7 +1820,7 @@ bool pkgDepCache::Sweep() /*{{{*/ { state.Garbage=true; if(debug_autoremove) - std::cout << "Garbage: " << p.Name() << std::endl; + std::clog << "Garbage: " << p.FullName() << std::endl; } } diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h index 0306861a1..3decc7a5f 100644 --- a/apt-pkg/depcache.h +++ b/apt-pkg/depcache.h @@ -46,6 +46,7 @@ #include <vector> #include <memory> +#include <set> class pkgDepCache : protected pkgCache::Namespace { @@ -78,8 +79,8 @@ class pkgDepCache : protected pkgCache::Namespace */ void MarkPackage(const pkgCache::PkgIterator &pkg, const pkgCache::VerIterator &ver, - bool follow_recommends, - bool follow_suggests); + bool const &follow_recommends, + bool const &follow_suggests); /** \brief Update the Marked field of all packages. * @@ -330,8 +331,11 @@ class pkgDepCache : protected pkgCache::Namespace // Legacy.. We look like a pkgCache inline operator pkgCache &() {return *Cache;}; inline Header &Head() {return *Cache->HeaderP;}; + inline GrpIterator GrpBegin() {return Cache->GrpBegin();}; inline PkgIterator PkgBegin() {return Cache->PkgBegin();}; + inline GrpIterator FindGrp(string const &Name) {return Cache->FindGrp(Name);}; inline PkgIterator FindPkg(string const &Name) {return Cache->FindPkg(Name);}; + inline PkgIterator FindPkg(string const &Name, string const &Arch) {return Cache->FindPkg(Name, Arch);}; inline pkgCache &GetCache() {return *Cache;}; inline pkgVersioningSystem &VS() {return *Cache->VS;}; @@ -442,12 +446,9 @@ class pkgDepCache : protected pkgCache::Namespace virtual bool IsDeleteOk(const PkgIterator &Pkg,bool Purge = false, unsigned long Depth = 0, bool FromUser = true); - // This is for debuging - void Update(OpProgress *Prog = 0); - // read persistent states bool readStateFile(OpProgress *prog); - bool writeStateFile(OpProgress *prog, bool InstalledOnly=false); + bool writeStateFile(OpProgress *prog, bool InstalledOnly=true); // Size queries inline double UsrSize() {return iUsrSize;}; @@ -460,9 +461,17 @@ class pkgDepCache : protected pkgCache::Namespace inline unsigned long BadCount() {return iBadCount;}; bool Init(OpProgress *Prog); - + // Generate all state information + void Update(OpProgress *Prog = 0); + pkgDepCache(pkgCache *Cache,Policy *Plcy = 0); virtual ~pkgDepCache(); + + private: + // Helper for Update(OpProgress) to remove pseudoinstalled arch all packages + bool RemovePseudoInstalledPkg(PkgIterator &Pkg, std::set<unsigned long> &recheck); + bool ReInstallPseudoForGroup(unsigned long const &Grp, std::set<unsigned long> &recheck); + bool ReInstallPseudoForGroup(pkgCache::PkgIterator const &P, std::set<unsigned long> &recheck); }; #endif diff --git a/apt-pkg/indexfile.cc b/apt-pkg/indexfile.cc index 2f5bc2439..37be87055 100644 --- a/apt-pkg/indexfile.cc +++ b/apt-pkg/indexfile.cc @@ -8,9 +8,9 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ -#include <apt-pkg/configuration.h> #include <apt-pkg/indexfile.h> #include <apt-pkg/error.h> +#include <apt-pkg/aptconfiguration.h> #include <clocale> #include <cstring> @@ -66,34 +66,23 @@ string pkgIndexFile::SourceInfo(pkgSrcRecords::Parser const &Record, return string(); } /*}}}*/ -// IndexFile::TranslationsAvailable - Check if will use Translation /*{{{*/ +// IndexFile::TranslationsAvailable - Check if will use Translation /*{{{*/ // --------------------------------------------------------------------- /* */ -bool pkgIndexFile::TranslationsAvailable() -{ - const string Translation = _config->Find("APT::Acquire::Translation"); - - if (Translation.compare("none") != 0) - return CheckLanguageCode(LanguageCode().c_str()); - else - return false; +bool pkgIndexFile::TranslationsAvailable() { + return (APT::Configuration::getLanguages().empty() != true); } /*}}}*/ -// IndexFile::CheckLanguageCode - Check the Language Code /*{{{*/ +// IndexFile::CheckLanguageCode - Check the Language Code /*{{{*/ // --------------------------------------------------------------------- -/* */ -/* common cases: de_DE, de_DE@euro, de_DE.UTF-8, de_DE.UTF-8@euro, - de_DE.ISO8859-1, tig_ER - more in /etc/gdm/locale.conf -*/ - -bool pkgIndexFile::CheckLanguageCode(const char *Lang) +/* No intern need for this method anymore as the check for correctness + is already done in getLanguages(). Note also that this check is + rather bad (doesn't take three character like ast into account). + TODO: Remove method with next API break */ +__attribute__ ((deprecated)) bool pkgIndexFile::CheckLanguageCode(const char *Lang) { - if (strlen(Lang) == 2 || - strlen(Lang) == 3 || - (strlen(Lang) > 3 && Lang[3] == '_') || - (strlen(Lang) == 5 && Lang[2] == '_')) - return true; + if (strlen(Lang) == 2 || (strlen(Lang) == 5 && Lang[2] == '_')) + return true; if (strcmp(Lang,"C") != 0) _error->Warning("Wrong language code %s", Lang); @@ -101,37 +90,14 @@ bool pkgIndexFile::CheckLanguageCode(const char *Lang) return false; } /*}}}*/ -// IndexFile::LanguageCode - Return the Language Code /*{{{*/ +// IndexFile::LanguageCode - Return the Language Code /*{{{*/ // --------------------------------------------------------------------- -/* return the language code */ -string pkgIndexFile::LanguageCode() -{ - const string Translation = _config->Find("APT::Acquire::Translation"); - - if (Translation.compare("environment") == 0) - { - string lang = std::setlocale(LC_MESSAGES,NULL); - - // we have a mapping of the language codes that contains all the language - // codes that need the country code as well - // (like pt_BR, pt_PT, sv_SE, zh_*, en_*) - const char *need_full_langcode[] = { "en_", - "pt_", - "sv_", - "zh_", - NULL }; - for(const char **s = need_full_langcode;*s != NULL; s++) - if(lang.find(*s) == 0) - return lang.substr(0,5); - - if(lang.find("_") != lang.npos) - return lang.substr(0, lang.find("_")); - else if(lang.find(".") != lang.npos) - return lang.substr(0, lang.find(".")); - else - return lang; - } - else - return Translation; +/* As we have now possibly more than one LanguageCode this method is + supersided by a) private classmembers or b) getLanguages(). + TODO: Remove method with next API break */ +__attribute__ ((deprecated)) string pkgIndexFile::LanguageCode() { + if (TranslationsAvailable() == false) + return ""; + return APT::Configuration::getLanguages()[0]; } /*}}}*/ diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc index e2f847ed2..21472eb3b 100644 --- a/apt-pkg/init.cc +++ b/apt-pkg/init.cc @@ -95,10 +95,10 @@ bool pkgInitConfig(Configuration &Cnf) // Read the configuration parts dir string Parts = Cnf.FindDir("Dir::Etc::parts"); - if (FileExists(Parts) == true) + if (DirectoryExists(Parts) == true) Res &= ReadConfigDir(Cnf,Parts); else - _error->WarningE("FileExists",_("Unable to read %s"),Parts.c_str()); + _error->WarningE("DirectoryExists",_("Unable to read %s"),Parts.c_str()); // Read the main config file string FName = Cnf.FindFile("Dir::Etc::main"); diff --git a/apt-pkg/init.h b/apt-pkg/init.h index f0757f644..b3e4b147f 100644 --- a/apt-pkg/init.h +++ b/apt-pkg/init.h @@ -22,7 +22,7 @@ // Non-ABI-Breaks should only increase RELEASE number. // See also buildlib/libversion.mak #define APT_PKG_MAJOR 4 -#define APT_PKG_MINOR 8 +#define APT_PKG_MINOR 9 #define APT_PKG_RELEASE 0 extern const char *pkgVersion; diff --git a/apt-pkg/makefile b/apt-pkg/makefile index bdd49c089..148ad581b 100644 --- a/apt-pkg/makefile +++ b/apt-pkg/makefile @@ -25,7 +25,7 @@ SOURCE = contrib/mmap.cc contrib/error.cc contrib/strutl.cc \ contrib/fileutl.cc HEADERS = mmap.h error.h configuration.h fileutl.h cmndline.h netrc.h\ md5.h crc-16.h cdromutl.h strutl.h sptr.h sha1.h sha256.h hashes.h \ - macros.h + macros.h weakptr.h # Source code for the core main library SOURCE+= pkgcache.cc version.cc depcache.cc \ diff --git a/apt-pkg/metaindex.h b/apt-pkg/metaindex.h index 779b6ab14..1d2140799 100644 --- a/apt-pkg/metaindex.h +++ b/apt-pkg/metaindex.h @@ -33,8 +33,8 @@ class metaIndex virtual const char* GetType() const {return Type;} // Interface for acquire - virtual string ArchiveURI(string /*File*/) const = 0; - virtual bool GetIndexes(pkgAcquire *Owner, bool GetAll=false) const = 0; + virtual string ArchiveURI(string const& /*File*/) const = 0; + virtual bool GetIndexes(pkgAcquire *Owner, bool const &GetAll=false) const = 0; virtual vector<pkgIndexFile *> *GetIndexFiles() = 0; virtual bool IsTrusted() const = 0; diff --git a/apt-pkg/orderlist.cc b/apt-pkg/orderlist.cc index 0ee2e2bc8..7c950292a 100644 --- a/apt-pkg/orderlist.cc +++ b/apt-pkg/orderlist.cc @@ -126,6 +126,11 @@ bool pkgOrderList::IsMissing(PkgIterator Pkg) if (FileList[Pkg->ID].empty() == false) return false; + + // Missing Pseudo packages are missing if the real package is missing + if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == true) + return IsMissing(Pkg.Group().FindPkg("all")); + return true; } /*}}}*/ @@ -199,7 +204,7 @@ bool pkgOrderList::OrderCritical() { PkgIterator P(Cache,*I); if (IsNow(P) == true) - clog << " " << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl; + clog << " " << P.FullName() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl; } } @@ -272,7 +277,7 @@ bool pkgOrderList::OrderUnpack(string *FileList) { PkgIterator P(Cache,*I); if (IsNow(P) == true) - clog << " " << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl; + clog << " " << P.FullName() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl; } } @@ -543,7 +548,7 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg) if (Debug == true) { for (int j = 0; j != Depth; j++) clog << ' '; - clog << "Visit " << Pkg.Name() << endl; + clog << "Visit " << Pkg.FullName() << endl; } Depth++; @@ -602,7 +607,7 @@ bool pkgOrderList::VisitNode(PkgIterator Pkg) if (Debug == true) { for (int j = 0; j != Depth; j++) clog << ' '; - clog << "Leave " << Pkg.Name() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl; + clog << "Leave " << Pkg.FullName() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl; } return true; diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index b747fa78a..eef79cccd 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -80,7 +80,10 @@ bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources, // Skip already processed packages if (List->IsNow(Pkg) == false) continue; - + + if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == true) + continue; + new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache), FileNames[Pkg->ID]); } @@ -277,8 +280,10 @@ bool pkgPackageManager::ConfigureAll() for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++) { PkgIterator Pkg(Cache,*I); - - if (ConfigurePkgs == true && Configure(Pkg) == false) + + if (ConfigurePkgs == true && + pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false && + Configure(Pkg) == false) return false; List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States); @@ -313,7 +318,9 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg) { PkgIterator Pkg(Cache,*I); - if (ConfigurePkgs == true && Configure(Pkg) == false) + if (ConfigurePkgs == true && + pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false && + Configure(Pkg) == false) return false; List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States); @@ -465,7 +472,12 @@ bool pkgPackageManager::SmartRemove(PkgIterator Pkg) return true; List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States); - return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge); + + if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false) + return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge); + else + return SmartRemove(Pkg.Group().FindPkg("all")); + return true; } /*}}}*/ // PM::SmartUnPack - Install helper /*{{{*/ @@ -579,10 +591,22 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) for (PrvIterator P = Cache[Pkg].InstVerIter(Cache).ProvidesList(); P.end() == false; P++) CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion()); - - if (Install(Pkg,FileNames[Pkg->ID]) == false) - return false; - + + if (pkgCache::VerIterator(Cache, Cache[Pkg].CandidateVer).Pseudo() == false) + { + if(Install(Pkg,FileNames[Pkg->ID]) == false) + return false; + } else { + // Pseudo packages will not be unpacked - instead we will do this + // for the "real" package, but only once and if it is already + // configured we don't need to unpack it again… + PkgIterator const P = Pkg.Group().FindPkg("all"); + if (List->IsFlag(P,pkgOrderList::UnPacked) != true && + List->IsFlag(P,pkgOrderList::Configured) != true) { + if (SmartUnPack(P) == false) + return false; + } + } List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States); // Perform immedate configuration of the package. diff --git a/apt-pkg/packagemanager.h b/apt-pkg/packagemanager.h index 44f5d5ef7..efd2cfac6 100644 --- a/apt-pkg/packagemanager.h +++ b/apt-pkg/packagemanager.h @@ -28,6 +28,7 @@ #include <iostream> #include <apt-pkg/pkgcache.h> #include <apt-pkg/depcache.h> +#include <set> using std::string; @@ -47,13 +48,17 @@ class pkgPackageManager : protected pkgCache::Namespace pkgDepCache &Cache; pkgOrderList *List; bool Debug; - + + /** \brief saves packages dpkg let disappear + + This way APT can retreat from trying to configure these + packages later on and a frontend can choose to display a + notice to inform the user about these disappears. + */ + std::set<std::string> disappearedPkgs; + bool DepAdd(pkgOrderList &Order,PkgIterator P,int Depth = 0); - // binary-compat change, fix on next abi break - void ImmediateAdd(PkgIterator P, bool UseInstallVer) { - ImmediateAdd(P, UseInstallVer, 0); - } - void ImmediateAdd(PkgIterator P, bool UseInstallVer, unsigned const int &Depth); + void ImmediateAdd(PkgIterator P, bool UseInstallVer, unsigned const int &Depth = 0); virtual OrderResult OrderInstall(); bool CheckRConflicts(PkgIterator Pkg,DepIterator Dep,const char *Ver); bool CreateOrderList(); @@ -97,7 +102,10 @@ class pkgPackageManager : protected pkgCache::Namespace // stuff that needs to be done after the fork OrderResult DoInstallPostFork(int statusFd=-1); bool FixMissing(); - + + /** \brief returns all packages dpkg let disappear */ + inline std::set<std::string> GetDisappearedPackages() { return disappearedPkgs; }; + pkgPackageManager(pkgDepCache *Cache); virtual ~pkgPackageManager(); }; diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index 4a0f3ee58..a59a06d65 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -22,11 +22,12 @@ // Include Files /*{{{*/ #include <apt-pkg/pkgcache.h> #include <apt-pkg/policy.h> -#include <apt-pkg/indexfile.h> #include <apt-pkg/version.h> #include <apt-pkg/error.h> #include <apt-pkg/strutl.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/aptconfiguration.h> +#include <apt-pkg/macros.h> #include <apti18n.h> @@ -54,6 +55,7 @@ pkgCache::Header::Header() Dirty = false; HeaderSz = sizeof(pkgCache::Header); + GroupSz = sizeof(pkgCache::Group); PackageSz = sizeof(pkgCache::Package); PackageFileSz = sizeof(pkgCache::PackageFile); VersionSz = sizeof(pkgCache::Version); @@ -63,6 +65,7 @@ pkgCache::Header::Header() VerFileSz = sizeof(pkgCache::VerFile); DescFileSz = sizeof(pkgCache::DescFile); + GroupCount = 0; PackageCount = 0; VersionCount = 0; DescriptionCount = 0; @@ -78,7 +81,8 @@ pkgCache::Header::Header() StringList = 0; VerSysName = 0; Architecture = 0; - memset(HashTable,0,sizeof(HashTable)); + memset(PkgHashTable,0,sizeof(PkgHashTable)); + memset(GrpHashTable,0,sizeof(GrpHashTable)); memset(Pools,0,sizeof(Pools)); } /*}}}*/ @@ -88,6 +92,7 @@ pkgCache::Header::Header() bool pkgCache::Header::CheckSizes(Header &Against) const { if (HeaderSz == Against.HeaderSz && + GroupSz == Against.GroupSz && PackageSz == Against.PackageSz && PackageFileSz == Against.PackageFileSz && VersionSz == Against.VersionSz && @@ -106,6 +111,7 @@ bool pkgCache::Header::CheckSizes(Header &Against) const /* */ pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map) { + MultiArchEnabled = APT::Configuration::getArchitectures().size() > 1; if (DoMap == true) ReMap(); } @@ -117,6 +123,7 @@ bool pkgCache::ReMap() { // Apply the typecasts. HeaderP = (Header *)Map.Data(); + GrpP = (Group *)Map.Data(); PkgP = (Package *)Map.Data(); VerFileP = (VerFile *)Map.Data(); DescFileP = (DescFile *)Map.Data(); @@ -164,7 +171,7 @@ unsigned long pkgCache::sHash(const string &Str) const unsigned long Hash = 0; for (string::const_iterator I = Str.begin(); I != Str.end(); I++) Hash = 5*Hash + tolower_ascii(*I); - return Hash % _count(HeaderP->HashTable); + return Hash % _count(HeaderP->PkgHashTable); } unsigned long pkgCache::sHash(const char *Str) const @@ -172,26 +179,82 @@ unsigned long pkgCache::sHash(const char *Str) const unsigned long Hash = 0; for (const char *I = Str; *I != 0; I++) Hash = 5*Hash + tolower_ascii(*I); - return Hash % _count(HeaderP->HashTable); + return Hash % _count(HeaderP->PkgHashTable); } /*}}}*/ -// Cache::FindPkg - Locate a package by name /*{{{*/ +// Cache::SingleArchFindPkg - Locate a package by name /*{{{*/ // --------------------------------------------------------------------- -/* Returns 0 on error, pointer to the package otherwise */ -pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) +/* Returns 0 on error, pointer to the package otherwise + The multiArch enabled methods will fallback to this one as it is (a bit) + faster for single arch environments and realworld is mostly singlearch… */ +pkgCache::PkgIterator pkgCache::SingleArchFindPkg(const string &Name) { // Look at the hash bucket - Package *Pkg = PkgP + HeaderP->HashTable[Hash(Name)]; + Package *Pkg = PkgP + HeaderP->PkgHashTable[Hash(Name)]; for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage) { if (Pkg->Name != 0 && StrP[Pkg->Name] == Name[0] && - stringcasecmp(Name,StrP + Pkg->Name) == 0) - return PkgIterator(*this,Pkg); + stringcasecmp(Name,StrP + Pkg->Name) == 0) + return PkgIterator(*this,Pkg); } return PkgIterator(*this,0); } /*}}}*/ +// Cache::FindPkg - Locate a package by name /*{{{*/ +// --------------------------------------------------------------------- +/* Returns 0 on error, pointer to the package otherwise */ +pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) { + if (MultiArchCache() == false) + return SingleArchFindPkg(Name); + size_t const found = Name.find(':'); + if (found == string::npos) + return FindPkg(Name, "native"); + string const Arch = Name.substr(found+1); + if (Arch == "any") + return FindPkg(Name, "any"); + return FindPkg(Name.substr(0, found), Arch); +} + /*}}}*/ +// Cache::FindPkg - Locate a package by name /*{{{*/ +// --------------------------------------------------------------------- +/* Returns 0 on error, pointer to the package otherwise */ +pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string const &Arch) { + if (MultiArchCache() == false) { + if (Arch == "native" || Arch == "all" || Arch == "any" || + Arch == _config->Find("APT::Architecture")) + return SingleArchFindPkg(Name); + else + return PkgIterator(*this,0); + } + /* We make a detour via the GrpIterator here as + on a multi-arch environment a group is easier to + find than a package (less entries in the buckets) */ + pkgCache::GrpIterator Grp = FindGrp(Name); + if (Grp.end() == true) + return PkgIterator(*this,0); + + return Grp.FindPkg(Arch); +} + /*}}}*/ +// Cache::FindGrp - Locate a group by name /*{{{*/ +// --------------------------------------------------------------------- +/* Returns End-Pointer on error, pointer to the group otherwise */ +pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) { + if (unlikely(Name.empty() == true)) + return GrpIterator(*this,0); + + // Look at the hash bucket for the group + Group *Grp = GrpP + HeaderP->GrpHashTable[sHash(Name)]; + for (; Grp != GrpP; Grp = GrpP + Grp->Next) { + if (Grp->Name != 0 && StrP[Grp->Name] == Name[0] && + stringcasecmp(Name, StrP + Grp->Name) == 0) + return GrpIterator(*this, Grp); + } + + return GrpIterator(*this,0); +} + /*}}}*/ // Cache::CompTypeDeb - Return a string describing the compare type /*{{{*/ // --------------------------------------------------------------------- /* This returns a string representation of the dependency compare @@ -241,11 +304,77 @@ const char *pkgCache::Priority(unsigned char Prio) return 0; } /*}}}*/ -// Bases for iterator classes /*{{{*/ -void pkgCache::VerIterator::_dummy() {} -void pkgCache::DepIterator::_dummy() {} -void pkgCache::PrvIterator::_dummy() {} -void pkgCache::DescIterator::_dummy() {} +// GrpIterator::FindPkg - Locate a package by arch /*{{{*/ +// --------------------------------------------------------------------- +/* Returns an End-Pointer on error, pointer to the package otherwise */ +pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) { + if (unlikely(IsGood() == false || S->FirstPackage == 0)) + return PkgIterator(*Owner, 0); + + static string const myArch = _config->Find("APT::Architecture"); + /* Most of the time the package for our native architecture is + the one we add at first to the cache, but this would be the + last one we check, so we do it now. */ + if (Arch == "native" || Arch == myArch) { + Arch = myArch; + pkgCache::Package *Pkg = Owner->PkgP + S->LastPackage; + if (stringcasecmp(Arch, Owner->StrP + Pkg->Arch) == 0) + return PkgIterator(*Owner, Pkg); + } + + /* If we accept any package we simply return the "first" + package in this group (the last one added). */ + if (Arch == "any") + return PkgIterator(*Owner, Owner->PkgP + S->FirstPackage); + + /* Iterate over the list to find the matching arch + unfortunately this list includes "package noise" + (= different packages with same calculated hash), + so we need to check the name also */ + for (pkgCache::Package *Pkg = PackageList(); Pkg != Owner->PkgP; + Pkg = Owner->PkgP + Pkg->NextPackage) { + if (S->Name == Pkg->Name && + stringcasecmp(Arch, Owner->StrP + Pkg->Arch) == 0) + return PkgIterator(*Owner, Pkg); + if ((Owner->PkgP + S->LastPackage) == Pkg) + break; + } + + return PkgIterator(*Owner, 0); +} + /*}}}*/ +// GrpIterator::NextPkg - Locate the next package in the group /*{{{*/ +// --------------------------------------------------------------------- +/* Returns an End-Pointer on error, pointer to the package otherwise. + We can't simply ++ to the next as the next package of the last will + be from a different group (with the same hash value) */ +pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const &LastPkg) { + if (unlikely(IsGood() == false || S->FirstPackage == 0 || + LastPkg.end() == true)) + return PkgIterator(*Owner, 0); + + if (S->LastPackage == LastPkg.Index()) + return PkgIterator(*Owner, 0); + + return PkgIterator(*Owner, Owner->PkgP + LastPkg->NextPackage); +} + /*}}}*/ +// GrpIterator::operator ++ - Postfix incr /*{{{*/ +// --------------------------------------------------------------------- +/* This will advance to the next logical group in the hash table. */ +void pkgCache::GrpIterator::operator ++(int) +{ + // Follow the current links + if (S != Owner->GrpP) + S = Owner->GrpP + S->Next; + + // Follow the hash table + while (S == Owner->GrpP && (HashIndex+1) < (signed)_count(Owner->HeaderP->GrpHashTable)) + { + HashIndex++; + S = Owner->GrpP + Owner->HeaderP->GrpHashTable[HashIndex]; + } +}; /*}}}*/ // PkgIterator::operator ++ - Postfix incr /*{{{*/ // --------------------------------------------------------------------- @@ -253,14 +382,14 @@ void pkgCache::DescIterator::_dummy() {} void pkgCache::PkgIterator::operator ++(int) { // Follow the current links - if (Pkg != Owner->PkgP) - Pkg = Owner->PkgP + Pkg->NextPackage; + if (S != Owner->PkgP) + S = Owner->PkgP + S->NextPackage; // Follow the hash table - while (Pkg == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->HashTable)) + while (S == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->PkgHashTable)) { HashIndex++; - Pkg = Owner->PkgP + Owner->HeaderP->HashTable[HashIndex]; + S = Owner->PkgP + Owner->HeaderP->PkgHashTable[HashIndex]; } }; /*}}}*/ @@ -269,12 +398,12 @@ void pkgCache::PkgIterator::operator ++(int) /* By this we mean if it is either cleanly installed or cleanly removed. */ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const { - if (Pkg->InstState == pkgCache::State::ReInstReq || - Pkg->InstState == pkgCache::State::HoldReInstReq) + if (S->InstState == pkgCache::State::ReInstReq || + S->InstState == pkgCache::State::HoldReInstReq) return NeedsUnpack; - if (Pkg->CurrentState == pkgCache::State::UnPacked || - Pkg->CurrentState == pkgCache::State::HalfConfigured) + if (S->CurrentState == pkgCache::State::UnPacked || + S->CurrentState == pkgCache::State::HalfConfigured) // we leave triggers alone complettely. dpkg deals with // them in a hard-to-predict manner and if they get // resolved by dpkg before apt run dpkg --configure on @@ -283,8 +412,8 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const //Pkg->CurrentState == pkgCache::State::TriggersPending) return NeedsConfigure; - if (Pkg->CurrentState == pkgCache::State::HalfInstalled || - Pkg->InstState != pkgCache::State::Ok) + if (S->CurrentState == pkgCache::State::HalfInstalled || + S->InstState != pkgCache::State::Ok) return NeedsUnpack; return NeedsNothing; @@ -331,7 +460,7 @@ operator<<(ostream& out, pkgCache::PkgIterator Pkg) string candidate = string(Pkg.CandVersion() == 0 ? "none" : Pkg.CandVersion()); string newest = string(Pkg.VersionList().end() ? "none" : Pkg.VersionList().VerStr()); - out << Pkg.Name() << " < " << current; + out << Pkg.Name() << " [ " << Pkg.Arch() << " ] < " << current; if (current != candidate) out << " -> " << candidate; if ( newest != "none" && candidate != newest) @@ -340,17 +469,29 @@ operator<<(ostream& out, pkgCache::PkgIterator Pkg) return out; } /*}}}*/ +// PkgIterator::FullName - Returns Name and (maybe) Architecture /*{{{*/ +// --------------------------------------------------------------------- +/* Returns a name:arch string */ +std::string pkgCache::PkgIterator::FullName(bool const &Pretty) const +{ + string fullname = Name(); + if (Pretty == false || + (strcmp(Arch(), "all") != 0 && _config->Find("APT::Architecture") != Arch())) + return fullname.append(":").append(Arch()); + return fullname; +} + /*}}}*/ // DepIterator::IsCritical - Returns true if the dep is important /*{{{*/ // --------------------------------------------------------------------- /* Currently critical deps are defined as depends, predepends and conflicts (including dpkg's Breaks fields). */ bool pkgCache::DepIterator::IsCritical() { - if (Dep->Type == pkgCache::Dep::Conflicts || - Dep->Type == pkgCache::Dep::DpkgBreaks || - Dep->Type == pkgCache::Dep::Obsoletes || - Dep->Type == pkgCache::Dep::Depends || - Dep->Type == pkgCache::Dep::PreDepends) + if (S->Type == pkgCache::Dep::Conflicts || + S->Type == pkgCache::Dep::DpkgBreaks || + S->Type == pkgCache::Dep::Obsoletes || + S->Type == pkgCache::Dep::Depends || + S->Type == pkgCache::Dep::PreDepends) return true; return false; } @@ -429,12 +570,12 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() // Walk along the actual package providing versions for (VerIterator I = DPkg.VersionList(); I.end() == false; I++) { - if (Owner->VS->CheckDep(I.VerStr(),Dep->CompareOp,TargetVer()) == false) + if (Owner->VS->CheckDep(I.VerStr(),S->CompareOp,TargetVer()) == false) continue; - if ((Dep->Type == pkgCache::Dep::Conflicts || - Dep->Type == pkgCache::Dep::DpkgBreaks || - Dep->Type == pkgCache::Dep::Obsoletes) && + if ((S->Type == pkgCache::Dep::Conflicts || + S->Type == pkgCache::Dep::DpkgBreaks || + S->Type == pkgCache::Dep::Obsoletes) && ParentPkg() == I.ParentPkg()) continue; @@ -446,12 +587,12 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() // Follow all provides for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++) { - if (Owner->VS->CheckDep(I.ProvideVersion(),Dep->CompareOp,TargetVer()) == false) + if (Owner->VS->CheckDep(I.ProvideVersion(),S->CompareOp,TargetVer()) == false) continue; - if ((Dep->Type == pkgCache::Dep::Conflicts || - Dep->Type == pkgCache::Dep::DpkgBreaks || - Dep->Type == pkgCache::Dep::Obsoletes) && + if ((S->Type == pkgCache::Dep::Conflicts || + S->Type == pkgCache::Dep::DpkgBreaks || + S->Type == pkgCache::Dep::Obsoletes) && ParentPkg() == I.OwnerPkg()) continue; @@ -489,7 +630,7 @@ void pkgCache::DepIterator::GlobOr(DepIterator &Start,DepIterator &End) End = *this; for (bool LastOR = true; end() == false && LastOR == true;) { - LastOR = (Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or; + LastOR = (S->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or; (*this)++; if (LastOR == true) End = (*this); @@ -544,6 +685,23 @@ bool pkgCache::VerIterator::Automatic() const return false; } /*}}}*/ +// VerIterator::Pseudo - Check if this version is a pseudo one /*{{{*/ +// --------------------------------------------------------------------- +/* Sometimes you have the need to express dependencies with versions + which doesn't really exist or exist multiply times for "different" + packages. We need these versions for dependency resolution but they + are a problem everytime we need to download/install something. */ +bool pkgCache::VerIterator::Pseudo() const +{ + if (S->MultiArch == pkgCache::Version::All && + strcmp(Arch(true),"all") != 0) + { + GrpIterator const Grp = ParentPkg().Group(); + return (Grp->LastPackage != Grp->FirstPackage); + } + return false; +} + /*}}}*/ // VerIterator::NewestFile - Return the newest file version relation /*{{{*/ // --------------------------------------------------------------------- /* This looks at the version numbers associated with all of the sources @@ -624,7 +782,9 @@ string pkgCache::VerIterator::RelStr() else Res += File.Site(); } - } + } + if (S->ParentPkg != 0) + Res.append(" [").append(Arch()).append("]"); return Res; } /*}}}*/ @@ -639,7 +799,7 @@ bool pkgCache::PkgFileIterator::IsOk() if (stat(FileName(),&Buf) != 0) return false; - if (Buf.st_size != (signed)File->Size || Buf.st_mtime != File->mtime) + if (Buf.st_size != (signed)S->Size || Buf.st_mtime != S->mtime) return false; return true; @@ -663,6 +823,8 @@ string pkgCache::PkgFileIterator::RelStr() Res = Res + (Res.empty() == true?"l=":",l=") + Label(); if (Component() != 0) Res = Res + (Res.empty() == true?"c=":",c=") + Component(); + if (Architecture() != 0) + Res = Res + (Res.empty() == true?"b=":",b=") + Architecture(); return Res; } /*}}}*/ @@ -673,14 +835,22 @@ string pkgCache::PkgFileIterator::RelStr() */ pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const { - pkgCache::DescIterator DescDefault = DescriptionList(); - pkgCache::DescIterator Desc = DescDefault; - for (; Desc.end() == false; Desc++) - if (pkgIndexFile::LanguageCode() == Desc.LanguageCode()) - break; - if (Desc.end() == true) - Desc = DescDefault; - return Desc; + std::vector<string> const lang = APT::Configuration::getLanguages(); + for (std::vector<string>::const_iterator l = lang.begin(); + l != lang.end(); l++) + { + pkgCache::DescIterator DescDefault = DescriptionList(); + pkgCache::DescIterator Desc = DescDefault; + + for (; Desc.end() == false; Desc++) + if (*l == Desc.LanguageCode()) + break; + if (Desc.end() == true) + Desc = DescDefault; + return Desc; + } + + return DescriptionList(); }; /*}}}*/ diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h index 38733713f..643f240b0 100644 --- a/apt-pkg/pkgcache.h +++ b/apt-pkg/pkgcache.h @@ -1,20 +1,75 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: pkgcache.h,v 1.25 2001/07/01 22:28:24 jgg Exp $ -/* ###################################################################### - - Cache - Structure definitions for the cache file - - Please see doc/apt-pkg/cache.sgml for a more detailed description of - this format. Also be sure to keep that file up-to-date!! - +/**\file pkgcache.h + \brief pkgCache - Structure definitions for the cache file + + The goal of the cache file is two fold: + Firstly to speed loading and processing of the package file array and + secondly to reduce memory consumption of the package file array. + + The implementation is aimed at an environment with many primary package + files, for instance someone that has a Package file for their CD-ROM, a + Package file for the latest version of the distribution on the CD-ROM and a + package file for the development version. Always present is the information + contained in the status file which might be considered a separate package + file. + + Please understand, this is designed as a <b>Cache file</b> it is not meant to be + used on any system other than the one it was created for. It is not meant to + be authoritative either, i.e. if a system crash or software failure occurs it + must be perfectly acceptable for the cache file to be in an inconsistent + state. Furthermore at any time the cache file may be erased without losing + any information. + + Also the structures and storage layout is optimized for use by the APT + and may not be suitable for all purposes. However it should be possible + to extend it with associate cache files that contain other information. + + To keep memory use down the cache file only contains often used fields and + fields that are inexpensive to store, the Package file has a full list of + fields. Also the client may assume that all items are perfectly valid and + need not perform checks against their correctness. Removal of information + from the cache is possible, but blanks will be left in the file, and + unused strings will also be present. The recommended implementation is to + simply rebuild the cache each time any of the data files change. It is + possible to add a new package file to the cache without any negative side + effects. + + <b>Note on Pointer access</b> Clients should always use the CacheIterators classes for access to the - cache. They provide a simple STL-like method for traversing the links - of the datastructure. - - See pkgcachegen.h for information about generating cache structures. - - ##################################################################### */ + cache and the data in it. They also provide a simple STL-like method for + traversing the links of the datastructure. + + Every item in every structure is stored as the index to that structure. + What this means is that once the files is mmaped every data access has to + go through a fix up stage to get a real memory pointer. This is done + by taking the index, multiplying it by the type size and then adding + it to the start address of the memory block. This sounds complex, but + in C it is a single array dereference. Because all items are aligned to + their size and indexes are stored as multiples of the size of the structure + the format is immediately portable to all possible architectures - BUT the + generated files are -NOT-. + + This scheme allows code like this to be written: + <example> + void *Map = mmap(...); + Package *PkgList = (Package *)Map; + Header *Head = (Header *)Map; + char *Strings = (char *)Map; + cout << (Strings + PkgList[Head->HashTable[0]]->Name) << endl; + </example> + Notice the lack of casting or multiplication. The net result is to return + the name of the first package in the first hash bucket, without error + checks. + + The generator uses allocation pools to group similarly sized structures in + large blocks to eliminate any alignment overhead. The generator also + assures that no structures overlap and all indexes are unique. Although + at first glance it may seem like there is the potential for two structures + to exist at the same point the generator never allows this to happen. + (See the discussion of free space pools) + + See \ref pkgcachegen.h for more information about generating cache structures. */ /*}}}*/ #ifndef PKGLIB_PKGCACHE_H #define PKGLIB_PKGCACHE_H @@ -32,6 +87,7 @@ class pkgCache /*{{{*/ public: // Cache element predeclarations struct Header; + struct Group; struct Package; struct PackageFile; struct Version; @@ -43,6 +99,8 @@ class pkgCache /*{{{*/ struct DescFile; // Iterators + template<typename Str, typename Itr> class Iterator; + class GrpIterator; class PkgIterator; class VerIterator; class DescIterator; @@ -51,14 +109,6 @@ class pkgCache /*{{{*/ class PkgFileIterator; class VerFileIterator; class DescFileIterator; - friend class PkgIterator; - friend class VerIterator; - friend class DescInterator; - friend class DepIterator; - friend class PrvIterator; - friend class PkgFileIterator; - friend class VerFileIterator; - friend class DescFileIterator; class Namespace; @@ -71,12 +121,20 @@ class pkgCache /*{{{*/ { enum DepType {Depends=1,PreDepends=2,Suggests=3,Recommends=4, Conflicts=5,Replaces=6,Obsoletes=7,DpkgBreaks=8,Enhances=9}; + /** \brief available compare operators + + The lower 4 bits are used to indicate what operator is being specified and + the upper 4 bits are flags. OR indicates that the next package is + or'd with the current package. */ enum DepCompareOp {Or=0x10,NoOp=0,LessEq=0x1,GreaterEq=0x2,Less=0x3, Greater=0x4,Equals=0x5,NotEquals=0x6}; }; struct State { + /** \brief priority of a package version + + Zero is used for unparsable or absent Priority fields. */ enum VerPriority {Important=1,Required=2,Standard=3,Optional=4,Extra=5}; enum PkgSelectedState {Unknown=0,Install=1,Hold=2,DeInstall=3,Purge=4}; enum PkgInstState {Ok=0,ReInstReq=1,HoldInst=2,HoldReInstReq=3}; @@ -104,6 +162,7 @@ class pkgCache /*{{{*/ // Pointers to the arrays of items Header *HeaderP; + Group *GrpP; Package *PkgP; VerFile *VerFileP; DescFile *DescFileP; @@ -124,17 +183,24 @@ class pkgCache /*{{{*/ inline unsigned long Hash(const string &S) const {return sHash(S);}; inline unsigned long Hash(const char *S) const {return sHash(S);}; - // Usefull transformation things + // Useful transformation things const char *Priority(unsigned char Priority); // Accessors + GrpIterator FindGrp(const string &Name); PkgIterator FindPkg(const string &Name); + PkgIterator FindPkg(const string &Name, const string &Arch); + Header &Head() {return *HeaderP;}; + inline GrpIterator GrpBegin(); + inline GrpIterator GrpEnd(); inline PkgIterator PkgBegin(); inline PkgIterator PkgEnd(); inline PkgFileIterator FileBegin(); inline PkgFileIterator FileEnd(); + inline bool MultiArchCache() const { return MultiArchEnabled; }; + // Make me a function pkgVersioningSystem *VS; @@ -145,19 +211,40 @@ class pkgCache /*{{{*/ pkgCache(MMap *Map,bool DoMap = true); virtual ~pkgCache() {}; + +private: + bool MultiArchEnabled; + PkgIterator SingleArchFindPkg(const string &Name); }; /*}}}*/ // Header structure /*{{{*/ struct pkgCache::Header { - // Signature information + /** \brief Signature information + + This must contain the hex value 0x98FE76DC which is designed to + verify that the system loading the image has the same byte order + and byte size as the system saving the image */ unsigned long Signature; + /** These contain the version of the cache file */ short MajorVersion; short MinorVersion; + /** \brief indicates if the cache should be erased + + Dirty is true if the cache file was opened for reading, the client + expects to have written things to it and have not fully synced it. + The file should be erased and rebuilt if it is true. */ bool Dirty; - - // Size of structure values + + /** \brief Size of structure values + + All *Sz variables contains the sizeof() that particular structure. + It is used as an extra consistency check on the structure of the file. + + If any of the size values do not exactly match what the client expects + then the client should refuse the load the file. */ unsigned short HeaderSz; + unsigned short GroupSz; unsigned short PackageSz; unsigned short PackageFileSz; unsigned short VersionSz; @@ -166,8 +253,13 @@ struct pkgCache::Header unsigned short ProvidesSz; unsigned short VerFileSz; unsigned short DescFileSz; - - // Structure counts + + /** \brief Structure counts + + These indicate the number of each structure contained in the cache. + PackageCount is especially useful for generating user state structures. + See Package::Id for more info. */ + unsigned long GroupCount; unsigned long PackageCount; unsigned long VersionCount; unsigned long DescriptionCount; @@ -176,154 +268,393 @@ struct pkgCache::Header unsigned long VerFileCount; unsigned long DescFileCount; unsigned long ProvidesCount; - - // Offsets - map_ptrloc FileList; // struct PackageFile - map_ptrloc StringList; // struct StringItem - map_ptrloc VerSysName; // StringTable - map_ptrloc Architecture; // StringTable + + /** \brief index of the first PackageFile structure + + The PackageFile structures are singly linked lists that represent + all package files that have been merged into the cache. */ + map_ptrloc FileList; + /** \brief index of the first StringItem structure + + The cache contains a list of all the unique strings (StringItems). + The parser reads this list into memory so it can match strings + against it.*/ + map_ptrloc StringList; + /** \brief String representing the version system used */ + map_ptrloc VerSysName; + /** \brief Architecture(s) the cache was built against */ + map_ptrloc Architecture; + /** \brief The maximum size of a raw entry from the original Package file */ unsigned long MaxVerFileSize; + /** \brief The maximum size of a raw entry from the original Translation file */ unsigned long MaxDescFileSize; - /* Allocation pools, there should be one of these for each structure - excluding the header */ - DynamicMMap::Pool Pools[8]; + /** \brief The Pool structures manage the allocation pools that the generator uses + + Start indicates the first byte of the pool, Count is the number of objects + remaining in the pool and ItemSize is the structure size (alignment factor) + of the pool. An ItemSize of 0 indicates the pool is empty. There should be + the same number of pools as there are structure types. The generator + stores this information so future additions can make use of any unused pool + blocks. */ + DynamicMMap::Pool Pools[9]; - // Rapid package name lookup - map_ptrloc HashTable[2*1048]; + /** \brief hash tables providing rapid group/package name lookup + + Each group/package name is inserted into the hash table using pkgCache::Hash(const &string) + By iterating over each entry in the hash table it is possible to iterate over + the entire list of packages. Hash Collisions are handled with a singly linked + list of packages based at the hash item. The linked list contains only + packages that match the hashing function. + In the PkgHashTable is it possible that multiple packages have the same name - + these packages are stored as a sequence in the list. + + Beware: The Hashmethod assumes that the hash table sizes are equal */ + map_ptrloc PkgHashTable[2*1048]; + map_ptrloc GrpHashTable[2*1048]; bool CheckSizes(Header &Against) const; Header(); }; /*}}}*/ -struct pkgCache::Package /*{{{*/ +// Group structure /*{{{*/ +/** \brief groups architecture depending packages together + + On or more packages with the same name form a group, so we have + a simple way to access a package built for different architectures + Group exists in a singly linked list of group records starting at + the hash index of the name in the pkgCache::Header::GrpHashTable */ +struct pkgCache::Group +{ + /** \brief Name of the group */ + map_ptrloc Name; // StringItem + + // Linked List + /** \brief Link to the first package which belongs to the group */ + map_ptrloc FirstPackage; // Package + /** \brief Link to the last package which belongs to the group */ + map_ptrloc LastPackage; // Package + /** \brief Link to the next Group */ + map_ptrloc Next; // Group + /** \brief unique sequel ID */ + unsigned int ID; + +}; + /*}}}*/ +// Package structure /*{{{*/ +/** \brief contains information for a single unique package + + There can be any number of versions of a given package. + Package exists in a singly linked list of package records starting at + the hash index of the name in the pkgCache::Header::PkgHashTable + + A package can be created for every architecture so package names are + not unique, but it is garanteed that packages with the same name + are sequencel ordered in the list. Packages with the same name can be + accessed with the Group. +*/ +struct pkgCache::Package { - // Pointers - map_ptrloc Name; // Stringtable + /** \brief Name of the package */ + map_ptrloc Name; // StringItem + /** \brief Architecture of the package */ + map_ptrloc Arch; // StringItem + /** \brief Base of a singly linked list of versions + + Each structure represents a unique version of the package. + The version structures contain links into PackageFile and the + original text file as well as detailed information about the size + and dependencies of the specific package. In this way multiple + versions of a package can be cleanly handled by the system. + Furthermore, this linked list is guaranteed to be sorted + from Highest version to lowest version with no duplicate entries. */ map_ptrloc VersionList; // Version + /** \brief index to the installed version */ map_ptrloc CurrentVer; // Version - map_ptrloc Section; // StringTable (StringItem) - - // Linked list + /** \brief indicates the deduced section + + Should be the index to the string "Unknown" or to the section + of the last parsed item. */ + map_ptrloc Section; // StringItem + /** \brief index of the group this package belongs to */ + map_ptrloc Group; // Group the Package belongs to + + // Linked list + /** \brief Link to the next package in the same bucket */ map_ptrloc NextPackage; // Package + /** \brief List of all dependencies on this package */ map_ptrloc RevDepends; // Dependency + /** \brief List of all "packages" this package provide */ map_ptrloc ProvidesList; // Provides // Install/Remove/Purge etc + /** \brief state that the user wishes the package to be in */ unsigned char SelectedState; // What + /** \brief installation state of the package + + This should be "ok" but in case the installation failed + it will be different. + */ unsigned char InstState; // Flags + /** \brief indicates if the package is installed */ unsigned char CurrentState; // State - + + /** \brief unique sequel ID + + ID is a unique value from 0 to Header->PackageCount assigned by the generator. + This allows clients to create an array of size PackageCount and use it to store + state information for the package map. For instance the status file emitter uses + this to track which packages have been emitted already. */ unsigned int ID; + /** \brief some useful indicators of the package's state */ unsigned long Flags; }; /*}}}*/ -struct pkgCache::PackageFile /*{{{*/ +// Package File structure /*{{{*/ +/** \brief stores information about the files used to generate the cache + + Package files are referenced by Version structures to be able to know + after the generation still from which Packages file includes this Version + as we need this information later on e.g. for pinning. */ +struct pkgCache::PackageFile { - // Names - map_ptrloc FileName; // Stringtable - map_ptrloc Archive; // Stringtable - map_ptrloc Codename; // Stringtable - map_ptrloc Component; // Stringtable - map_ptrloc Version; // Stringtable - map_ptrloc Origin; // Stringtable - map_ptrloc Label; // Stringtable - map_ptrloc Architecture; // Stringtable - map_ptrloc Site; // Stringtable - map_ptrloc IndexType; // Stringtable - unsigned long Size; + /** \brief physical disk file that this PackageFile represents */ + map_ptrloc FileName; // StringItem + /** \brief the release information + + Please see the files document for a description of what the + release information means. */ + map_ptrloc Archive; // StringItem + map_ptrloc Codename; // StringItem + map_ptrloc Component; // StringItem + map_ptrloc Version; // StringItem + map_ptrloc Origin; // StringItem + map_ptrloc Label; // StringItem + map_ptrloc Architecture; // StringItem + /** \brief The site the index file was fetched from */ + map_ptrloc Site; // StringItem + /** \brief indicates what sort of index file this is + + @TODO enumerate at least the possible indexes */ + map_ptrloc IndexType; // StringItem + /** \brief Size of the file + + Used together with the modification time as a + simple check to ensure that the Packages + file has not been altered since Cache generation. */ + unsigned long Size; + /** \brief Modification time for the file */ + time_t mtime; + + /* @TODO document PackageFile::Flags */ unsigned long Flags; - + // Linked list + /** \brief Link to the next PackageFile in the Cache */ map_ptrloc NextFile; // PackageFile + /** \brief unique sequel ID */ unsigned int ID; - time_t mtime; // Modification time for the file }; /*}}}*/ -struct pkgCache::VerFile /*{{{*/ +// VerFile structure /*{{{*/ +/** \brief associates a version with a PackageFile + + This allows a full description of all Versions in all files + (and hence all sources) under consideration. */ +struct pkgCache::VerFile { + /** \brief index of the package file that this version was found in */ map_ptrloc File; // PackageFile + /** \brief next step in the linked list */ map_ptrloc NextFile; // PkgVerFile + /** \brief position in the package file */ map_ptrloc Offset; // File offset - unsigned short Size; + /* @TODO document pkgCache::VerFile::Size */ + unsigned long Size; }; /*}}}*/ -struct pkgCache::DescFile /*{{{*/ +// DescFile structure /*{{{*/ +/** \brief associates a description with a Translation file */ +struct pkgCache::DescFile { + /** \brief index of the file that this description was found in */ map_ptrloc File; // PackageFile + /** \brief next step in the linked list */ map_ptrloc NextFile; // PkgVerFile + /** \brief position in the file */ map_ptrloc Offset; // File offset - unsigned short Size; + /* @TODO document pkgCache::DescFile::Size */ + unsigned long Size; }; /*}}}*/ -struct pkgCache::Version /*{{{*/ +// Version structure /*{{{*/ +/** \brief information for a single version of a package + + The version list is always sorted from highest version to lowest + version by the generator. Equal version numbers are either merged + or handled as separate versions based on the Hash value. */ +struct pkgCache::Version { - map_ptrloc VerStr; // Stringtable - map_ptrloc Section; // StringTable (StringItem) - map_ptrloc Arch; // StringTable - - // Lists + /** \brief complete version string */ + map_ptrloc VerStr; // StringItem + /** \brief section this version is filled in */ + map_ptrloc Section; // StringItem + /** \brief stores the MultiArch capabilities of this version + + None is the default and doesn't trigger special behaviour, + Foreign means that this version can fulfill dependencies even + if it is built for another architecture as the requester. + Same indicates that builds for different architectures can + be co-installed on the system and All is the marker for a + version with the Architecture: all. */ + enum {None, All, Foreign, Same, Allowed} MultiArch; + + /** \brief references all the PackageFile's that this version came from + + FileList can be used to determine what distribution(s) the Version + applies to. If FileList is 0 then this is a blank version. + The structure should also have a 0 in all other fields excluding + pkgCache::Version::VerStr and Possibly pkgCache::Version::NextVer. */ map_ptrloc FileList; // VerFile + /** \brief next (lower or equal) version in the linked list */ map_ptrloc NextVer; // Version + /** \brief next description in the linked list */ map_ptrloc DescriptionList; // Description + /** \brief base of the dependency list */ map_ptrloc DependsList; // Dependency + /** \brief links to the owning package + + This allows reverse dependencies to determine the package */ map_ptrloc ParentPkg; // Package + /** \brief list of pkgCache::Provides */ map_ptrloc ProvidesList; // Provides - + + /** \brief archive size for this version + + For Debian this is the size of the .deb file. */ map_ptrloc Size; // These are the .deb size + /** \brief uncompressed size for this version */ map_ptrloc InstalledSize; + /** \brief characteristic value representing this version + + No two packages in existence should have the same VerStr + and Hash with different contents. */ unsigned short Hash; + /** \brief unique sequel ID */ unsigned int ID; + /** \brief parsed priority value */ unsigned char Priority; }; /*}}}*/ -struct pkgCache::Description /*{{{*/ +// Description structure /*{{{*/ +/** \brief datamember of a linked list of available description for a version */ +struct pkgCache::Description { - // Language Code store the description translation language code. If - // the value has a 0 lenght then this is readed using the Package - // file else the Translation-CODE are used. - map_ptrloc language_code; // StringTable - map_ptrloc md5sum; // StringTable + /** \brief Language code of this description (translation) + + If the value has a 0 length then this is read using the Package + file else the Translation-CODE file is used. */ + map_ptrloc language_code; // StringItem + /** \brief MD5sum of the original description + + Used to map Translations of a description to a version + and to check that the Translation is up-to-date. */ + map_ptrloc md5sum; // StringItem - // Linked list + /* @TODO document pkgCache::Description::FileList */ map_ptrloc FileList; // DescFile + /** \brief next translation for this description */ map_ptrloc NextDesc; // Description + /** \brief the text is a description of this package */ map_ptrloc ParentPkg; // Package + /** \brief unique sequel ID */ unsigned int ID; }; /*}}}*/ -struct pkgCache::Dependency /*{{{*/ +// Dependency structure /*{{{*/ +/** \brief information for a single dependency record + + The records are split up like this to ease processing by the client. + The base of the linked list is pkgCache::Version::DependsList. + All forms of dependencies are recorded here including Depends, + Recommends, Suggests, Enhances, Conflicts, Replaces and Breaks. */ +struct pkgCache::Dependency { - map_ptrloc Version; // Stringtable + /** \brief string of the version the dependency is applied against */ + map_ptrloc Version; // StringItem + /** \brief index of the package this depends applies to + + The generator will - if the package does not already exist - + create a blank (no version records) package. */ map_ptrloc Package; // Package + /** \brief next dependency of this version */ map_ptrloc NextDepends; // Dependency + /** \brief next reverse dependency of this package */ map_ptrloc NextRevDepends; // Dependency + /** \brief version of the package which has the reverse depends */ map_ptrloc ParentVer; // Version - - // Specific types of depends - map_ptrloc ID; + + /** \brief unique sequel ID */ + map_ptrloc ID; + /** \brief Dependency type - Depends, Recommends, Conflicts, etc */ unsigned char Type; + /** \brief comparison operator specified on the depends line + + If the high bit is set then it is a logical OR with the previous record. */ unsigned char CompareOp; }; /*}}}*/ -struct pkgCache::Provides /*{{{*/ +// Provides structure /*{{{*/ +/** \brief handles virtual packages + + When a Provides: line is encountered a new provides record is added + associating the package with a virtual package name. + The provides structures are linked off the package structures. + This simplifies the analysis of dependencies and other aspects A provides + refers to a specific version of a specific package, not all versions need to + provide that provides.*/ +struct pkgCache::Provides { - map_ptrloc ParentPkg; // Pacakge + /** \brief index of the package providing this */ + map_ptrloc ParentPkg; // Package + /** \brief index of the version this provide line applies to */ map_ptrloc Version; // Version - map_ptrloc ProvideVersion; // Stringtable + /** \brief version in the provides line (if any) + + This version allows dependencies to depend on specific versions of a + Provides, as well as allowing Provides to override existing packages. + This is experimental. Note that Debian doesn't allow versioned provides */ + map_ptrloc ProvideVersion; // StringItem + /** \brief next provides (based of package) */ map_ptrloc NextProvides; // Provides + /** \brief next provides (based of version) */ map_ptrloc NextPkgProv; // Provides }; /*}}}*/ -struct pkgCache::StringItem /*{{{*/ +// StringItem structure /*{{{*/ +/** \brief used for generating single instances of strings + + Some things like Section Name are are useful to have as unique tags. + It is part of a linked list based at pkgCache::Header::StringList + + All strings are simply inlined any place in the file that is natural + for the writer. The client should make no assumptions about the positioning + of strings. All StringItems should be null-terminated. */ +struct pkgCache::StringItem { - map_ptrloc String; // Stringtable + /** \brief string this refers to */ + map_ptrloc String; // StringItem + /** \brief Next link in the chain */ map_ptrloc NextItem; // StringItem }; /*}}}*/ #include <apt-pkg/cacheiterators.h> +inline pkgCache::GrpIterator pkgCache::GrpBegin() + {return GrpIterator(*this);}; +inline pkgCache::GrpIterator pkgCache::GrpEnd() + {return GrpIterator(*this,GrpP);}; inline pkgCache::PkgIterator pkgCache::PkgBegin() {return PkgIterator(*this);}; inline pkgCache::PkgIterator pkgCache::PkgEnd() @@ -337,7 +668,7 @@ inline pkgCache::PkgFileIterator pkgCache::FileEnd() class pkgCache::Namespace /*{{{*/ { public: - + typedef pkgCache::GrpIterator GrpIterator; typedef pkgCache::PkgIterator PkgIterator; typedef pkgCache::VerIterator VerIterator; typedef pkgCache::DescIterator DescIterator; diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc index 3eeb18cae..d96d3370f 100644 --- a/apt-pkg/pkgcachegen.cc +++ b/apt-pkg/pkgcachegen.cc @@ -18,6 +18,7 @@ #include <apt-pkg/progress.h> #include <apt-pkg/sourcelist.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/aptconfiguration.h> #include <apt-pkg/strutl.h> #include <apt-pkg/sptr.h> #include <apt-pkg/pkgsystem.h> @@ -38,7 +39,7 @@ typedef vector<pkgIndexFile *>::iterator FileIterator; // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/ // --------------------------------------------------------------------- -/* We set the diry flag and make sure that is written to the disk */ +/* We set the dirty flag and make sure that is written to the disk */ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) : Map(*pMap), Cache(pMap,false), Progress(Prog), FoundFileDeps(0) @@ -107,13 +108,26 @@ bool pkgCacheGenerator::MergeList(ListParser &List, unsigned int Counter = 0; while (List.Step() == true) { - // Get a pointer to the package structure - string PackageName = List.Package(); + string const PackageName = List.Package(); if (PackageName.empty() == true) return false; - + + /* As we handle Arch all packages as architecture bounded + we add all information to every (simulated) arch package */ + std::vector<string> genArch; + if (List.ArchitectureAll() == true) { + genArch = APT::Configuration::getArchitectures(); + if (genArch.size() != 1) + genArch.push_back("all"); + } else + genArch.push_back(List.Architecture()); + + for (std::vector<string>::const_iterator arch = genArch.begin(); + arch != genArch.end(); ++arch) + { + // Get a pointer to the package structure pkgCache::PkgIterator Pkg; - if (NewPackage(Pkg,PackageName) == false) + if (NewPackage(Pkg, PackageName, *arch) == false) return _error->Error(_("Error occurred while processing %s (NewPackage)"),PackageName.c_str()); Counter++; if (Counter % 100 == 0 && Progress != 0) @@ -175,17 +189,22 @@ bool pkgCacheGenerator::MergeList(ListParser &List, pkgCache::VerIterator Ver = Pkg.VersionList(); map_ptrloc *LastVer = &Pkg->VersionList; int Res = 1; + unsigned long const Hash = List.VersionHash(); for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++) { Res = Cache.VS->CmpVersion(Version,Ver.VerStr()); - if (Res >= 0) + // Version is higher as current version - insert here + if (Res > 0) + break; + // Versionstrings are equal - is hash also equal? + if (Res == 0 && Ver->Hash == Hash) break; + // proceed with the next till we have either the right + // or we found another version (which will be lower) } - - /* We already have a version for this item, record that we - saw it */ - unsigned long Hash = List.VersionHash(); - if (Res == 0 && Ver->Hash == Hash) + + /* We already have a version for this item, record that we saw it */ + if (Res == 0 && Ver.end() == false && Ver->Hash == Hash) { if (List.UsePackage(Pkg,Ver) == false) return _error->Error(_("Error occurred while processing %s (UsePackage2)"), @@ -204,17 +223,6 @@ bool pkgCacheGenerator::MergeList(ListParser &List, } continue; - } - - // Skip to the end of the same version set. - if (Res == 0) - { - for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++) - { - Res = Cache.VS->CmpVersion(Version,Ver.VerStr()); - if (Res != 0) - break; - } } // Add a new version @@ -256,6 +264,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List, if ((*LastDesc == 0 && _error->PendingError()) || NewFileDesc(Desc,List) == false) return _error->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName.c_str()); + } } FoundFileDeps |= List.HasFileDeps(); @@ -323,33 +332,79 @@ bool pkgCacheGenerator::MergeFileProvides(ListParser &List) return true; } /*}}}*/ -// CacheGenerator::NewPackage - Add a new package /*{{{*/ +// CacheGenerator::NewGroup - Add a new group /*{{{*/ // --------------------------------------------------------------------- -/* This creates a new package structure and adds it to the hash table */ -bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name) +/* This creates a new group structure and adds it to the hash table */ +bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name) { - Pkg = Cache.FindPkg(Name); - if (Pkg.end() == false) + Grp = Cache.FindGrp(Name); + if (Grp.end() == false) return true; // Get a structure - unsigned long Package = Map.Allocate(sizeof(pkgCache::Package)); - if (Package == 0) + unsigned long const Group = Map.Allocate(sizeof(pkgCache::Group)); + if (unlikely(Group == 0)) return false; - - Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package); - + + Grp = pkgCache::GrpIterator(Cache, Cache.GrpP + Group); + Grp->Name = Map.WriteString(Name); + if (unlikely(Grp->Name == 0)) + return false; + // Insert it into the hash table - unsigned long Hash = Cache.Hash(Name); - Pkg->NextPackage = Cache.HeaderP->HashTable[Hash]; - Cache.HeaderP->HashTable[Hash] = Package; - - // Set the name and the ID - Pkg->Name = Map.WriteString(Name); - if (Pkg->Name == 0) + unsigned long const Hash = Cache.Hash(Name); + Grp->Next = Cache.HeaderP->GrpHashTable[Hash]; + Cache.HeaderP->GrpHashTable[Hash] = Group; + + Grp->ID = Cache.HeaderP->GroupCount++; + return true; +} + /*}}}*/ +// CacheGenerator::NewPackage - Add a new package /*{{{*/ +// --------------------------------------------------------------------- +/* This creates a new package structure and adds it to the hash table */ +bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name, + const string &Arch) { + pkgCache::GrpIterator Grp; + if (unlikely(NewGroup(Grp, Name) == false)) + return false; + + Pkg = Grp.FindPkg(Arch); + if (Pkg.end() == false) + return true; + + // Get a structure + unsigned long const Package = Map.Allocate(sizeof(pkgCache::Package)); + if (unlikely(Package == 0)) + return false; + Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package); + + // Insert the package into our package list + if (Grp->FirstPackage == 0) // the group is new + { + // Insert it into the hash table + unsigned long const Hash = Cache.Hash(Name); + Pkg->NextPackage = Cache.HeaderP->PkgHashTable[Hash]; + Cache.HeaderP->PkgHashTable[Hash] = Package; + Grp->FirstPackage = Package; + } + else // Group the Packages together + { + // this package is the new last package + pkgCache::PkgIterator LastPkg(Cache, Cache.PkgP + Grp->LastPackage); + Pkg->NextPackage = LastPkg->NextPackage; + LastPkg->NextPackage = Package; + } + Grp->LastPackage = Package; + + // Set the name, arch and the ID + Pkg->Name = Grp->Name; + Pkg->Group = Grp.Index(); + Pkg->Arch = WriteUniqString(Arch.c_str()); + if (unlikely(Pkg->Arch == 0)) return false; Pkg->ID = Cache.HeaderP->PackageCount++; - + return true; } /*}}}*/ @@ -468,21 +523,95 @@ map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc, return Description; } /*}}}*/ -// ListParser::NewDepends - Create a dependency element /*{{{*/ +// CacheGenerator::FinishCache - do various finish operations /*{{{*/ +// --------------------------------------------------------------------- +/* This prepares the Cache for delivery */ +bool pkgCacheGenerator::FinishCache(OpProgress &Progress) +{ + // FIXME: add progress reporting for this operation + // Do we have different architectures in your groups ? + vector<string> archs = APT::Configuration::getArchitectures(); + if (archs.size() > 1) + { + // Create Conflicts in between the group + for (pkgCache::GrpIterator G = GetCache().GrpBegin(); G.end() != true; G++) + { + string const PkgName = G.Name(); + for (pkgCache::PkgIterator P = G.PackageList(); P.end() != true; P = G.NextPkg(P)) + { + if (strcmp(P.Arch(),"all") == 0) + continue; + pkgCache::PkgIterator allPkg; + for (pkgCache::VerIterator V = P.VersionList(); V.end() != true; V++) + { + string const Arch = V.Arch(true); + map_ptrloc *OldDepLast = NULL; + /* MultiArch handling introduces a lot of implicit Dependencies: + - MultiArch: same → Co-Installable if they have the same version + - Architecture: all → Need to be Co-Installable for internal reasons + - All others conflict with all other group members */ + bool const coInstall = (V->MultiArch == pkgCache::Version::All || + V->MultiArch == pkgCache::Version::Same); + if (V->MultiArch == pkgCache::Version::All && allPkg.end() == true) + allPkg = G.FindPkg("all"); + for (vector<string>::const_iterator A = archs.begin(); A != archs.end(); ++A) + { + if (*A == Arch) + continue; + /* We allow only one installed arch at the time + per group, therefore each group member conflicts + with all other group members */ + pkgCache::PkgIterator D = G.FindPkg(*A); + if (D.end() == true) + continue; + if (coInstall == true) + { + // Replaces: ${self}:other ( << ${binary:Version}) + NewDepends(D, V, V.VerStr(), + pkgCache::Dep::Less, pkgCache::Dep::Replaces, + OldDepLast); + // Breaks: ${self}:other (!= ${binary:Version}) + NewDepends(D, V, V.VerStr(), + pkgCache::Dep::Less, pkgCache::Dep::DpkgBreaks, + OldDepLast); + NewDepends(D, V, V.VerStr(), + pkgCache::Dep::Greater, pkgCache::Dep::DpkgBreaks, + OldDepLast); + if (V->MultiArch == pkgCache::Version::All) + { + // Depend on ${self}:all which does depend on nothing + NewDepends(allPkg, V, V.VerStr(), + pkgCache::Dep::Equals, pkgCache::Dep::Depends, + OldDepLast); + } + } else { + // Conflicts: ${self}:other + NewDepends(D, V, "", + pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts, + OldDepLast); + } + } + } + } + } + } + return true; +} + /*}}}*/ +// CacheGenerator::NewDepends - Create a dependency element /*{{{*/ // --------------------------------------------------------------------- /* This creates a dependency element in the tree. It is linked to the version and to the package that it is pointing to. */ -bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver, - const string &PackageName, - const string &Version, - unsigned int Op, - unsigned int Type) +bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg, + pkgCache::VerIterator &Ver, + string const &Version, + unsigned int const &Op, + unsigned int const &Type, + map_ptrloc *OldDepLast) { - pkgCache &Cache = Owner->Cache; - // Get a structure - unsigned long Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency)); - if (Dependency == 0) + unsigned long const Dependency = Map.Allocate(sizeof(pkgCache::Dependency)); + if (unlikely(Dependency == 0)) return false; // Fill it in @@ -491,12 +620,7 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver, Dep->Type = Type; Dep->CompareOp = Op; Dep->ID = Cache.HeaderP->DependsCount++; - - // Locate the target package - pkgCache::PkgIterator Pkg; - if (Owner->NewPackage(Pkg,PackageName) == false) - return false; - + // Probe the reverse dependency list for a version string that matches if (Version.empty() == false) { @@ -504,29 +628,23 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver, if (I->Version != 0 && I.TargetVer() == Version) Dep->Version = I->Version;*/ if (Dep->Version == 0) - if ((Dep->Version = WriteString(Version)) == 0) + if (unlikely((Dep->Version = Map.WriteString(Version)) == 0)) return false; } - + // Link it to the package Dep->Package = Pkg.Index(); Dep->NextRevDepends = Pkg->RevDepends; Pkg->RevDepends = Dep.Index(); - - /* Link it to the version (at the end of the list) - Caching the old end point speeds up generation substantially */ - if (OldDepVer != Ver) + + // Do we know where to link the Dependency to? + if (OldDepLast == NULL) { OldDepLast = &Ver->DependsList; for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++) OldDepLast = &D->NextDepends; - OldDepVer = Ver; } - // Is it a file dependency? - if (PackageName[0] == '/') - FoundFileDeps = true; - Dep->NextDepends = *OldDepLast; *OldDepLast = Dep.Index(); OldDepLast = &Dep->NextDepends; @@ -534,22 +652,58 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver, return true; } /*}}}*/ +// ListParser::NewDepends - Create the environment for a new dependency /*{{{*/ +// --------------------------------------------------------------------- +/* This creates a Group and the Package to link this dependency to if + needed and handles also the caching of the old endpoint */ +bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver, + const string &PackageName, + const string &Arch, + const string &Version, + unsigned int Op, + unsigned int Type) +{ + pkgCache::GrpIterator Grp; + if (unlikely(Owner->NewGroup(Grp, PackageName) == false)) + return false; + + // Locate the target package + pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch); + if (Pkg.end() == true) { + if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false)) + return false; + } + + // Is it a file dependency? + if (unlikely(PackageName[0] == '/')) + FoundFileDeps = true; + + /* Caching the old end point speeds up generation substantially */ + if (OldDepVer != Ver) { + OldDepLast = NULL; + OldDepVer = Ver; + } + + return Owner->NewDepends(Pkg, Ver, Version, Op, Type, OldDepLast); +} + /*}}}*/ // ListParser::NewProvides - Create a Provides element /*{{{*/ // --------------------------------------------------------------------- /* */ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver, - const string &PackageName, + const string &PkgName, + const string &PkgArch, const string &Version) { pkgCache &Cache = Owner->Cache; // We do not add self referencing provides - if (Ver.ParentPkg().Name() == PackageName) + if (Ver.ParentPkg().Name() == PkgName && PkgArch == Ver.Arch(true)) return true; // Get a structure - unsigned long Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides)); - if (Provides == 0) + unsigned long const Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides)); + if (unlikely(Provides == 0)) return false; Cache.HeaderP->ProvidesCount++; @@ -558,12 +712,12 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver, Prv->Version = Ver.Index(); Prv->NextPkgProv = Ver->ProvidesList; Ver->ProvidesList = Prv.Index(); - if (Version.empty() == false && (Prv->ProvideVersion = WriteString(Version)) == 0) + if (Version.empty() == false && unlikely((Prv->ProvideVersion = WriteString(Version)) == 0)) return false; // Locate the target package pkgCache::PkgIterator Pkg; - if (Owner->NewPackage(Pkg,PackageName) == false) + if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false)) return false; // Link it to the package @@ -848,7 +1002,20 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress, // Decide if we can write to the files.. string const CacheFile = _config->FindFile("Dir::Cache::pkgcache"); string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache"); - + + // ensure the cache directory exists + if (CacheFile.empty() == false || SrcCacheFile.empty() == false) + { + string dir = _config->FindDir("Dir::Cache"); + size_t const len = dir.size(); + if (len > 5 && dir.find("/apt/", len - 6, 5) == len - 5) + dir = dir.substr(0, len - 5); + if (CacheFile.empty() == false) + CreateDirectory(dir, flNotFile(CacheFile)); + if (SrcCacheFile.empty() == false) + CreateDirectory(dir, flNotFile(SrcCacheFile)); + } + // Decide if we can write to the cache bool Writeable = false; if (CacheFile.empty() == false) @@ -923,6 +1090,9 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress, if (BuildCache(Gen,Progress,CurrentSize,TotalSize, Files.begin()+EndOfSource,Files.end()) == false) return false; + + // FIXME: move me to a better place + Gen.FinishCache(Progress); } else { @@ -965,6 +1135,9 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress, if (BuildCache(Gen,Progress,CurrentSize,TotalSize, Files.begin()+EndOfSource,Files.end()) == false) return false; + + // FIXME: move me to a better place + Gen.FinishCache(Progress); } if (Debug == true) std::clog << "Caches are ready for shipping" << std::endl; @@ -1012,7 +1185,10 @@ bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap) if (BuildCache(Gen,Progress,CurrentSize,TotalSize, Files.begin()+EndOfSource,Files.end()) == false) return false; - + + // FIXME: move me to a better place + Gen.FinishCache(Progress); + if (_error->PendingError() == true) return false; *OutMap = Map.UnGuard(); diff --git a/apt-pkg/pkgcachegen.h b/apt-pkg/pkgcachegen.h index 108b34207..46d0cd893 100644 --- a/apt-pkg/pkgcachegen.h +++ b/apt-pkg/pkgcachegen.h @@ -51,9 +51,13 @@ class pkgCacheGenerator /*{{{*/ // Flag file dependencies bool FoundFileDeps; - bool NewPackage(pkgCache::PkgIterator &Pkg,const string &PkgName); + bool NewGroup(pkgCache::GrpIterator &Grp,const string &Name); + bool NewPackage(pkgCache::PkgIterator &Pkg,const string &Name, const string &Arch); bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List); bool NewFileDesc(pkgCache::DescIterator &Desc,ListParser &List); + bool NewDepends(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver, + string const &Version, unsigned int const &Op, + unsigned int const &Type, map_ptrloc *OldDepLast); unsigned long NewVersion(pkgCache::VerIterator &Ver,const string &VerStr,unsigned long Next); map_ptrloc NewDescription(pkgCache::DescIterator &Desc,const string &Lang,const MD5SumValue &md5sum,map_ptrloc Next); @@ -72,7 +76,8 @@ class pkgCacheGenerator /*{{{*/ bool HasFileDeps() {return FoundFileDeps;}; bool MergeFileProvides(ListParser &List); - + bool FinishCache(OpProgress &Progress); + pkgCacheGenerator(DynamicMMap *Map,OpProgress *Progress); ~pkgCacheGenerator(); }; @@ -96,16 +101,18 @@ class pkgCacheGenerator::ListParser inline unsigned long WriteUniqString(const char *S,unsigned int Size) {return Owner->WriteUniqString(S,Size);}; inline unsigned long WriteString(const string &S) {return Owner->Map.WriteString(S);}; inline unsigned long WriteString(const char *S,unsigned int Size) {return Owner->Map.WriteString(S,Size);}; - bool NewDepends(pkgCache::VerIterator Ver,const string &Package, + bool NewDepends(pkgCache::VerIterator Ver,const string &Package, const string &Arch, const string &Version,unsigned int Op, unsigned int Type); - bool NewProvides(pkgCache::VerIterator Ver,const string &Package, - const string &Version); + bool NewProvides(pkgCache::VerIterator Ver,const string &PkgName, + const string &PkgArch, const string &Version); public: // These all operate against the current section virtual string Package() = 0; + virtual string Architecture() = 0; + virtual bool ArchitectureAll() = 0; virtual string Version() = 0; virtual bool NewVersion(pkgCache::VerIterator Ver) = 0; virtual string Description() = 0; diff --git a/apt-pkg/pkgrecords.cc b/apt-pkg/pkgrecords.cc index a5dab22ff..e506de73a 100644 --- a/apt-pkg/pkgrecords.cc +++ b/apt-pkg/pkgrecords.cc @@ -23,8 +23,8 @@ pkgRecords::pkgRecords(pkgCache &Cache) : Cache(Cache), Files(Cache.HeaderP->PackageFileCount) { - for (pkgCache::PkgFileIterator I = Cache.FileBegin(); - I.end() == false; I++) + for (pkgCache::PkgFileIterator I = Cache.FileBegin(); + I.end() == false; I++) { const pkgIndexFile::Type *Type = pkgIndexFile::Type::GetType(I.IndexType()); if (Type == 0) diff --git a/apt-pkg/policy.cc b/apt-pkg/policy.cc index f9901bc9a..922efb0dd 100644 --- a/apt-pkg/policy.cc +++ b/apt-pkg/policy.cc @@ -106,7 +106,7 @@ bool pkgPolicy::InitDefaults() if (_config->FindB("Debug::pkgPolicy",false) == true) for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F != Cache->FileEnd(); F++) - cout << "Prio of " << F.FileName() << ' ' << PFPriority[F->ID] << endl; + std::clog << "Prio of " << F.FileName() << ' ' << PFPriority[F->ID] << std::endl; return true; } @@ -121,6 +121,10 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg) signed Max = GetPriority(Pkg); pkgCache::VerIterator Pref = GetMatch(Pkg); + // Alternatives in case we can not find our package pin (Bug#512318). + signed MaxAlt = 0; + pkgCache::VerIterator PrefAlt; + // no package = no candidate version if (Pkg.end() == true) return Pref; @@ -159,6 +163,11 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg) { Pref = Ver; Max = Prio; + } + if (Prio > MaxAlt) + { + PrefAlt = Ver; + MaxAlt = Prio; } } @@ -175,6 +184,11 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg) break; } } + // If we do not find our candidate, use the one with the highest pin. + // This means that if there is a version available with pin > 0; there + // will always be a candidate (Closes: #512318) + if (!Pref.IsGood() && MaxAlt > 0) + Pref = PrefAlt; return Pref; } /*}}}*/ @@ -187,35 +201,38 @@ pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg) void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name, string Data,signed short Priority) { - Pin *P = 0; - if (Name.empty() == true) - P = &*Defaults.insert(Defaults.end(),PkgPin()); - else { - // Get a spot to put the pin - pkgCache::PkgIterator Pkg = Cache->FindPkg(Name); - if (Pkg.end() == true) + Pin *P = &*Defaults.insert(Defaults.end(),PkgPin()); + P->Type = Type; + P->Priority = Priority; + P->Data = Data; + return; + } + + // Get a spot to put the pin + pkgCache::GrpIterator Grp = Cache->FindGrp(Name); + for (pkgCache::PkgIterator Pkg = Grp.FindPkg("any"); + Pkg.end() != true; Pkg = Grp.NextPkg(Pkg)) + { + Pin *P = 0; + if (Pkg.end() == false) + P = Pins + Pkg->ID; + else { // Check the unmatched table - for (vector<PkgPin>::iterator I = Unmatched.begin(); + for (vector<PkgPin>::iterator I = Unmatched.begin(); I != Unmatched.end() && P == 0; I++) if (I->Pkg == Name) P = &*I; - + if (P == 0) - P = &*Unmatched.insert(Unmatched.end(),PkgPin()); + P = &*Unmatched.insert(Unmatched.end(),PkgPin()); } - else - { - P = Pins + Pkg->ID; - } + P->Type = Type; + P->Priority = Priority; + P->Data = Data; } - - // Set.. - P->Type = Type; - P->Priority = Priority; - P->Data = Data; } /*}}}*/ // Policy::GetMatch - Get the matching version for a package pin /*{{{*/ @@ -274,9 +291,9 @@ bool ReadPinDir(pkgPolicy &Plcy,string Dir) if (Dir.empty() == true) Dir = _config->FindDir("Dir::Etc::PreferencesParts"); - if (FileExists(Dir) == false) + if (DirectoryExists(Dir) == false) { - _error->WarningE("FileExists",_("Unable to read %s"),Dir.c_str()); + _error->WarningE("DirectoryExists",_("Unable to read %s"),Dir.c_str()); return true; } diff --git a/apt-pkg/sourcelist.cc b/apt-pkg/sourcelist.cc index 929259961..c3ec9865a 100644 --- a/apt-pkg/sourcelist.cc +++ b/apt-pkg/sourcelist.cc @@ -72,13 +72,58 @@ bool pkgSourceList::Type::FixupURI(string &URI) const Weird types may override this. */ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List, const char *Buffer, - unsigned long CurLine, - string File) const + unsigned long const &CurLine, + string const &File) const { + for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces + + // Parse option field if it exists + // e.g.: [ option1=value1 option2=value2 ] + map<string, string> Options; + if (Buffer != 0 && Buffer[0] == '[') + { + ++Buffer; // ignore the [ + for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces + while (*Buffer != ']') + { + // get one option, e.g. option1=value1 + string option; + if (ParseQuoteWord(Buffer,option) == false) + return _error->Error(_("Malformed line %lu in source list %s ([option] unparseable)"),CurLine,File.c_str()); + + if (option.length() < 3) + return _error->Error(_("Malformed line %lu in source list %s ([option] too short)"),CurLine,File.c_str()); + + // accept options even if the last has no space before the ]-end marker + if (option.at(option.length()-1) == ']') + { + for (; *Buffer != ']'; --Buffer); + option.resize(option.length()-1); + } + + size_t const needle = option.find('='); + if (needle == string::npos) + return _error->Error(_("Malformed line %lu in source list %s ([%s] is not an assignment)"),CurLine,File.c_str(), option.c_str()); + + string const key = string(option, 0, needle); + string const value = string(option, needle + 1, option.length()); + + if (key.empty() == true) + return _error->Error(_("Malformed line %lu in source list %s ([%s] has no key)"),CurLine,File.c_str(), option.c_str()); + + if (value.empty() == true) + return _error->Error(_("Malformed line %lu in source list %s ([%s] key %s has no value)"),CurLine,File.c_str(),option.c_str(),key.c_str()); + + Options[key] = value; + } + ++Buffer; // ignore the ] + for (;Buffer != 0 && isspace(*Buffer); ++Buffer); // Skip whitespaces + } + string URI; string Dist; - string Section; - + string Section; + if (ParseQuoteWord(Buffer,URI) == false) return _error->Error(_("Malformed line %lu in source list %s (URI)"),CurLine,File.c_str()); if (ParseQuoteWord(Buffer,Dist) == false) @@ -93,7 +138,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List, if (ParseQuoteWord(Buffer,Section) == true) return _error->Error(_("Malformed line %lu in source list %s (absolute dist)"),CurLine,File.c_str()); Dist = SubstVar(Dist,"$(ARCH)",_config->Find("APT::Architecture")); - return CreateItem(List,URI,Dist,Section); + return CreateItem(List, URI, Dist, Section, Options); } // Grab the rest of the dists @@ -102,7 +147,7 @@ bool pkgSourceList::Type::ParseLine(vector<metaIndex *> &List, do { - if (CreateItem(List,URI,Dist,Section) == false) + if (CreateItem(List, URI, Dist, Section, Options) == false) return false; } while (ParseQuoteWord(Buffer,Section) == true); @@ -154,15 +199,15 @@ bool pkgSourceList::ReadMainList() if (FileExists(Main) == true) Res &= ReadAppend(Main); - else if (FileExists(Parts) == false) + else if (DirectoryExists(Parts) == false) // Only warn if there are no sources.list.d. - _error->WarningE("FileExists",_("Unable to read %s"),Main.c_str()); + _error->WarningE("DirectoryExists", _("Unable to read %s"), Parts.c_str()); - if (FileExists(Parts) == true) + if (DirectoryExists(Parts) == true) Res &= ReadSourceDir(Parts); else if (FileExists(Main) == false) // Only warn if there is no sources.list file. - _error->WarningE("FileExists",_("Unable to read %s"),Parts.c_str()); + _error->WarningE("FileExists", _("Unable to read %s"), Main.c_str()); return Res; } @@ -239,36 +284,7 @@ bool pkgSourceList::ReadAppend(string File) if (Parse == 0) return _error->Error(_("Type '%s' is not known on line %u in source list %s"),LineType.c_str(),CurLine,File.c_str()); - // Vendor name specified - if (C[0] == '[') - { - string VendorID; - - if (ParseQuoteWord(C,VendorID) == false) - return _error->Error(_("Malformed line %u in source list %s (vendor id)"),CurLine,File.c_str()); - - if (VendorID.length() < 2 || VendorID.end()[-1] != ']') - return _error->Error(_("Malformed line %u in source list %s (vendor id)"),CurLine,File.c_str()); - VendorID = string(VendorID,1,VendorID.size()-2); - -// for (vector<const Vendor *>::const_iterator iter = VendorList.begin(); -// iter != VendorList.end(); iter++) -// { -// if ((*iter)->GetVendorID() == VendorID) -// { -// if (_config->FindB("Debug::sourceList", false)) -// std::cerr << "Comparing VendorID \"" << VendorID << "\" with \"" << (*iter)->GetVendorID() << '"' << std::endl; -// Verifier = *iter; -// break; -// } -// } - -// if (Verifier == 0) -// return _error->Error(_("Unknown vendor ID '%s' in line %u of source list %s"), -// VendorID.c_str(),CurLine,File.c_str()); - } - - if (Parse->ParseLine(SrcList,C,CurLine,File) == false) + if (Parse->ParseLine(SrcList, C, CurLine, File) == false) return false; } return true; diff --git a/apt-pkg/sourcelist.h b/apt-pkg/sourcelist.h index b9e4389ed..e15314a5e 100644 --- a/apt-pkg/sourcelist.h +++ b/apt-pkg/sourcelist.h @@ -29,6 +29,7 @@ #include <string> #include <vector> +#include <map> #include <apt-pkg/pkgcache.h> #include <apt-pkg/metaindex.h> @@ -57,9 +58,10 @@ class pkgSourceList bool FixupURI(string &URI) const; virtual bool ParseLine(vector<metaIndex *> &List, const char *Buffer, - unsigned long CurLine,string File) const; - virtual bool CreateItem(vector<metaIndex *> &List,string URI, - string Dist,string Section) const = 0; + unsigned long const &CurLine,string const &File) const; + virtual bool CreateItem(vector<metaIndex *> &List,string const &URI, + string const &Dist,string const &Section, + std::map<string, string> const &Options) const = 0; Type(); virtual ~Type() {}; }; diff --git a/apt-pkg/srcrecords.cc b/apt-pkg/srcrecords.cc index 5e40ae624..46a02b55c 100644 --- a/apt-pkg/srcrecords.cc +++ b/apt-pkg/srcrecords.cc @@ -77,7 +77,7 @@ bool pkgSrcRecords::Restart() /* This searches on both source package names and output binary names and returns the first found. A 'cursor' like system is used to allow this function to be called multiple times to get successive entries */ -pkgSrcRecords::Parser *pkgSrcRecords::Find(const char *Package,bool SrcOnly) +pkgSrcRecords::Parser *pkgSrcRecords::Find(const char *Package,bool const &SrcOnly) { if (Current == Files.end()) return 0; @@ -116,7 +116,7 @@ pkgSrcRecords::Parser *pkgSrcRecords::Find(const char *Package,bool SrcOnly) // Parser::BuildDepType - Convert a build dep to a string /*{{{*/ // --------------------------------------------------------------------- /* */ -const char *pkgSrcRecords::Parser::BuildDepType(unsigned char Type) +const char *pkgSrcRecords::Parser::BuildDepType(unsigned char const &Type) { const char *fields[] = {"Build-Depends", "Build-Depends-Indep", diff --git a/apt-pkg/srcrecords.h b/apt-pkg/srcrecords.h index 99cbc6060..a49533864 100644 --- a/apt-pkg/srcrecords.h +++ b/apt-pkg/srcrecords.h @@ -59,7 +59,7 @@ class pkgSrcRecords virtual bool Restart() = 0; virtual bool Step() = 0; - virtual bool Jump(unsigned long Off) = 0; + virtual bool Jump(unsigned long const &Off) = 0; virtual unsigned long Offset() = 0; virtual string AsStr() = 0; @@ -69,8 +69,8 @@ class pkgSrcRecords virtual string Section() const = 0; virtual const char **Binaries() = 0; // Ownership does not transfer - virtual bool BuildDepends(vector<BuildDepRec> &BuildDeps, bool ArchOnly) = 0; - static const char *BuildDepType(unsigned char Type); + virtual bool BuildDepends(vector<BuildDepRec> &BuildDeps, bool const &ArchOnly, bool const &StripMultiArch = true) = 0; + static const char *BuildDepType(unsigned char const &Type); virtual bool Files(vector<pkgSrcRecords::File> &F) = 0; @@ -90,7 +90,7 @@ class pkgSrcRecords bool Restart(); // Locate a package by name - Parser *Find(const char *Package,bool SrcOnly = false); + Parser *Find(const char *Package,bool const &SrcOnly = false); pkgSrcRecords(pkgSourceList &List); ~pkgSrcRecords(); diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc index 1c41f1265..e1f576875 100644 --- a/apt-pkg/tagfile.cc +++ b/apt-pkg/tagfile.cc @@ -193,17 +193,8 @@ bool pkgTagFile::Jump(pkgTagSection &Tag,unsigned long Offset) /*}}}*/ // TagSection::Scan - Scan for the end of the header information /*{{{*/ // --------------------------------------------------------------------- -/* This looks for the first double new line in the data stream. It also - indexes the tags in the section. This very simple hash function for the - last 8 letters gives very good performance on the debian package files */ -inline static unsigned long AlphaHash(const char *Text, const char *End = 0) -{ - unsigned long Res = 0; - for (; Text != End && *Text != ':' && *Text != 0; Text++) - Res = ((unsigned long)(*Text) & 0xDF) ^ (Res << 1); - return Res & 0xFF; -} - +/* This looks for the first double new line in the data stream. + It also indexes the tags in the section. */ bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength) { const char *End = Start + MaxLength; diff --git a/apt-pkg/tagfile.h b/apt-pkg/tagfile.h index 321329a23..f63a51d07 100644 --- a/apt-pkg/tagfile.h +++ b/apt-pkg/tagfile.h @@ -33,7 +33,18 @@ class pkgTagSection unsigned int AlphaIndexes[0x100]; unsigned int TagCount; - + + /* This very simple hash function for the last 8 letters gives + very good performance on the debian package files */ + inline static unsigned long AlphaHash(const char *Text, const char *End = 0) + { + unsigned long Res = 0; + for (; Text != End && *Text != ':' && *Text != 0; Text++) + Res = ((unsigned long)(*Text) & 0xDF) ^ (Res << 1); + return Res & 0xFF; + } + + protected: const char *Stop; @@ -54,6 +65,8 @@ class pkgTagSection virtual void TrimRecord(bool BeforeRecord, const char* &End); inline unsigned int Count() const {return TagCount;}; + inline bool Exists(const char* const Tag) {return AlphaIndexes[AlphaHash(Tag)] != 0;} + inline void Get(const char *&Start,const char *&Stop,unsigned int I) const {Start = Section + Indexes[I]; Stop = Section + Indexes[I+1];} diff --git a/apt-pkg/versionmatch.cc b/apt-pkg/versionmatch.cc index b4d1d4696..e5f0fafd2 100644 --- a/apt-pkg/versionmatch.cc +++ b/apt-pkg/versionmatch.cc @@ -100,6 +100,8 @@ pkgVersionMatch::pkgVersionMatch(string Data,MatchType Type) : Type(Type) RelLabel = Fragments[J]+2; else if (stringcasecmp(Fragments[J],Fragments[J]+2,"c=") == 0) RelComponent = Fragments[J]+2; + else if (stringcasecmp(Fragments[J],Fragments[J]+2,"b=") == 0) + RelArchitecture = Fragments[J]+2; } if (RelVerStr.end()[-1] == '*') @@ -178,7 +180,7 @@ bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File) if (RelVerStr.empty() == true && RelOrigin.empty() == true && RelArchive.empty() == true && RelLabel.empty() == true && RelRelease.empty() == true && RelCodename.empty() == true && - RelComponent.empty() == true) + RelComponent.empty() == true && RelArchitecture.empty() == true) return false; if (RelVerStr.empty() == false) @@ -211,6 +213,10 @@ bool pkgVersionMatch::FileMatch(pkgCache::PkgFileIterator File) if (File->Component == 0 || stringcasecmp(RelComponent,File.Component()) != 0) return false; + if (RelArchitecture.empty() == false) + if (File->Architecture == 0 || + stringcasecmp(RelArchitecture,File.Architecture()) != 0) + return false; return true; } diff --git a/apt-pkg/versionmatch.h b/apt-pkg/versionmatch.h index a8f3c84ac..a8da072ae 100644 --- a/apt-pkg/versionmatch.h +++ b/apt-pkg/versionmatch.h @@ -23,6 +23,7 @@ Codename (n=) e.g. etch, lenny, squeeze, sid Label (l=) Component (c=) + Binary Architecture (b=) If there are no equals signs in the string then it is scanned in short form - if it starts with a number it is Version otherwise it is an Archive or a Codename. @@ -55,6 +56,7 @@ class pkgVersionMatch string RelArchive; string RelLabel; string RelComponent; + string RelArchitecture; bool MatchAll; // Origin Matching |