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!!
- This is the general utility functions for cache managment. They provide
+ This is the general utility functions for cache management. They provide
a complete set of accessor functions for the cache. The cacheiterators
header contains the STL-like iterators that can be used to easially
navigate the cache as well as seemlessly dereference the mmap'd
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
+#include<config.h>
+
#include <apt-pkg/pkgcache.h>
#include <apt-pkg/policy.h>
#include <apt-pkg/version.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/configuration.h>
#include <apt-pkg/aptconfiguration.h>
+#include <apt-pkg/mmap.h>
#include <apt-pkg/macros.h>
-#include <apti18n.h>
-
+#include <stddef.h>
+#include <string.h>
+#include <sstream>
+#include <algorithm>
+#include <vector>
#include <string>
#include <sys/stat.h>
-#include <unistd.h>
+#include <zlib.h>
-#include <ctype.h>
+#include <apti18n.h>
/*}}}*/
using std::string;
+using APT::StringView;
// Cache::Header::Header - Constructor /*{{{*/
/* Simply initialize the header */
pkgCache::Header::Header()
{
- Signature = 0x98FE76DC;
-
+#define APT_HEADER_SET(X,Y) X = Y; static_assert(std::numeric_limits<decltype(X)>::max() > Y, "Size violation detected in pkgCache::Header")
+ APT_HEADER_SET(Signature, 0x98FE76DC);
+
/* Whenever the structures change the major version should be bumped,
whenever the generator changes the minor version should be bumped. */
- MajorVersion = 8;
- MinorVersion = 0;
- Dirty = false;
-
- HeaderSz = sizeof(pkgCache::Header);
- GroupSz = sizeof(pkgCache::Group);
- PackageSz = sizeof(pkgCache::Package);
- PackageFileSz = sizeof(pkgCache::PackageFile);
- VersionSz = sizeof(pkgCache::Version);
- DescriptionSz = sizeof(pkgCache::Description);
- DependencySz = sizeof(pkgCache::Dependency);
- ProvidesSz = sizeof(pkgCache::Provides);
- VerFileSz = sizeof(pkgCache::VerFile);
- DescFileSz = sizeof(pkgCache::DescFile);
-
+ APT_HEADER_SET(MajorVersion, 10);
+ APT_HEADER_SET(MinorVersion, 6);
+ APT_HEADER_SET(Dirty, false);
+
+ APT_HEADER_SET(HeaderSz, sizeof(pkgCache::Header));
+ APT_HEADER_SET(GroupSz, sizeof(pkgCache::Group));
+ APT_HEADER_SET(PackageSz, sizeof(pkgCache::Package));
+ APT_HEADER_SET(ReleaseFileSz, sizeof(pkgCache::ReleaseFile));
+ APT_HEADER_SET(PackageFileSz, sizeof(pkgCache::PackageFile));
+ APT_HEADER_SET(VersionSz, sizeof(pkgCache::Version));
+ APT_HEADER_SET(DescriptionSz, sizeof(pkgCache::Description));
+ APT_HEADER_SET(DependencySz, sizeof(pkgCache::Dependency));
+ APT_HEADER_SET(DependencyDataSz, sizeof(pkgCache::DependencyData));
+ APT_HEADER_SET(ProvidesSz, sizeof(pkgCache::Provides));
+ APT_HEADER_SET(VerFileSz, sizeof(pkgCache::VerFile));
+ APT_HEADER_SET(DescFileSz, sizeof(pkgCache::DescFile));
+#undef APT_HEADER_SET
+
GroupCount = 0;
PackageCount = 0;
VersionCount = 0;
DescriptionCount = 0;
DependsCount = 0;
+ DependsDataCount = 0;
+ ReleaseFileCount = 0;
PackageFileCount = 0;
VerFileCount = 0;
DescFileCount = 0;
ProvidesCount = 0;
MaxVerFileSize = 0;
MaxDescFileSize = 0;
-
+
FileList = 0;
- StringList = 0;
+ RlsFileList = 0;
VerSysName = 0;
Architecture = 0;
- memset(PkgHashTable,0,sizeof(PkgHashTable));
- memset(GrpHashTable,0,sizeof(GrpHashTable));
+ SetArchitectures(0);
+ SetHashTableSize(_config->FindI("APT::Cache-HashTableSize", 50503));
memset(Pools,0,sizeof(Pools));
+
+ CacheFileSize = 0;
}
/*}}}*/
// Cache::Header::CheckSizes - Check if the two headers have same *sz /*{{{*/
if (HeaderSz == Against.HeaderSz &&
GroupSz == Against.GroupSz &&
PackageSz == Against.PackageSz &&
+ ReleaseFileSz == Against.ReleaseFileSz &&
PackageFileSz == Against.PackageFileSz &&
VersionSz == Against.VersionSz &&
DescriptionSz == Against.DescriptionSz &&
DependencySz == Against.DependencySz &&
+ DependencyDataSz == Against.DependencyDataSz &&
VerFileSz == Against.VerFileSz &&
DescFileSz == Against.DescFileSz &&
ProvidesSz == Against.ProvidesSz)
// Cache::pkgCache - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
-pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map)
+APT_IGNORE_DEPRECATED_PUSH
+pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map), VS(nullptr), d(NULL)
{
// call getArchitectures() with cached=false to ensure that the
// architectures cache is re-evaulated. this is needed in cases
if (DoMap == true)
ReMap();
}
+APT_IGNORE_DEPRECATED_POP
/*}}}*/
// Cache::ReMap - Reopen the cache file /*{{{*/
// ---------------------------------------------------------------------
PkgP = (Package *)Map.Data();
VerFileP = (VerFile *)Map.Data();
DescFileP = (DescFile *)Map.Data();
+ RlsFileP = (ReleaseFile *)Map.Data();
PkgFileP = (PackageFile *)Map.Data();
VerP = (Version *)Map.Data();
DescP = (Description *)Map.Data();
ProvideP = (Provides *)Map.Data();
DepP = (Dependency *)Map.Data();
- StringItemP = (StringItem *)Map.Data();
+ DepDataP = (DependencyData *)Map.Data();
StrP = (char *)Map.Data();
if (Errorchecks == false)
HeaderP->CheckSizes(DefHeader) == false)
return _error->Error(_("The package cache file is an incompatible version"));
+ if (HeaderP->VerSysName == 0 || HeaderP->Architecture == 0 || HeaderP->GetArchitectures() == 0)
+ return _error->Error(_("The package cache file is corrupted"));
+
// Locate our VS..
- if (HeaderP->VerSysName == 0 ||
- (VS = pkgVersioningSystem::GetVS(StrP + HeaderP->VerSysName)) == 0)
+ if ((VS = pkgVersioningSystem::GetVS(StrP + HeaderP->VerSysName)) == 0)
return _error->Error(_("This APT does not support the versioning system '%s'"),StrP + HeaderP->VerSysName);
- // Chcek the arhcitecture
- if (HeaderP->Architecture == 0 ||
- _config->Find("APT::Architecture") != StrP + HeaderP->Architecture)
- return _error->Error(_("The package cache was built for a different architecture"));
+ // Check the architecture
+ std::vector<std::string> archs = APT::Configuration::getArchitectures();
+ std::string list = "";
+ for (auto const & arch : archs) {
+ if (!list.empty())
+ list.append(",");
+ list.append(arch);
+ }
+ if (_config->Find("APT::Architecture") != StrP + HeaderP->Architecture ||
+ list != StrP + HeaderP->GetArchitectures())
+ return _error->Error(_("The package cache was built for different architectures: %s vs %s"), StrP + HeaderP->GetArchitectures(), list.c_str());
+
+
+ auto hash = CacheHash();
+ if (_config->FindB("Debug::pkgCacheGen", false))
+ std::clog << "Opened cache with hash " << hash << ", expecting " << HeaderP->CacheFileSize << "\n";
+ if (hash != HeaderP->CacheFileSize)
+ return _error->Error(_("The package cache file is corrupted, it has the wrong hash"));
+
return true;
}
/*}}}*/
/* This is used to generate the hash entries for the HashTable. With my
package list from bo this function gets 94% table usage on a 512 item
table (480 used items) */
-unsigned long pkgCache::sHash(const string &Str) const
+map_id_t pkgCache::sHash(StringView 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->PkgHashTable);
+ uint32_t Hash = 5381;
+ for (auto I = Str.begin(); I != Str.end(); ++I)
+ Hash = 33 * Hash + tolower_ascii(*I);
+ return Hash % HeaderP->GetHashTableSize();
+}
+map_id_t pkgCache::sHash(const string &Str) const
+{
+ uint32_t Hash = 5381;
+ for (string::const_iterator I = Str.begin(); I != Str.end(); ++I)
+ Hash = 33 * Hash + tolower_ascii((signed char)*I);
+ return Hash % HeaderP->GetHashTableSize();
}
-unsigned long pkgCache::sHash(const char *Str) const
+map_id_t 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->PkgHashTable);
+ uint32_t Hash = 5381;
+ for (const char *I = Str; *I != 0; ++I)
+ Hash = 33 * Hash + tolower_ascii((signed char)*I);
+ return Hash % HeaderP->GetHashTableSize();
}
- /*}}}*/
-// Cache::SingleArchFindPkg - Locate a package by 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)
+uint32_t pkgCache::CacheHash()
{
- // Look at the hash bucket
- 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);
+ pkgCache::Header header = {};
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ if (Map.Size() < sizeof(header))
+ return adler;
+ memcpy(&header, GetMap().Data(), sizeof(header));
+
+ header.Dirty = false;
+ header.CacheFileSize = 0;
+
+ adler = adler32(adler,
+ reinterpret_cast<const unsigned char *>(&header),
+ sizeof(header));
+
+ if (Map.Size() > sizeof(header)) {
+ adler = adler32(adler,
+ static_cast<const unsigned char *>(GetMap().Data()) + sizeof(header),
+ GetMap().Size() - sizeof(header));
}
- return PkgIterator(*this,0);
+
+ return adler;
}
/*}}}*/
// 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(':');
+ return FindPkg(StringView(Name));
+}
+
+pkgCache::PkgIterator pkgCache::FindPkg(StringView Name) {
+ auto const found = Name.rfind(':');
if (found == string::npos)
- return FindPkg(Name, "native");
- string const Arch = Name.substr(found+1);
+ return FindPkg(Name, "native");
+ auto const Arch = Name.substr(found+1);
+ /* Beware: This is specialcased to handle pkg:any in dependencies
+ as these are linked to virtual pkg:any named packages.
+ If you want any arch from a pkg, use FindPkg(pkg,"any") */
if (Arch == "any")
return FindPkg(Name, "any");
return FindPkg(Name.substr(0, found), Arch);
// ---------------------------------------------------------------------
/* 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);
- }
+ return FindPkg(StringView(Name), StringView(Arch));
+}
+
+pkgCache::PkgIterator pkgCache::FindPkg(StringView Name, StringView Arch) {
/* 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) */
// ---------------------------------------------------------------------
/* Returns End-Pointer on error, pointer to the group otherwise */
pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) {
+ return FindGrp(StringView(Name));
+}
+
+pkgCache::GrpIterator pkgCache::FindGrp(StringView 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)];
+ Group *Grp = GrpP + HeaderP->GrpHashTableP()[sHash(Name)];
for (; Grp != GrpP; Grp = GrpP + Grp->Next) {
- if (Grp->Name != 0 && StrP[Grp->Name] == Name[0] &&
- stringcasecmp(Name, StrP + Grp->Name) == 0)
+ int const cmp = Name.compare(ViewString(Grp->Name));
+ if (cmp == 0)
return GrpIterator(*this, Grp);
+ else if (cmp < 0)
+ break;
}
return GrpIterator(*this,0);
type in the weird debian style.. */
const char *pkgCache::CompTypeDeb(unsigned char Comp)
{
- const char *Ops[] = {"","<=",">=","<<",">>","=","!="};
- if ((unsigned)(Comp & 0xF) < 7)
- return Ops[Comp & 0xF];
- return "";
+ const char * const Ops[] = {"","<=",">=","<<",">>","=","!="};
+ if (unlikely((unsigned)(Comp & 0xF) >= sizeof(Ops)/sizeof(Ops[0])))
+ return "";
+ return Ops[Comp & 0xF];
}
/*}}}*/
// Cache::CompType - Return a string describing the compare type /*{{{*/
// ---------------------------------------------------------------------
-/* This returns a string representation of the dependency compare
+/* This returns a string representation of the dependency compare
type */
const char *pkgCache::CompType(unsigned char Comp)
{
- const char *Ops[] = {"","<=",">=","<",">","=","!="};
- if ((unsigned)(Comp & 0xF) < 7)
- return Ops[Comp & 0xF];
- return "";
+ const char * const Ops[] = {"","<=",">=","<",">","=","!="};
+ if (unlikely((unsigned)(Comp & 0xF) >= sizeof(Ops)/sizeof(Ops[0])))
+ return "";
+ return Ops[Comp & 0xF];
}
/*}}}*/
// Cache::DepType - Return a string describing the dep type /*{{{*/
/* */
const char *pkgCache::Priority(unsigned char Prio)
{
- const char *Mapping[] = {0,_("important"),_("required"),_("standard"),
+ const char *Mapping[] = {0,_("required"),_("important"),_("standard"),
_("optional"),_("extra")};
if (Prio < _count(Mapping))
return Mapping[Prio];
// ---------------------------------------------------------------------
/* Returns an End-Pointer on error, pointer to the package otherwise */
pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) const {
+ return FindPkg(StringView(Arch));
+}
+pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(const char *Arch) const {
+ return FindPkg(StringView(Arch));
+}
+pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(StringView Arch) const {
if (unlikely(IsGood() == false || S->FirstPackage == 0))
return PkgIterator(*Owner, 0);
/* If we accept any package we simply return the "first"
- package in this group (the last one added). */
+ package in this group */
if (Arch == "any")
return PkgIterator(*Owner, Owner->PkgP + S->FirstPackage);
+ if (Arch == "native" || Arch == "all")
+ Arch = Owner->NativeArch();
- 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 == "all") {
- Arch = myArch;
- pkgCache::Package *Pkg = Owner->PkgP + S->LastPackage;
- if (stringcasecmp(Arch, Owner->StrP + Pkg->Arch) == 0)
- return PkgIterator(*Owner, Pkg);
- }
-
- /* 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 */
+ // Iterate over the list to find the matching arch
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)
+ if (Arch == Owner->ViewString(Pkg->Arch))
return PkgIterator(*Owner, Pkg);
if ((Owner->PkgP + S->LastPackage) == Pkg)
break;
// ---------------------------------------------------------------------
/* Returns an End-Pointer on error, pointer to the package otherwise */
pkgCache::PkgIterator pkgCache::GrpIterator::FindPreferredPkg(bool const &PreferNonVirtual) const {
- pkgCache::PkgIterator Pkg = FindPkg("native");
+ pkgCache::PkgIterator Pkg = FindPkg(StringView("native", 6));
if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
return Pkg;
if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
return Pkg;
}
+ // packages without an architecture
+ Pkg = FindPkg(StringView("none", 4));
+ if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0))
+ return Pkg;
if (PreferNonVirtual == true)
return FindPreferredPkg(false);
return PkgIterator(*Owner, Owner->PkgP + LastPkg->NextPackage);
}
/*}}}*/
-// GrpIterator::operator ++ - Postfix incr /*{{{*/
+// GrpIterator::operator++ - Prefix incr /*{{{*/
// ---------------------------------------------------------------------
/* This will advance to the next logical group in the hash table. */
-void pkgCache::GrpIterator::operator ++(int)
+pkgCache::GrpIterator& pkgCache::GrpIterator::operator++()
{
// 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))
+ while (S == Owner->GrpP && (HashIndex+1) < (signed)Owner->HeaderP->GetHashTableSize())
{
- HashIndex++;
- S = Owner->GrpP + Owner->HeaderP->GrpHashTable[HashIndex];
+ ++HashIndex;
+ S = Owner->GrpP + Owner->HeaderP->GrpHashTableP()[HashIndex];
}
-};
+ return *this;
+}
/*}}}*/
-// PkgIterator::operator ++ - Postfix incr /*{{{*/
+// PkgIterator::operator++ - Prefix incr /*{{{*/
// ---------------------------------------------------------------------
/* This will advance to the next logical package in the hash table. */
-void pkgCache::PkgIterator::operator ++(int)
+pkgCache::PkgIterator& pkgCache::PkgIterator::operator++()
{
// Follow the current links
if (S != Owner->PkgP)
S = Owner->PkgP + S->NextPackage;
// Follow the hash table
- while (S == Owner->PkgP && (HashIndex+1) < (signed)_count(Owner->HeaderP->PkgHashTable))
+ while (S == Owner->PkgP && (HashIndex+1) < (signed)Owner->HeaderP->GetHashTableSize())
{
- HashIndex++;
- S = Owner->PkgP + Owner->HeaderP->PkgHashTable[HashIndex];
+ ++HashIndex;
+ S = Owner->PkgP + Owner->HeaderP->PkgHashTableP()[HashIndex];
}
-};
+ return *this;
+}
+ /*}}}*/
+pkgCache::DepIterator& pkgCache::DepIterator::operator++() /*{{{*/
+{
+ if (S == Owner->DepP)
+ return *this;
+ S = Owner->DepP + (Type == DepVer ? S->NextDepends : S->NextRevDepends);
+ if (S == Owner->DepP)
+ S2 = Owner->DepDataP;
+ else
+ S2 = Owner->DepDataP + S->DependencyData;
+ return *this;
+}
/*}}}*/
// PkgIterator::State - Check the State of the package /*{{{*/
// ---------------------------------------------------------------------
if (S->CurrentState == pkgCache::State::UnPacked ||
S->CurrentState == pkgCache::State::HalfConfigured)
- // we leave triggers alone complettely. dpkg deals with
+ // we leave triggers alone completely. dpkg deals with
// them in a hard-to-predict manner and if they get
// resolved by dpkg before apt run dpkg --configure on
// the TriggersPending package dpkg returns a error
// ---------------------------------------------------------------------
/* Return string representing of the candidate version. */
const char *
-pkgCache::PkgIterator::CandVersion() const
+pkgCache::PkgIterator::CandVersion() const
{
//TargetVer is empty, so don't use it.
VerIterator version = pkgPolicy(Owner).GetCandidateVer(*this);
if (version.IsGood())
return version.VerStr();
return 0;
-};
+}
/*}}}*/
// PkgIterator::CurVersion - Returns the current version string /*{{{*/
// ---------------------------------------------------------------------
/* Return string representing of the current version. */
const char *
-pkgCache::PkgIterator::CurVersion() const
+pkgCache::PkgIterator::CurVersion() const
{
VerIterator version = CurrentVer();
if (version.IsGood())
return CurrentVer().VerStr();
return 0;
-};
+}
/*}}}*/
// ostream operator to handle string representation of a package /*{{{*/
// ---------------------------------------------------------------------
/* Output name < cur.rent.version -> candid.ate.version | new.est.version > (section)
- Note that the characters <|>() are all literal above. Versions will be ommited
+ Note that the characters <|>() are all literal above. Versions will be omitted
if they provide no new information (e.g. there is no newer version than candidate)
If no version and/or section can be found "none" is used. */
std::ostream&
-operator<<(ostream& out, pkgCache::PkgIterator Pkg)
+operator<<(std::ostream& out, pkgCache::PkgIterator Pkg)
{
if (Pkg.end() == true)
return out << "invalid package";
string current = string(Pkg.CurVersion() == 0 ? "none" : Pkg.CurVersion());
+APT_IGNORE_DEPRECATED_PUSH
string candidate = string(Pkg.CandVersion() == 0 ? "none" : Pkg.CandVersion());
+APT_IGNORE_DEPRECATED_POP
string newest = string(Pkg.VersionList().end() ? "none" : Pkg.VersionList().VerStr());
out << Pkg.Name() << " [ " << Pkg.Arch() << " ] < " << current;
out << " -> " << candidate;
if ( newest != "none" && candidate != newest)
out << " | " << newest;
- out << " > ( " << string(Pkg.Section()==0?"none":Pkg.Section()) << " )";
+ if (Pkg->VersionList == 0)
+ out << " > ( none )";
+ else
+ out << " > ( " << string(Pkg.VersionList().Section()==0?"unknown":Pkg.VersionList().Section()) << " )";
return out;
}
/*}}}*/
{
string fullname = Name();
if (Pretty == false ||
- (strcmp(Arch(), "all") != 0 && _config->Find("APT::Architecture") != Arch()))
+ (strcmp(Arch(), "all") != 0 && strcmp(Arch(), "any") != 0 &&
+ strcmp(Owner->NativeArch(), Arch()) != 0))
return fullname.append(":").append(Arch());
return fullname;
}
conflicts (including dpkg's Breaks fields). */
bool pkgCache::DepIterator::IsCritical() const
{
- 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)
+ if (IsNegative() == true ||
+ S2->Type == pkgCache::Dep::Depends ||
+ S2->Type == pkgCache::Dep::PreDepends)
return true;
return false;
}
/*}}}*/
+// DepIterator::IsNegative - Returns true if the dep is a negative one /*{{{*/
+// ---------------------------------------------------------------------
+/* Some dependencies are positive like Depends and Recommends, others
+ are negative like Conflicts which can and should be handled differently */
+bool pkgCache::DepIterator::IsNegative() const
+{
+ return S2->Type == Dep::DpkgBreaks ||
+ S2->Type == Dep::Conflicts ||
+ S2->Type == Dep::Obsoletes;
+}
+ /*}}}*/
// DepIterator::SmartTargetPkg - Resolve dep target pointers w/provides /*{{{*/
// ---------------------------------------------------------------------
/* This intellegently looks at dep target packages and tries to figure
virtual package libc-dev which is provided by libc5-dev and libc6-dev
we must ignore libc5-dev when considering the provides list. */
PrvIterator PStart = Result.ProvidesList();
- for (; PStart.end() != true && PStart.OwnerPkg() == ParentPkg(); PStart++);
+ for (; PStart.end() != true && PStart.OwnerPkg() == ParentPkg(); ++PStart);
// Nothing but indirect self provides
if (PStart.end() == true)
// Check for single packages in the provides list
PrvIterator P = PStart;
- for (; P.end() != true; P++)
+ for (; P.end() != true; ++P)
{
// Skip over self provides
if (P.OwnerPkg() == ParentPkg())
PkgIterator DPkg = TargetPkg();
// Walk along the actual package providing versions
- for (VerIterator I = DPkg.VersionList(); I.end() == false; I++)
+ for (VerIterator I = DPkg.VersionList(); I.end() == false; ++I)
{
- if (Owner->VS->CheckDep(I.VerStr(),S->CompareOp,TargetVer()) == false)
+ if (IsIgnorable(I.ParentPkg()) == true)
continue;
-
- if ((S->Type == pkgCache::Dep::Conflicts ||
- S->Type == pkgCache::Dep::DpkgBreaks ||
- S->Type == pkgCache::Dep::Obsoletes) &&
- ParentPkg() == I.ParentPkg())
+ if (IsSatisfied(I) == false)
continue;
-
+
Size++;
if (Res != 0)
*End++ = I;
}
// Follow all provides
- for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++)
+ for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; ++I)
{
- if (Owner->VS->CheckDep(I.ProvideVersion(),S->CompareOp,TargetVer()) == false)
+ if (IsIgnorable(I) == true)
continue;
-
- if ((S->Type == pkgCache::Dep::Conflicts ||
- S->Type == pkgCache::Dep::DpkgBreaks ||
- S->Type == pkgCache::Dep::Obsoletes) &&
- ParentPkg() == I.OwnerPkg())
+ if (IsSatisfied(I) == false)
continue;
-
+
Size++;
if (Res != 0)
*End++ = I.OwnerVer();
End = *this;
for (bool LastOR = true; end() == false && LastOR == true;)
{
- LastOR = (S->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
- (*this)++;
+ LastOR = (S2->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
+ ++(*this);
if (LastOR == true)
End = (*this);
}
}
/*}}}*/
-// ostream operator to handle string representation of a dependecy /*{{{*/
+// DepIterator::IsIgnorable - should this packag/providr be ignored? /*{{{*/
+// ---------------------------------------------------------------------
+/* Deps like self-conflicts should be ignored as well as implicit conflicts
+ on virtual packages. */
+bool pkgCache::DepIterator::IsIgnorable(PkgIterator const &PT) const
+{
+ if (IsNegative() == false)
+ return false;
+
+ pkgCache::PkgIterator const PP = ParentPkg();
+ if (PP->Group != PT->Group)
+ return false;
+ // self-conflict
+ if (PP == PT)
+ return true;
+ pkgCache::VerIterator const PV = ParentVer();
+ // ignore group-conflict on a M-A:same package - but not our implicit dependencies
+ // so that we can have M-A:same packages conflicting with their own real name
+ if ((PV->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
+ return IsMultiArchImplicit() == false;
+
+ return false;
+}
+bool pkgCache::DepIterator::IsIgnorable(PrvIterator const &Prv) const
+{
+ if (IsNegative() == false)
+ return false;
+
+ PkgIterator const Pkg = ParentPkg();
+ /* Provides may never be applied against the same package (or group)
+ if it is a conflicts. See the comment above. */
+ if (Prv.OwnerPkg()->Group == Pkg->Group)
+ return true;
+ // Implicit group-conflicts should not be applied on providers of other groups
+ if (IsMultiArchImplicit() && Prv.OwnerPkg()->Group != Pkg->Group)
+ return true;
+
+ return false;
+}
+ /*}}}*/
+// DepIterator::IsSatisfied - check if a version satisfied the dependency /*{{{*/
+bool pkgCache::DepIterator::IsSatisfied(VerIterator const &Ver) const
+{
+ return Owner->VS->CheckDep(Ver.VerStr(),S2->CompareOp,TargetVer());
+}
+bool pkgCache::DepIterator::IsSatisfied(PrvIterator const &Prv) const
+{
+ return Owner->VS->CheckDep(Prv.ProvideVersion(),S2->CompareOp,TargetVer());
+}
+ /*}}}*/
+// DepIterator::IsImplicit - added by the cache generation /*{{{*/
+bool pkgCache::DepIterator::IsImplicit() const
+{
+ if (IsMultiArchImplicit() == true)
+ return true;
+ if (IsNegative() || S2->Type == pkgCache::Dep::Replaces)
+ {
+ if ((S2->CompareOp & pkgCache::Dep::ArchSpecific) != pkgCache::Dep::ArchSpecific &&
+ strcmp(ParentPkg().Arch(), TargetPkg().Arch()) != 0)
+ return true;
+ }
+ return false;
+}
+ /*}}}*/
+// ostream operator to handle string representation of a dependency /*{{{*/
// ---------------------------------------------------------------------
/* */
-std::ostream& operator<<(ostream& out, pkgCache::DepIterator D)
+std::ostream& operator<<(std::ostream& out, pkgCache::DepIterator D)
{
if (D.end() == true)
return out << "invalid dependency";
out << (P.end() ? "invalid pkg" : P.FullName(false)) << " " << D.DepType()
<< " on ";
+APT_IGNORE_DEPRECATED_PUSH
if (T.end() == true)
out << "invalid pkg";
else
out << T;
+APT_IGNORE_DEPRECATED_POP
if (D->Version != 0)
out << " (" << D.CompType() << " " << D.TargetVer() << ")";
/* Start at A and look for B. If B is found then A > B otherwise
B was before A so A < B */
VerIterator I = *this;
- for (;I.end() == false; I++)
+ for (;I.end() == false; ++I)
if (I == B)
return 1;
return -1;
// VerIterator::Downloadable - Checks if the version is downloadable /*{{{*/
// ---------------------------------------------------------------------
/* */
-bool pkgCache::VerIterator::Downloadable() const
+APT_PURE bool pkgCache::VerIterator::Downloadable() const
{
VerFileIterator Files = FileList();
- for (; Files.end() == false; Files++)
- if ((Files.File()->Flags & pkgCache::Flag::NotSource) != pkgCache::Flag::NotSource)
+ for (; Files.end() == false; ++Files)
+ if (Files.File().Flagged(pkgCache::Flag::NotSource) == false)
return true;
return false;
}
// ---------------------------------------------------------------------
/* This checks to see if any of the versions files are not NotAutomatic.
True if this version is selectable for automatic installation. */
-bool pkgCache::VerIterator::Automatic() const
+APT_PURE bool pkgCache::VerIterator::Automatic() const
{
VerFileIterator Files = FileList();
- for (; Files.end() == false; Files++)
+ for (; Files.end() == false; ++Files)
// Do not check ButAutomaticUpgrades here as it is kind of automatic…
- if ((Files.File()->Flags & pkgCache::Flag::NotAutomatic) != pkgCache::Flag::NotAutomatic)
+ if (Files.File().Flagged(pkgCache::Flag::NotAutomatic) == false)
return true;
return false;
}
/*}}}*/
-// VerIterator::Pseudo - deprecated no-op method /*{{{*/
-bool pkgCache::VerIterator::Pseudo() const { return false; }
- /*}}}*/
// VerIterator::NewestFile - Return the newest file version relation /*{{{*/
// ---------------------------------------------------------------------
/* This looks at the version numbers associated with all of the sources
{
VerFileIterator Files = FileList();
VerFileIterator Highest = Files;
- for (; Files.end() == false; Files++)
+ for (; Files.end() == false; ++Files)
{
if (Owner->VS->CmpReleaseVer(Files.File().Version(),Highest.File().Version()) > 0)
Highest = Files;
// ---------------------------------------------------------------------
/* This describes the version from a release-centric manner. The output is a
list of Label:Version/Archive */
+static std::string PkgFileIteratorToRelString(pkgCache::PkgFileIterator const &File)
+{
+ std::string Res;
+ if (File.Label() != 0)
+ Res = Res + File.Label() + ':';
+
+ if (File.Archive() != 0)
+ {
+ if (File.Version() == 0)
+ Res += File.Archive();
+ else
+ Res = Res + File.Version() + '/' + File.Archive();
+ }
+ else
+ {
+ // No release file, print the host name that this came from
+ if (File.Site() == 0 || File.Site()[0] == 0)
+ Res += "localhost";
+ else
+ Res += File.Site();
+ }
+ return Res;
+}
string pkgCache::VerIterator::RelStr() const
{
- bool First = true;
- string Res;
- for (pkgCache::VerFileIterator I = this->FileList(); I.end() == false; I++)
+ std::vector<std::string> RelStrs;
+ for (pkgCache::VerFileIterator I = this->FileList(); I.end() == false; ++I)
{
// Do not print 'not source' entries'
- pkgCache::PkgFileIterator File = I.File();
- if ((File->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
+ pkgCache::PkgFileIterator const File = I.File();
+ if (File.Flagged(pkgCache::Flag::NotSource))
continue;
- // See if we have already printed this out..
- bool Seen = false;
- for (pkgCache::VerFileIterator J = this->FileList(); I != J; J++)
- {
- pkgCache::PkgFileIterator File2 = J.File();
- if (File2->Label == 0 || File->Label == 0)
- continue;
-
- if (strcmp(File.Label(),File2.Label()) != 0)
- continue;
-
- if (File2->Version == File->Version)
- {
- Seen = true;
- break;
- }
- if (File2->Version == 0 || File->Version == 0)
- break;
- if (strcmp(File.Version(),File2.Version()) == 0)
- Seen = true;
- }
-
- if (Seen == true)
+ std::string const RS = PkgFileIteratorToRelString(File);
+ if (std::find(RelStrs.begin(), RelStrs.end(), RS) != RelStrs.end())
continue;
-
- if (First == false)
- Res += ", ";
- else
- First = false;
-
- if (File->Label != 0)
- Res = Res + File.Label() + ':';
- if (File->Archive != 0)
- {
- if (File->Version == 0)
- Res += File.Archive();
- else
- Res = Res + File.Version() + '/' + File.Archive();
- }
- else
- {
- // No release file, print the host name that this came from
- if (File->Site == 0 || File.Site()[0] == 0)
- Res += "localhost";
- else
- Res += File.Site();
- }
+ RelStrs.push_back(RS);
+ }
+ std::ostringstream os;
+ if (likely(RelStrs.empty() == false))
+ {
+ std::copy(RelStrs.begin(), RelStrs.end()-1, std::ostream_iterator<std::string>(os, ", "));
+ os << *RelStrs.rbegin();
}
if (S->ParentPkg != 0)
- Res.append(" [").append(Arch()).append("]");
- return Res;
+ os << " [" << Arch() << "]";
+ return os.str();
}
/*}}}*/
-// PkgFileIterator::IsOk - Checks if the cache is in sync with the file /*{{{*/
+// VerIterator::MultiArchType - string representing MultiArch flag /*{{{*/
+const char * pkgCache::VerIterator::MultiArchType() const
+{
+ if ((S->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same)
+ return "same";
+ else if ((S->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
+ return "foreign";
+ else if ((S->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed)
+ return "allowed";
+ return "none";
+}
+ /*}}}*/
+// RlsFileIterator::IsOk - Checks if the cache is in sync with the file /*{{{*/
// ---------------------------------------------------------------------
/* This stats the file and compares its stats with the ones that were
- stored during generation. Date checks should probably also be
+ stored during generation. Date checks should probably also be
included here. */
-bool pkgCache::PkgFileIterator::IsOk()
+bool pkgCache::RlsFileIterator::IsOk()
{
struct stat Buf;
if (stat(FileName(),&Buf) != 0)
return true;
}
/*}}}*/
-// PkgFileIterator::RelStr - Return the release string /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-string pkgCache::PkgFileIterator::RelStr()
+// RlsFileIterator::RelStr - Return the release string /*{{{*/
+string pkgCache::RlsFileIterator::RelStr()
{
string Res;
if (Version() != 0)
Res = Res + (Res.empty() == true?"n=":",n=") + Codename();
if (Label() != 0)
Res = Res + (Res.empty() == true?"l=":",l=") + Label();
- if (Component() != 0)
- Res = Res + (Res.empty() == true?"c=":",c=") + Component();
+ return Res;
+}
+ /*}}}*/
+// PkgFileIterator::IsOk - Checks if the cache is in sync with the file /*{{{*/
+// ---------------------------------------------------------------------
+/* This stats the file and compares its stats with the ones that were
+ stored during generation. Date checks should probably also be
+ included here. */
+bool pkgCache::PkgFileIterator::IsOk()
+{
+ struct stat Buf;
+ if (stat(FileName(),&Buf) != 0)
+ return false;
+
+ if (Buf.st_size != (signed)S->Size || Buf.st_mtime != S->mtime)
+ return false;
+
+ return true;
+}
+ /*}}}*/
+string pkgCache::PkgFileIterator::RelStr() /*{{{*/
+{
+ std::string Res;
+ if (ReleaseFile() == 0)
+ {
+ if (Component() != 0)
+ Res = Res + (Res.empty() == true?"a=":",a=") + Component();
+ }
+ else
+ {
+ Res = ReleaseFile().RelStr();
+ if (Component() != 0)
+ Res = Res + (Res.empty() == true?"c=":",c=") + Component();
+ }
if (Architecture() != 0)
Res = Res + (Res.empty() == true?"b=":",b=") + Architecture();
return Res;
/*}}}*/
// VerIterator::TranslatedDescription - Return the a DescIter for locale/*{{{*/
// ---------------------------------------------------------------------
-/* return a DescIter for the current locale or the default if none is
+/* return a DescIter for the current locale or the default if none is
* found
*/
pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const
{
std::vector<string> const lang = APT::Configuration::getLanguages();
for (std::vector<string>::const_iterator l = lang.begin();
- l != lang.end(); l++)
+ l != lang.end(); ++l)
{
pkgCache::DescIterator Desc = DescriptionList();
for (; Desc.end() == false; ++Desc)
- if (*l == Desc.LanguageCode() ||
- (*l == "en" && strcmp(Desc.LanguageCode(),"") == 0))
+ if (*l == Desc.LanguageCode())
break;
if (Desc.end() == true)
- continue;
+ {
+ if (*l == "en")
+ {
+ Desc = DescriptionList();
+ for (; Desc.end() == false; ++Desc)
+ if (strcmp(Desc.LanguageCode(), "") == 0)
+ break;
+ if (Desc.end() == true)
+ continue;
+ }
+ else
+ continue;
+ }
return Desc;
}
for (pkgCache::DescIterator Desc = DescriptionList();
if (strcmp(Desc.LanguageCode(), "") == 0)
return Desc;
return DescriptionList();
-};
+}
/*}}}*/
+
+pkgCache::~pkgCache() {}