X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/0418949ebe9fc886e7794fa1de17c8b6c74e65ea..32ab4bd05cb298f6bf1f9574f5b20570beaae429:/apt-pkg/pkgcache.cc?ds=sidebyside diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index c854249e4..8d6e242b1 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -8,7 +8,7 @@ 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 @@ -29,12 +29,15 @@ #include #include #include +#include #include +#include +#include +#include +#include #include #include -#include -#include #include /*}}}*/ @@ -51,7 +54,7 @@ pkgCache::Header::Header() /* Whenever the structures change the major version should be bumped, whenever the generator changes the minor version should be bumped. */ - MajorVersion = 8; + MajorVersion = 10; MinorVersion = 0; Dirty = false; @@ -79,11 +82,13 @@ pkgCache::Header::Header() MaxDescFileSize = 0; FileList = 0; - StringList = 0; +#if APT_PKG_ABI < 413 + APT_IGNORE_DEPRECATED(StringList = 0;) +#endif VerSysName = 0; Architecture = 0; - memset(PkgHashTable,0,sizeof(PkgHashTable)); - memset(GrpHashTable,0,sizeof(GrpHashTable)); + SetArchitectures(0); + SetHashTableSize(_config->FindI("APT::Cache-HashTableSize", 10 * 1048)); memset(Pools,0,sizeof(Pools)); CacheFileSize = 0; @@ -112,6 +117,7 @@ bool pkgCache::Header::CheckSizes(Header &Against) const // Cache::pkgCache - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ +APT_IGNORE_DEPRECATED_PUSH pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map) { // call getArchitectures() with cached=false to ensure that the @@ -121,6 +127,7 @@ pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map) if (DoMap == true) ReMap(); } +APT_IGNORE_DEPRECATED_POP /*}}}*/ // Cache::ReMap - Reopen the cache file /*{{{*/ // --------------------------------------------------------------------- @@ -138,7 +145,6 @@ bool pkgCache::ReMap(bool const &Errorchecks) DescP = (Description *)Map.Data(); ProvideP = (Provides *)Map.Data(); DepP = (Dependency *)Map.Data(); - StringItemP = (StringItem *)Map.Data(); StrP = (char *)Map.Data(); if (Errorchecks == false) @@ -161,15 +167,23 @@ bool pkgCache::ReMap(bool const &Errorchecks) if (Map.Size() < HeaderP->CacheFileSize) return _error->Error(_("The package cache file is corrupted, it is too small")); + 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 archs = APT::Configuration::getArchitectures(); + std::vector::const_iterator a = archs.begin(); + std::string list = *a; + for (++a; a != archs.end(); ++a) + list.append(",").append(*a); + 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()); + return true; } /*}}}*/ @@ -178,22 +192,21 @@ bool pkgCache::ReMap(bool const &Errorchecks) /* 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(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->PkgHashTable); + Hash = 41 * Hash + tolower_ascii(*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); + unsigned long Hash = tolower_ascii(*Str); + for (const char *I = Str + 1; *I != 0; ++I) + Hash = 41 * Hash + tolower_ascii(*I); + return Hash % HeaderP->GetHashTableSize(); } - /*}}}*/ // Cache::SingleArchFindPkg - Locate a package by name /*{{{*/ // --------------------------------------------------------------------- @@ -203,12 +216,14 @@ unsigned long pkgCache::sHash(const char *Str) const pkgCache::PkgIterator pkgCache::SingleArchFindPkg(const string &Name) { // Look at the hash bucket - Package *Pkg = PkgP + HeaderP->PkgHashTable[Hash(Name)]; + Package *Pkg = PkgP + HeaderP->PkgHashTableP()[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); + int const cmp = strcmp(Name.c_str(), StrP + (GrpP + Pkg->Group)->Name); + if (cmp == 0) + return PkgIterator(*this, Pkg); + else if (cmp < 0) + break; } return PkgIterator(*this,0); } @@ -238,7 +253,7 @@ pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) { // --------------------------------------------------------------------- /* Returns 0 on error, pointer to the package otherwise */ pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string const &Arch) { - if (MultiArchCache() == false) { + if (MultiArchCache() == false && Arch != "none") { if (Arch == "native" || Arch == "all" || Arch == "any" || Arch == NativeArch()) return SingleArchFindPkg(Name); @@ -263,11 +278,13 @@ pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) { 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 = strcmp(Name.c_str(), StrP + Grp->Name); + if (cmp == 0) return GrpIterator(*this, Grp); + else if (cmp < 0) + break; } return GrpIterator(*this,0); @@ -279,22 +296,22 @@ pkgCache::GrpIterator pkgCache::FindGrp(const string &Name) { 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 /*{{{*/ @@ -340,19 +357,15 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) const { last one we check, so we do it now. */ if (Arch == "native" || Arch == myArch || Arch == "all") { pkgCache::Package *Pkg = Owner->PkgP + S->LastPackage; - if (strcasecmp(myArch, Owner->StrP + Pkg->Arch) == 0) + if (strcmp(myArch, Owner->StrP + Pkg->Arch) == 0) return PkgIterator(*Owner, Pkg); Arch = myArch; } - /* 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 (stringcmp(Arch, Owner->StrP + Pkg->Arch) == 0) return PkgIterator(*Owner, Pkg); if ((Owner->PkgP + S->LastPackage) == Pkg) break; @@ -376,6 +389,10 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPreferredPkg(bool const &Prefer if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0)) return Pkg; } + // packages without an architecture + Pkg = FindPkg("none"); + if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0)) + return Pkg; if (PreferNonVirtual == true) return FindPreferredPkg(false); @@ -401,36 +418,36 @@ pkgCache::PkgIterator pkgCache::GrpIterator::NextPkg(pkgCache::PkgIterator const // GrpIterator::operator ++ - Postfix incr /*{{{*/ // --------------------------------------------------------------------- /* This will advance to the next logical group in the hash table. */ -void pkgCache::GrpIterator::operator ++(int) +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)) + while (S == Owner->GrpP && (HashIndex+1) < (signed)Owner->HeaderP->GetHashTableSize()) { HashIndex++; - S = Owner->GrpP + Owner->HeaderP->GrpHashTable[HashIndex]; + S = Owner->GrpP + Owner->HeaderP->GrpHashTableP()[HashIndex]; } -}; +} /*}}}*/ // PkgIterator::operator ++ - Postfix incr /*{{{*/ // --------------------------------------------------------------------- /* This will advance to the next logical package in the hash table. */ -void pkgCache::PkgIterator::operator ++(int) +void pkgCache::PkgIterator::operator ++(int) { // 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]; + S = Owner->PkgP + Owner->HeaderP->PkgHashTableP()[HashIndex]; } -}; +} /*}}}*/ // PkgIterator::State - Check the State of the package /*{{{*/ // --------------------------------------------------------------------- @@ -462,31 +479,31 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const // --------------------------------------------------------------------- /* 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& @@ -504,7 +521,10 @@ operator<<(std::ostream& out, pkgCache::PkgIterator Pkg) 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; } /*}}}*/ @@ -619,13 +639,11 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() const // Walk along the actual package providing versions 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 (IsNegative() == true && - ParentPkg() == I.ParentPkg()) + if (IsSatisfied(I) == false) continue; - + Size++; if (Res != 0) *End++ = I; @@ -634,13 +652,11 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() const // Follow all provides 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 (IsNegative() == true && - ParentPkg()->Group == I.OwnerPkg()->Group) + if (IsSatisfied(I) == false) continue; - + Size++; if (Res != 0) *End++ = I.OwnerVer(); @@ -682,6 +698,80 @@ void pkgCache::DepIterator::GlobOr(DepIterator &Start,DepIterator &End) } } /*}}}*/ +// 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 &/*Pkg*/) const +{ + if (IsNegative() == false) + return false; + + pkgCache::PkgIterator PP = ParentPkg(); + pkgCache::PkgIterator PT = TargetPkg(); + if (PP->Group != PT->Group) + return false; + // self-conflict + if (PP == PT) + return true; + pkgCache::VerIterator 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) + { + // Replaces: ${self}:other ( << ${binary:Version}) + if (S->Type == pkgCache::Dep::Replaces && S->CompareOp == pkgCache::Dep::Less && strcmp(PV.VerStr(), TargetVer()) == 0) + return false; + // Breaks: ${self}:other (!= ${binary:Version}) + if (S->Type == pkgCache::Dep::DpkgBreaks && S->CompareOp == pkgCache::Dep::NotEquals && strcmp(PV.VerStr(), TargetVer()) == 0) + return false; + return true; + } + + 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 (Pkg->Group == TargetPkg()->Group && Prv.OwnerPkg()->Group != Pkg->Group) + return true; + + return false; +} + /*}}}*/ +// DepIterator::IsMultiArchImplicit - added by the cache generation /*{{{*/ +// --------------------------------------------------------------------- +/* MultiArch can be translated to SingleArch for an resolver and we did so, + by adding dependencies to help the resolver understand the problem, but + sometimes it is needed to identify these to ignore them… */ +bool pkgCache::DepIterator::IsMultiArchImplicit() const +{ + if (ParentPkg()->Arch != TargetPkg()->Arch && + (S->Type == pkgCache::Dep::Replaces || + S->Type == pkgCache::Dep::DpkgBreaks || + S->Type == pkgCache::Dep::Conflicts)) + 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(),S->CompareOp,TargetVer()); +} +bool pkgCache::DepIterator::IsSatisfied(PrvIterator const &Prv) const +{ + return Owner->VS->CheckDep(Prv.ProvideVersion(),S->CompareOp,TargetVer()); +} + /*}}}*/ // ostream operator to handle string representation of a dependecy /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -732,7 +822,7 @@ int pkgCache::VerIterator::CompareVer(const VerIterator &B) const // 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) @@ -745,7 +835,7 @@ bool pkgCache::VerIterator::Downloadable() const // --------------------------------------------------------------------- /* 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) @@ -841,6 +931,18 @@ string pkgCache::VerIterator::RelStr() const return Res; } /*}}}*/ +// 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"; +} + /*}}}*/ // 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 @@ -883,7 +985,7 @@ string pkgCache::PkgFileIterator::RelStr() /*}}}*/ // 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 @@ -917,6 +1019,26 @@ pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const if (strcmp(Desc.LanguageCode(), "") == 0) return Desc; return DescriptionList(); -}; +} /*}}}*/ +// PrvIterator::IsMultiArchImplicit - added by the cache generation /*{{{*/ +// --------------------------------------------------------------------- +/* MultiArch can be translated to SingleArch for an resolver and we did so, + by adding provides to help the resolver understand the problem, but + sometimes it is needed to identify these to ignore them… */ +bool pkgCache::PrvIterator::IsMultiArchImplicit() const +{ + pkgCache::PkgIterator const Owner = OwnerPkg(); + pkgCache::PkgIterator const Parent = ParentPkg(); + if (strcmp(Owner.Arch(), Parent.Arch()) != 0 || Owner.Group()->Name == Parent.Group()->Name) + return true; + return false; +} + /*}}}*/ +APT_DEPRECATED APT_PURE const char * pkgCache::PkgIterator::Section() const {/*{{{*/ + if (S->VersionList == 0) + return 0; + return VersionList().Section(); +} + /*}}}*/