#include <vector>
#include <string>
#include <sys/stat.h>
+#include <zlib.h>
#include <apti18n.h>
/*}}}*/
using std::string;
+using APT::StringView;
// Cache::Header::Header - Constructor /*{{{*/
/* Whenever the structures change the major version should be bumped,
whenever the generator changes the minor version should be bumped. */
- APT_HEADER_SET(MajorVersion, 10);
+ APT_HEADER_SET(MajorVersion, 11);
APT_HEADER_SET(MinorVersion, 0);
APT_HEADER_SET(Dirty, false);
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;
// ---------------------------------------------------------------------
/* */
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
VerP = (Version *)Map.Data();
DescP = (Description *)Map.Data();
ProvideP = (Provides *)Map.Data();
+ TagP = (Tag *)Map.Data();
DepP = (Dependency *)Map.Data();
DepDataP = (DependencyData *)Map.Data();
StrP = (char *)Map.Data();
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"));
// Check the architecture
std::vector<std::string> archs = APT::Configuration::getArchitectures();
- std::vector<std::string>::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;
}
/*}}}*/
/* 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_unsafe(*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_unsafe((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_unsafe((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<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) {
- 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);
// ---------------------------------------------------------------------
/* 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) */
// ---------------------------------------------------------------------
/* 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 = StringViewCompareFast(Name, ViewString(Grp->Name));
if (cmp == 0)
return GrpIterator(*this, Grp);
else if (cmp < 0)
/* */
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);
-
- 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;
// ---------------------------------------------------------------------
/* 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;
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;
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 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;
{
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;
return false;
}
/*}}}*/
-// ostream operator to handle string representation of a dependecy /*{{{*/
+// ostream operator to handle string representation of a dependency /*{{{*/
// ---------------------------------------------------------------------
/* */
std::ostream& operator<<(std::ostream& out, pkgCache::DepIterator D)
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() << ")";