X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/4dc77823d360158d6870a5710cc8c17064f1308f..29636cc759c6fbb92c6c462c90611eefb67cbbd4:/apt-pkg/pkgcache.cc diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index 2348cca2d..83cb6149e 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -34,15 +34,18 @@ #include #include -#include +#include +#include #include #include #include +#include #include /*}}}*/ using std::string; +using APT::StringView; // Cache::Header::Header - Constructor /*{{{*/ @@ -50,27 +53,29 @@ using std::string; /* Simply initialize the header */ pkgCache::Header::Header() { - Signature = 0x98FE76DC; - +#define APT_HEADER_SET(X,Y) X = Y; static_assert(std::numeric_limits::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 = 10; - MinorVersion = 0; - Dirty = false; - - HeaderSz = sizeof(pkgCache::Header); - GroupSz = sizeof(pkgCache::Group); - PackageSz = sizeof(pkgCache::Package); - ReleaseFileSz = sizeof(pkgCache::ReleaseFile); - PackageFileSz = sizeof(pkgCache::PackageFile); - VersionSz = sizeof(pkgCache::Version); - DescriptionSz = sizeof(pkgCache::Description); - DependencySz = sizeof(pkgCache::Dependency); - DependencyDataSz = sizeof(pkgCache::DependencyData); - ProvidesSz = sizeof(pkgCache::Provides); - VerFileSz = sizeof(pkgCache::VerFile); - DescFileSz = sizeof(pkgCache::DescFile); - + APT_HEADER_SET(MajorVersion, 10); + APT_HEADER_SET(MinorVersion, 5); + 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; @@ -84,13 +89,13 @@ pkgCache::Header::Header() ProvidesCount = 0; MaxVerFileSize = 0; MaxDescFileSize = 0; - + FileList = 0; RlsFileList = 0; VerSysName = 0; Architecture = 0; SetArchitectures(0); - SetHashTableSize(_config->FindI("APT::Cache-HashTableSize", 10 * 1048)); + SetHashTableSize(_config->FindI("APT::Cache-HashTableSize", 50503)); memset(Pools,0,sizeof(Pools)); CacheFileSize = 0; @@ -122,7 +127,7 @@ bool pkgCache::Header::CheckSizes(Header &Against) const // --------------------------------------------------------------------- /* */ APT_IGNORE_DEPRECATED_PUSH -pkgCache::pkgCache(MMap *Map, bool DoMap) : Map(*Map), d(NULL) +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 @@ -170,9 +175,6 @@ bool pkgCache::ReMap(bool const &Errorchecks) HeaderP->CheckSizes(DefHeader) == false) return _error->Error(_("The package cache file is an incompatible version")); - 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")); @@ -182,14 +184,23 @@ bool pkgCache::ReMap(bool const &Errorchecks) // 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); + 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; } /*}}}*/ @@ -198,53 +209,69 @@ 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) */ +map_id_t pkgCache::sHash(StringView Str) const +{ + 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 { - unsigned long Hash = 0; + uint32_t Hash = 5381; for (string::const_iterator I = Str.begin(); I != Str.end(); ++I) - Hash = 41 * Hash + tolower_ascii(*I); + Hash = 33 * Hash + tolower_ascii((signed char)*I); return Hash % HeaderP->GetHashTableSize(); } map_id_t pkgCache::sHash(const char *Str) const { - unsigned long Hash = tolower_ascii(*Str); - for (const char *I = Str + 1; *I != 0; ++I) - Hash = 41 * Hash + tolower_ascii(*I); + 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->PkgHashTableP()[Hash(Name)]; - for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage) - { - int const cmp = strcmp(Name.c_str(), StrP + (GrpP + Pkg->Group)->Name); - if (cmp == 0) - return PkgIterator(*this, Pkg); - else if (cmp < 0) - break; + 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(&header), + sizeof(header)); + + if (Map.Size() > sizeof(header)) { + adler = adler32(adler, + static_cast(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) { - 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); - /* Beware: This is specialcased to handle pkg:any in dependencies as - these are linked to virtual pkg:any named packages with all archs. - If you want any arch from a given pkg, use FindPkg(pkg,arch) */ + 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); @@ -254,6 +281,10 @@ 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) { + 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) */ @@ -268,13 +299,17 @@ pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string const &Arch) // --------------------------------------------------------------------- /* 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->GrpHashTableP()[sHash(Name)]; for (; Grp != GrpP; Grp = GrpP + Grp->Next) { - int const cmp = strcmp(Name.c_str(), StrP + Grp->Name); + int const cmp = Name.compare(ViewString(Grp->Name)); if (cmp == 0) return GrpIterator(*this, Grp); else if (cmp < 0) @@ -326,7 +361,7 @@ const char *pkgCache::DepType(unsigned char 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]; @@ -337,29 +372,26 @@ const char *pkgCache::Priority(unsigned char 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); - - char const* const myArch = Owner->NativeArch(); - /* 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") { - pkgCache::Package *Pkg = Owner->PkgP + S->LastPackage; - if (strcmp(myArch, Owner->StrP + Pkg->Arch) == 0) - return PkgIterator(*Owner, Pkg); - Arch = myArch; - } + if (Arch == "native" || Arch == "all") + Arch = Owner->NativeArch(); // Iterate over the list to find the matching arch for (pkgCache::Package *Pkg = PackageList(); Pkg != Owner->PkgP; Pkg = Owner->PkgP + Pkg->NextPackage) { - if (stringcmp(Arch, Owner->StrP + Pkg->Arch) == 0) + if (Arch == Owner->ViewString(Pkg->Arch)) return PkgIterator(*Owner, Pkg); if ((Owner->PkgP + S->LastPackage) == Pkg) break; @@ -372,7 +404,7 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) const { // --------------------------------------------------------------------- /* 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; @@ -384,7 +416,7 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPreferredPkg(bool const &Prefer return Pkg; } // packages without an architecture - Pkg = FindPkg("none"); + Pkg = FindPkg(StringView("none", 4)); if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0)) return Pkg; @@ -468,7 +500,7 @@ pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const 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 @@ -543,7 +575,7 @@ std::string pkgCache::PkgIterator::FullName(bool const &Pretty) const { string fullname = Name(); if (Pretty == false || - (strcmp(Arch(), "all") != 0 && + (strcmp(Arch(), "all") != 0 && strcmp(Arch(), "any") != 0 && strcmp(Owner->NativeArch(), Arch()) != 0)) return fullname.append(":").append(Arch()); return fullname; @@ -725,21 +757,7 @@ bool pkgCache::DepIterator::IsIgnorable(PkgIterator const &PT) const // 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 (S2->Type == pkgCache::Dep::Replaces) - { - if (S2->CompareOp == pkgCache::Dep::Less && strcmp(PV.VerStr(), TargetVer()) == 0) - return false; - } - // Breaks: ${self}:other (!= ${binary:Version}) - else if (S2->Type == pkgCache::Dep::DpkgBreaks) - { - if (S2->CompareOp == pkgCache::Dep::NotEquals && strcmp(PV.VerStr(), TargetVer()) == 0) - return false; - } - return true; - } + return IsMultiArchImplicit() == false; return false; } @@ -754,27 +772,12 @@ bool pkgCache::DepIterator::IsIgnorable(PrvIterator const &Prv) const 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) + if (IsMultiArchImplicit() && 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 && - (S2->Type == pkgCache::Dep::Replaces || - S2->Type == pkgCache::Dep::DpkgBreaks || - S2->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 { @@ -785,7 +788,21 @@ bool pkgCache::DepIterator::IsSatisfied(PrvIterator const &Prv) const return Owner->VS->CheckDep(Prv.ProvideVersion(),S2->CompareOp,TargetVer()); } /*}}}*/ -// ostream operator to handle string representation of a dependecy /*{{{*/ +// 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<<(std::ostream& out, pkgCache::DepIterator D) @@ -879,10 +896,32 @@ pkgCache::VerFileIterator pkgCache::VerIterator::NewestFile() const // --------------------------------------------------------------------- /* 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; + std::vector RelStrs; for (pkgCache::VerFileIterator I = this->FileList(); I.end() == false; ++I) { // Do not print 'not source' entries' @@ -890,58 +929,21 @@ string pkgCache::VerIterator::RelStr() const 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 const 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(os, ", ")); + os << *RelStrs.rbegin(); } if (S->ParentPkg != 0) - Res.append(" [").append(Arch()).append("]"); - return Res; + os << " [" << Arch() << "]"; + return os.str(); } /*}}}*/ // VerIterator::MultiArchType - string representing MultiArch flag /*{{{*/ @@ -1065,19 +1067,5 @@ pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const } /*}}}*/ -// 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; -} - /*}}}*/ pkgCache::~pkgCache() {}