X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/4c333a25a88b1afac2ed50bf1b9af61dc5b09343..d27daedb6a0bf672508072100f20233d08ccf0e0:/apt-pkg/pkgcachegen.cc diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc index 6bb246e9f..61f7a1124 100644 --- a/apt-pkg/pkgcachegen.cc +++ b/apt-pkg/pkgcachegen.cc @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include #include #include @@ -36,11 +34,14 @@ #include #include #include +#include +#include #include #include #include - /*}}}*/ + +template using Dynamic = pkgCacheGenerator::Dynamic; /*}}}*/ typedef std::vector::iterator FileIterator; template std::vector pkgCacheGenerator::Dynamic::toReMap; @@ -54,18 +55,17 @@ using std::string; /* 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) + CurrentRlsFile(NULL), CurrentFile(NULL), d(NULL) { - CurrentFile = 0; - - if (_error->PendingError() == true) - return; - if (Map.Size() == 0) { // Setup the map interface.. Cache.HeaderP = (pkgCache::Header *)Map.Data(); - if (Map.RawAllocate(sizeof(pkgCache::Header)) == 0 && _error->PendingError() == true) + _error->PushToStack(); + Map.RawAllocate(sizeof(pkgCache::Header)); + bool const newError = _error->PendingError(); + _error->MergeWithStack(); + if (newError) return; Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0])); @@ -74,7 +74,7 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) : *Cache.HeaderP = pkgCache::Header(); // make room for the hashtables for packages and groups - if (Map.RawAllocate(2 * (Cache.HeaderP->HashTableSize * sizeof(map_pointer_t))) == 0) + if (Map.RawAllocate(2 * (Cache.HeaderP->GetHashTableSize() * sizeof(map_pointer_t))) == 0) return; map_stringitem_t const idxVerSysName = WriteStringInMap(_system->VS->Label); @@ -96,10 +96,10 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) : map_stringitem_t const idxArchitectures = WriteStringInMap(list); if (unlikely(idxArchitectures == 0)) return; - Cache.HeaderP->Architectures = idxArchitectures; + Cache.HeaderP->SetArchitectures(idxArchitectures); } else - Cache.HeaderP->Architectures = idxArchitecture; + Cache.HeaderP->SetArchitectures(idxArchitecture); Cache.ReMap(); } @@ -125,7 +125,7 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) : advoid a problem during a crash */ pkgCacheGenerator::~pkgCacheGenerator() { - if (_error->PendingError() == true) + if (_error->PendingError() == true || Map.validData() == false) return; if (Map.Sync() == false) return; @@ -145,6 +145,7 @@ void pkgCacheGenerator::ReMap(void const * const oldMap, void const * const newM Cache.ReMap(false); CurrentFile += (pkgCache::PackageFile const * const) newMap - (pkgCache::PackageFile const * const) oldMap; + CurrentRlsFile += (pkgCache::ReleaseFile const * const) newMap - (pkgCache::ReleaseFile const * const) oldMap; for (std::vector::const_iterator i = Dynamic::toReMap.begin(); i != Dynamic::toReMap.end(); ++i) @@ -167,6 +168,9 @@ void pkgCacheGenerator::ReMap(void const * const oldMap, void const * const newM for (std::vector::const_iterator i = Dynamic::toReMap.begin(); i != Dynamic::toReMap.end(); ++i) (*i)->ReMap(oldMap, newMap); + for (std::vector::const_iterator i = Dynamic::toReMap.begin(); + i != Dynamic::toReMap.end(); ++i) + (*i)->ReMap(oldMap, newMap); } /*}}}*/ // CacheGenerator::WriteStringInMap /*{{{*/ map_stringitem_t pkgCacheGenerator::WriteStringInMap(const char *String, @@ -225,22 +229,6 @@ bool pkgCacheGenerator::MergeList(ListParser &List, continue; } - if (Arch.empty() == true) - { - // use the pseudo arch 'none' for arch-less packages - Arch = "none"; - /* We might built a SingleArchCache here, which we don't want to blow up - just for these :none packages to a proper MultiArchCache, so just ensure - that we have always a native package structure first for SingleArch */ - pkgCache::PkgIterator NP; - Dynamic DynPkg(NP); - if (NewPackage(NP, PackageName, _config->Find("APT::Architecture")) == false) - // TRANSLATOR: The first placeholder is a package name, - // the other two should be copied verbatim as they include debug info - return _error->Error(_("Error occurred while processing %s (%s%d)"), - PackageName.c_str(), "NewPackage", 0); - } - // Get a pointer to the package structure pkgCache::PkgIterator Pkg; Dynamic DynPkg(Pkg); @@ -263,10 +251,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List, } if (OutVer != 0) - { - FoundFileDeps |= List.HasFileDeps(); return true; - } } if (Cache.HeaderP->PackageCount >= std::numeric_limits::max()) @@ -282,7 +267,6 @@ bool pkgCacheGenerator::MergeList(ListParser &List, return _error->Error(_("Wow, you exceeded the number of dependencies " "this APT is capable of.")); - FoundFileDeps |= List.HasFileDeps(); return true; } // CacheGenerator::MergeListGroup /*{{{*/ @@ -399,7 +383,7 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator // Add a new version map_pointer_t const verindex = NewVersion(Ver, Version, Pkg.Index(), Hash, *LastVer); - if (verindex == 0 && _error->PendingError()) + if (unlikely(verindex == 0)) return _error->Error(_("Error occurred while processing %s (%s%d)"), Pkg.Name(), "NewVersion", 1); @@ -440,40 +424,6 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator return _error->Error(_("Error occurred while processing %s (%s%d)"), Pkg.Name(), "AddImplicitDepends", 1); } - /* :none packages are packages without an architecture. They are forbidden by - debian-policy, so usually they will only be in (old) dpkg status files - - and dpkg will complain about them - and are pretty rare. We therefore do - usually not create conflicts while the parent is created, but only if a :none - package (= the target) appears. This creates incorrect dependencies on :none - for architecture-specific dependencies on the package we copy from, but we - will ignore this bug as architecture-specific dependencies are only allowed - in jessie and until then the :none packages should be extinct (hopefully). - In other words: This should work long enough to allow graceful removal of - these packages, it is not supposed to allow users to keep using them … */ - if (strcmp(Pkg.Arch(), "none") == 0) - { - pkgCache::PkgIterator M = Grp.FindPreferredPkg(); - if (M.end() == false && Pkg != M) - { - pkgCache::DepIterator D = M.RevDependsList(); - Dynamic DynD(D); - for (; D.end() == false; ++D) - { - if ((D->Type != pkgCache::Dep::Conflicts && - D->Type != pkgCache::Dep::DpkgBreaks && - D->Type != pkgCache::Dep::Replaces) || - D.ParentPkg().Group() == Grp) - continue; - - map_pointer_t *OldDepLast = NULL; - pkgCache::VerIterator ConVersion = D.ParentVer(); - Dynamic DynV(ConVersion); - // duplicate the Conflicts/Breaks/Replaces for :none arch - NewDepends(Pkg, ConVersion, D->Version, - D->CompareOp, D->Type, OldDepLast); - } - } - } } if (unlikely(AddImplicitDepends(Grp, Pkg, Ver) == false)) return _error->Error(_("Error occurred while processing %s (%s%d)"), @@ -521,7 +471,7 @@ bool pkgCacheGenerator::AddNewDescription(ListParser &List, pkgCache::VerIterato Dynamic DynDesc(Desc); map_pointer_t const descindex = NewDescription(Desc, lang, CurMd5, md5idx); - if (unlikely(descindex == 0 && _error->PendingError())) + if (unlikely(descindex == 0)) return _error->Error(_("Error occurred while processing %s (%s%d)"), Ver.ParentPkg().Name(), "NewDescription", 1); @@ -543,57 +493,6 @@ bool pkgCacheGenerator::AddNewDescription(ListParser &List, pkgCache::VerIterato } /*}}}*/ /*}}}*/ -// CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/ -// --------------------------------------------------------------------- -/* If we found any file depends while parsing the main list we need to - resolve them. Since it is undesired to load the entire list of files - into the cache as virtual packages we do a two stage effort. MergeList - identifies the file depends and this creates Provdies for them by - re-parsing all the indexs. */ -bool pkgCacheGenerator::MergeFileProvides(ListParser &List) -{ - List.Owner = this; - - unsigned int Counter = 0; - while (List.Step() == true) - { - string PackageName = List.Package(); - if (PackageName.empty() == true) - return false; - string Version = List.Version(); - if (Version.empty() == true) - continue; - - pkgCache::PkgIterator Pkg = Cache.FindPkg(PackageName); - Dynamic DynPkg(Pkg); - if (Pkg.end() == true) - return _error->Error(_("Error occurred while processing %s (%s%d)"), - PackageName.c_str(), "FindPkg", 1); - Counter++; - if (Counter % 100 == 0 && Progress != 0) - Progress->Progress(List.Offset()); - - unsigned short Hash = List.VersionHash(); - pkgCache::VerIterator Ver = Pkg.VersionList(); - Dynamic DynVer(Ver); - for (; Ver.end() == false; ++Ver) - { - if (List.SameVersion(Hash, Ver) == true && Version == Ver.VerStr()) - { - if (List.CollectFileProvides(Cache,Ver) == false) - return _error->Error(_("Error occurred while processing %s (%s%d)"), - PackageName.c_str(), "CollectFileProvides", 1); - break; - } - } - - if (Ver.end() == true) - _error->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName.c_str(),Version.c_str()); - } - - return true; -} - /*}}}*/ // CacheGenerator::NewGroup - Add a new group /*{{{*/ // --------------------------------------------------------------------- /* This creates a new group structure and adds it to the hash table */ @@ -616,7 +515,7 @@ bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name) // Insert it into the hash table unsigned long const Hash = Cache.Hash(Name); - map_pointer_t *insertAt = &Cache.HeaderP->GrpHashTable()[Hash]; + map_pointer_t *insertAt = &Cache.HeaderP->GrpHashTableP()[Hash]; while (*insertAt != 0 && strcasecmp(Name.c_str(), Cache.StrP + (Cache.GrpP + *insertAt)->Name) > 0) insertAt = &(Cache.GrpP + *insertAt)->Next; Grp->Next = *insertAt; @@ -646,44 +545,122 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name return false; Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package); + // Set the name, arch and the ID + APT_IGNORE_DEPRECATED(Pkg->Name = Grp->Name;) + Pkg->Group = Grp.Index(); + // all is mapped to the native architecture + map_stringitem_t const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : StoreString(MIXED, Arch); + if (unlikely(idxArch == 0)) + return false; + Pkg->Arch = idxArch; + Pkg->ID = Cache.HeaderP->PackageCount++; + // Insert the package into our package list if (Grp->FirstPackage == 0) // the group is new { Grp->FirstPackage = Package; // Insert it into the hash table map_id_t const Hash = Cache.Hash(Name); - map_pointer_t *insertAt = &Cache.HeaderP->PkgHashTable()[Hash]; + map_pointer_t *insertAt = &Cache.HeaderP->PkgHashTableP()[Hash]; while (*insertAt != 0 && strcasecmp(Name.c_str(), Cache.StrP + (Cache.GrpP + (Cache.PkgP + *insertAt)->Group)->Name) > 0) - insertAt = &(Cache.PkgP + *insertAt)->Next; - Pkg->Next = *insertAt; + insertAt = &(Cache.PkgP + *insertAt)->NextPackage; + Pkg->NextPackage = *insertAt; *insertAt = Package; } else // Group the Packages together { + // but first get implicit provides done + if (APT::Configuration::checkArchitecture(Pkg.Arch()) == true) + { + pkgCache::PkgIterator const M = Grp.FindPreferredPkg(false); // native or any foreign pkg will do + if (M.end() == false) { + pkgCache::PrvIterator Prv; + Dynamic DynPrv(Prv); + for (Prv = M.ProvidesList(); Prv.end() == false; ++Prv) + { + if ((Prv->Flags & pkgCache::Flag::ArchSpecific) != 0) + continue; + pkgCache::VerIterator Ver = Prv.OwnerVer(); + Dynamic DynVer(Ver); + if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed || + ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign && + (Prv->Flags & pkgCache::Flag::MultiArchImplicit) == 0)) + if (NewProvides(Ver, Pkg, Prv->ProvideVersion, Prv->Flags) == false) + return false; + } + } + + + pkgCache::PkgIterator P; + pkgCache::VerIterator Ver; + Dynamic DynP(P); + Dynamic DynVer(Ver); + + for (P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P)) + for (Ver = P.VersionList(); Ver.end() == false; ++Ver) + if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) + if (NewProvides(Ver, Pkg, Ver->VerStr, pkgCache::Flag::MultiArchImplicit) == false) + return false; + } + // and negative dependencies, don't forget negative dependencies + { + pkgCache::PkgIterator const M = Grp.FindPreferredPkg(false); + if (M.end() == false) { + pkgCache::DepIterator Dep; + Dynamic DynDep(Dep); + for (Dep = M.RevDependsList(); Dep.end() == false; ++Dep) + { + if ((Dep->CompareOp & (pkgCache::Dep::ArchSpecific | pkgCache::Dep::MultiArchImplicit)) != 0) + continue; + if (Dep->Type != pkgCache::Dep::DpkgBreaks && Dep->Type != pkgCache::Dep::Conflicts && + Dep->Type != pkgCache::Dep::Replaces) + continue; + pkgCache::VerIterator Ver = Dep.ParentVer(); + Dynamic DynVer(Ver); + map_pointer_t * unused = NULL; + if (NewDepends(Pkg, Ver, Dep->Version, Dep->CompareOp, Dep->Type, unused) == false) + return false; + } + } + } + // this package is the new last package pkgCache::PkgIterator LastPkg(Cache, Cache.PkgP + Grp->LastPackage); - Pkg->Next = LastPkg->Next; - LastPkg->Next = Package; + Pkg->NextPackage = LastPkg->NextPackage; + LastPkg->NextPackage = Package; } Grp->LastPackage = Package; - // Set the name, arch and the ID -#if __GNUC__ >= 4 - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - Pkg->Name = Grp->Name; -#if __GNUC__ >= 4 - #pragma GCC diagnostic pop -#endif - Pkg->Group = Grp.Index(); - // all is mapped to the native architecture - map_stringitem_t const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : StoreString(MIXED, Arch); - if (unlikely(idxArch == 0)) - return false; - Pkg->Arch = idxArch; - Pkg->ID = Cache.HeaderP->PackageCount++; - + // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it + if (Arch == "any") + { + size_t const found = Name.find(':'); + std::string const NameA = Name.substr(0, found); + std::string const ArchA = Name.substr(found + 1); + pkgCache::PkgIterator PkgA = Cache.FindPkg(NameA, ArchA); + if (PkgA.end() == false) + { + Dynamic DynPkgA(PkgA); + pkgCache::PrvIterator Prv = PkgA.ProvidesList(); + for (; Prv.end() == false; ++Prv) + { + if (Prv.IsMultiArchImplicit()) + continue; + pkgCache::VerIterator V = Prv.OwnerVer(); + if (ArchA != V.ParentPkg().Arch()) + continue; + if (NewProvides(V, Pkg, V->VerStr, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false) + return false; + } + pkgCache::VerIterator V = PkgA.VersionList(); + Dynamic DynV(V); + for (; V.end() == false; ++V) + { + if (NewProvides(V, Pkg, V->VerStr, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false) + return false; + } + } + } return true; } /*}}}*/ @@ -714,16 +691,16 @@ bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator &G, { // Replaces: ${self}:other ( << ${binary:Version}) NewDepends(D, V, VerStrIdx, - pkgCache::Dep::Less, pkgCache::Dep::Replaces, + pkgCache::Dep::Less | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::Replaces, OldDepLast); // Breaks: ${self}:other (!= ${binary:Version}) NewDepends(D, V, VerStrIdx, - pkgCache::Dep::NotEquals, pkgCache::Dep::DpkgBreaks, + pkgCache::Dep::NotEquals | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::DpkgBreaks, OldDepLast); } else { // Conflicts: ${self}:other NewDepends(D, V, 0, - pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts, + pkgCache::Dep::NoOp | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::Conflicts, OldDepLast); } } @@ -742,16 +719,16 @@ bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator &V, map_stringitem_t const VerStrIdx = V->VerStr; // Replaces: ${self}:other ( << ${binary:Version}) NewDepends(D, V, VerStrIdx, - pkgCache::Dep::Less, pkgCache::Dep::Replaces, + pkgCache::Dep::Less | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::Replaces, OldDepLast); // Breaks: ${self}:other (!= ${binary:Version}) NewDepends(D, V, VerStrIdx, - pkgCache::Dep::NotEquals, pkgCache::Dep::DpkgBreaks, + pkgCache::Dep::NotEquals | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::DpkgBreaks, OldDepLast); } else { // Conflicts: ${self}:other NewDepends(D, V, 0, - pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts, + pkgCache::Dep::NoOp | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::Conflicts, OldDepLast); } return true; @@ -836,7 +813,7 @@ map_pointer_t pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver, } } // haven't found the version string, so create - map_stringitem_t const idxVerStr = StoreString(VERSION, VerStr); + map_stringitem_t const idxVerStr = StoreString(VERSIONNUMBER, VerStr); if (unlikely(idxVerStr == 0)) return 0; Ver->VerStr = idxVerStr; @@ -915,38 +892,11 @@ map_pointer_t pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc, // --------------------------------------------------------------------- /* 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::NewDepends(pkgCache::PkgIterator &Pkg, - pkgCache::VerIterator &Ver, - string const &Version, - unsigned int const &Op, - unsigned int const &Type, - map_stringitem_t* &OldDepLast) -{ - map_stringitem_t index = 0; - if (Version.empty() == false) - { - int const CmpOp = Op & 0x0F; - // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages) - if (CmpOp == pkgCache::Dep::Equals && strcmp(Version.c_str(), Ver.VerStr()) == 0) - index = Ver->VerStr; - - if (index == 0) - { - void const * const oldMap = Map.Data(); - index = StoreString(VERSION, Version); - if (unlikely(index == 0)) - return false; - if (OldDepLast != 0 && oldMap != Map.Data()) - OldDepLast += (map_pointer_t const * const) Map.Data() - (map_pointer_t const * const) oldMap; - } - } - return NewDepends(Pkg, Ver, index, Op, Type, OldDepLast); -} bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver, map_pointer_t const Version, - unsigned int const &Op, - unsigned int const &Type, + uint8_t const Op, + uint8_t const Type, map_pointer_t* &OldDepLast) { void const * const oldMap = Map.Data(); @@ -955,19 +905,72 @@ bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg, if (unlikely(Dependency == 0)) return false; - // Fill it in - pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency); - Dynamic DynDep(Dep); - Dep->ParentVer = Ver.Index(); - Dep->Type = Type; - Dep->CompareOp = Op; - Dep->Version = Version; - Dep->ID = Cache.HeaderP->DependsCount++; + bool isDuplicate = false; + map_pointer_t DependencyData = 0; + map_pointer_t PreviousData = 0; + if (Pkg->RevDepends != 0) + { + pkgCache::Dependency const * const L = Cache.DepP + Pkg->RevDepends; + DependencyData = L->DependencyData; + do { + pkgCache::DependencyData const * const D = Cache.DepDataP + DependencyData; + if (Version > D->Version) + break; + if (D->Version == Version && D->Type == Type && D->CompareOp == Op) + { + isDuplicate = true; + break; + } + PreviousData = DependencyData; + DependencyData = D->NextData; + } while (DependencyData != 0); + } + + if (isDuplicate == false) + { + DependencyData = AllocateInMap(sizeof(pkgCache::DependencyData)); + if (unlikely(DependencyData == 0)) + return false; + } + + pkgCache::Dependency * Link = Cache.DepP + Dependency; + Link->ParentVer = Ver.Index(); + Link->DependencyData = DependencyData; + Link->ID = Cache.HeaderP->DependsCount++; + + pkgCache::DepIterator Dep(Cache, Link); + if (isDuplicate == false) + { + Dep->Type = Type; + Dep->CompareOp = Op; + Dep->Version = Version; + Dep->Package = Pkg.Index(); + ++Cache.HeaderP->DependsDataCount; + if (PreviousData != 0) + { + pkgCache::DependencyData * const D = Cache.DepDataP + PreviousData; + Dep->NextData = D->NextData; + D->NextData = DependencyData; + } + else if (Pkg->RevDepends != 0) + { + pkgCache::Dependency const * const D = Cache.DepP + Pkg->RevDepends; + Dep->NextData = D->DependencyData; + } + } + + if (isDuplicate == true || PreviousData != 0) + { + pkgCache::Dependency * const L = Cache.DepP + Pkg->RevDepends; + Link->NextRevDepends = L->NextRevDepends; + L->NextRevDepends = Dependency; + } + else + { + Link->NextRevDepends = Pkg->RevDepends; + Pkg->RevDepends = Dependency; + } - // Link it to the package - Dep->Package = Pkg.Index(); - Dep->NextRevDepends = Pkg->RevDepends; - Pkg->RevDepends = Dep.Index(); // Do we know where to link the Dependency to? if (OldDepLast == NULL) @@ -979,9 +982,8 @@ bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg, OldDepLast += (map_pointer_t const * const) Map.Data() - (map_pointer_t const * const) oldMap; Dep->NextDepends = *OldDepLast; - *OldDepLast = Dep.Index(); + *OldDepLast = Dependency; OldDepLast = &Dep->NextDepends; - return true; } /*}}}*/ @@ -989,103 +991,214 @@ bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg, // --------------------------------------------------------------------- /* 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, +bool pkgCacheListParser::NewDepends(pkgCache::VerIterator &Ver, const string &PackageName, const string &Arch, const string &Version, - unsigned int Op, - unsigned int Type) + uint8_t const Op, + uint8_t const Type) { pkgCache::GrpIterator Grp; Dynamic DynGrp(Grp); if (unlikely(Owner->NewGroup(Grp, PackageName) == false)) return false; - // Locate the target package - pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch); - // we don't create 'none' packages and their dependencies if we can avoid it … - if (Pkg.end() == true && Arch == "none" && strcmp(Ver.ParentPkg().Arch(), "none") != 0) - return true; - Dynamic DynPkg(Pkg); - if (Pkg.end() == true) { - if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false)) - return false; + map_stringitem_t idxVersion = 0; + if (Version.empty() == false) + { + int const CmpOp = Op & 0x0F; + // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages) + if (CmpOp == pkgCache::Dep::Equals && strcmp(Version.c_str(), Ver.VerStr()) == 0) + idxVersion = Ver->VerStr; + + if (idxVersion == 0) + { + idxVersion = StoreString(pkgCacheGenerator::VERSIONNUMBER, Version); + if (unlikely(idxVersion == 0)) + return false; + } } - // Is it a file dependency? - if (unlikely(PackageName[0] == '/')) - FoundFileDeps = true; + bool const isNegative = (Type == pkgCache::Dep::DpkgBreaks || + Type == pkgCache::Dep::Conflicts || + Type == pkgCache::Dep::Replaces); - /* Caching the old end point speeds up generation substantially */ - if (OldDepVer != Ver) { - OldDepLast = NULL; - OldDepVer = Ver; + pkgCache::PkgIterator Pkg; + Dynamic DynPkg(Pkg); + if (isNegative == false || (Op & pkgCache::Dep::ArchSpecific) == pkgCache::Dep::ArchSpecific || Grp->FirstPackage == 0) + { + // Locate the target package + Pkg = Grp.FindPkg(Arch); + if (Pkg.end() == true) { + if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false)) + return false; + } + + /* Caching the old end point speeds up generation substantially */ + if (OldDepVer != Ver) { + OldDepLast = NULL; + OldDepVer = Ver; + } + + return Owner->NewDepends(Pkg, Ver, idxVersion, Op, Type, OldDepLast); } + else + { + /* 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); + for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg)) + { + if (Owner->NewDepends(Pkg, Ver, idxVersion, Op, Type, OldDepLast) == false) + return false; + } + } + return true; } /*}}}*/ // ListParser::NewProvides - Create a Provides element /*{{{*/ -// --------------------------------------------------------------------- -/* */ -bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver, - const string &PkgName, +bool pkgCacheListParser::NewProvides(pkgCache::VerIterator &Ver, + const string &PkgName, const string &PkgArch, - const string &Version) + const string &Version, + uint8_t const Flags) { - pkgCache &Cache = Owner->Cache; + pkgCache const &Cache = Owner->Cache; // We do not add self referencing provides if (Ver.ParentPkg().Name() == PkgName && (PkgArch == Ver.ParentPkg().Arch() || - (PkgArch == "all" && strcmp((Cache.StrP + Cache.HeaderP->Architecture), Ver.ParentPkg().Arch()) == 0))) + (PkgArch == "all" && strcmp((Cache.StrP + Cache.HeaderP->Architecture), Ver.ParentPkg().Arch()) == 0)) && + (Version.empty() || Version == Ver.VerStr())) return true; - + + // Locate the target package + pkgCache::PkgIterator Pkg; + Dynamic DynPkg(Pkg); + if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false)) + return false; + + map_stringitem_t idxProvideVersion = 0; + if (Version.empty() == false) { + idxProvideVersion = StoreString(pkgCacheGenerator::VERSIONNUMBER, Version); + if (unlikely(idxProvideVersion == 0)) + return false; + } + return Owner->NewProvides(Ver, Pkg, idxProvideVersion, Flags); +} +bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator &Ver, + pkgCache::PkgIterator &Pkg, + map_pointer_t const ProvideVersion, + uint8_t const Flags) +{ // Get a structure - map_pointer_t const Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides)); + map_pointer_t const Provides = AllocateInMap(sizeof(pkgCache::Provides)); if (unlikely(Provides == 0)) return false; - Cache.HeaderP->ProvidesCount++; - + ++Cache.HeaderP->ProvidesCount; + // Fill it in pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP); - Dynamic DynPrv(Prv); Prv->Version = Ver.Index(); + Prv->ProvideVersion = ProvideVersion; + Prv->Flags = Flags; Prv->NextPkgProv = Ver->ProvidesList; Ver->ProvidesList = Prv.Index(); - if (Version.empty() == false) { - map_stringitem_t const idxProvideVersion = WriteString(Version); - Prv->ProvideVersion = idxProvideVersion; - if (unlikely(idxProvideVersion == 0)) - return false; - } - - // Locate the target package - pkgCache::PkgIterator Pkg; - Dynamic DynPkg(Pkg); - if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false)) - return false; - + // Link it to the package Prv->ParentPkg = Pkg.Index(); Prv->NextProvides = Pkg->ProvidesList; Pkg->ProvidesList = Prv.Index(); - return true; } /*}}}*/ -bool pkgCacheGenerator::ListParser::SameVersion(unsigned short const Hash,/*{{{*/ +// ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/ +bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package, + string const &Version, uint8_t const Flags) { + pkgCache &Cache = Owner->Cache; + pkgCache::GrpIterator Grp = Cache.FindGrp(Package); + Dynamic DynGrp(Grp); + + if (Grp.end() == true) + return NewProvides(Ver, Package, Cache.NativeArch(), Version, Flags); + else + { + map_stringitem_t idxProvideVersion = 0; + if (Version.empty() == false) { + idxProvideVersion = StoreString(pkgCacheGenerator::VERSIONNUMBER, Version); + if (unlikely(idxProvideVersion == 0)) + return false; + } + + bool const isImplicit = (Flags & pkgCache::Flag::MultiArchImplicit) == pkgCache::Flag::MultiArchImplicit; + bool const isArchSpecific = (Flags & pkgCache::Flag::ArchSpecific) == pkgCache::Flag::ArchSpecific; + pkgCache::PkgIterator OwnerPkg = Ver.ParentPkg(); + Dynamic DynOwnerPkg(OwnerPkg); + pkgCache::PkgIterator Pkg; + Dynamic DynPkg(Pkg); + for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg)) + { + if (isImplicit && OwnerPkg == Pkg) + continue; + if (isArchSpecific == false && APT::Configuration::checkArchitecture(OwnerPkg.Arch()) == false) + continue; + if (Owner->NewProvides(Ver, Pkg, idxProvideVersion, Flags) == false) + return false; + } + } + return true; +} + /*}}}*/ +bool pkgCacheListParser::SameVersion(unsigned short const Hash, /*{{{*/ pkgCache::VerIterator const &Ver) { return Hash == Ver->Hash; } /*}}}*/ +// CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/ +bool pkgCacheGenerator::SelectReleaseFile(const string &File,const string &Site, + unsigned long Flags) +{ + if (File.empty() && Site.empty()) + { + CurrentRlsFile = NULL; + return true; + } + + // Get some space for the structure + map_pointer_t const idxFile = AllocateInMap(sizeof(*CurrentRlsFile)); + if (unlikely(idxFile == 0)) + return false; + CurrentRlsFile = Cache.RlsFileP + idxFile; + + // Fill it in + map_stringitem_t const idxFileName = WriteStringInMap(File); + map_stringitem_t const idxSite = StoreString(MIXED, Site); + if (unlikely(idxFileName == 0 || idxSite == 0)) + return false; + CurrentRlsFile->FileName = idxFileName; + CurrentRlsFile->Site = idxSite; + CurrentRlsFile->NextFile = Cache.HeaderP->RlsFileList; + CurrentRlsFile->Flags = Flags; + CurrentRlsFile->ID = Cache.HeaderP->ReleaseFileCount; + RlsFileName = File; + Cache.HeaderP->RlsFileList = CurrentRlsFile - Cache.RlsFileP; + Cache.HeaderP->ReleaseFileCount++; + + return true; +} + /*}}}*/ // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/ // --------------------------------------------------------------------- /* This is used to select which file is to be associated with all newly added versions. The caller is responsible for setting the IMS fields. */ -bool pkgCacheGenerator::SelectFile(const string &File,const string &Site, - const pkgIndexFile &Index, - unsigned long Flags) +bool pkgCacheGenerator::SelectFile(std::string const &File, + pkgIndexFile const &Index, + std::string const &Architecture, + std::string const &Component, + unsigned long const Flags) { // Get some space for the structure map_pointer_t const idxFile = AllocateInMap(sizeof(*CurrentFile)); @@ -1095,18 +1208,33 @@ bool pkgCacheGenerator::SelectFile(const string &File,const string &Site, // Fill it in map_stringitem_t const idxFileName = WriteStringInMap(File); - map_stringitem_t const idxSite = StoreString(MIXED, Site); - if (unlikely(idxFileName == 0 || idxSite == 0)) + if (unlikely(idxFileName == 0)) return false; CurrentFile->FileName = idxFileName; - CurrentFile->Site = idxSite; CurrentFile->NextFile = Cache.HeaderP->FileList; - CurrentFile->Flags = Flags; CurrentFile->ID = Cache.HeaderP->PackageFileCount; map_stringitem_t const idxIndexType = StoreString(MIXED, Index.GetType()->Label); if (unlikely(idxIndexType == 0)) return false; CurrentFile->IndexType = idxIndexType; + if (Architecture.empty()) + CurrentFile->Architecture = 0; + else + { + map_stringitem_t const arch = StoreString(pkgCacheGenerator::MIXED, Architecture); + if (unlikely(arch == 0)) + return false; + CurrentFile->Architecture = arch; + } + map_stringitem_t const component = StoreString(pkgCacheGenerator::MIXED, Component); + if (unlikely(component == 0)) + return false; + CurrentFile->Component = component; + CurrentFile->Flags = Flags; + if (CurrentRlsFile != NULL) + CurrentFile->Release = CurrentRlsFile - Cache.RlsFileP; + else + CurrentFile->Release = 0; PkgFileName = File; Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP; Cache.HeaderP->PackageFileCount++; @@ -1129,7 +1257,7 @@ map_stringitem_t pkgCacheGenerator::StoreString(enum StringType const type, cons switch(type) { case MIXED: strings = &strMixed; break; case PKGNAME: strings = &strPkgNames; break; - case VERSION: strings = &strVersions; break; + case VERSIONNUMBER: strings = &strVersions; break; case SECTION: strings = &strSections; break; default: _error->Fatal("Unknown enum type used for string storage of '%s'", key.c_str()); return 0; } @@ -1148,18 +1276,24 @@ map_stringitem_t pkgCacheGenerator::StoreString(enum StringType const type, cons /* This just verifies that each file in the list of index files exists, has matching attributes with the cache and the cache does not have any extra files. */ -static bool CheckValidity(const string &CacheFile, +class APT_HIDDEN ScopedErrorRevert { +public: + ScopedErrorRevert() { _error->PushToStack(); } + ~ScopedErrorRevert() { _error->RevertToStack(); } +}; +static bool CheckValidity(const string &CacheFile, pkgSourceList &List, - FileIterator Start, - FileIterator End, + FileIterator const Start, + FileIterator const End, MMap **OutMap = 0) { + ScopedErrorRevert ser; bool const Debug = _config->FindB("Debug::pkgCacheGen", false); // No file, certainly invalid if (CacheFile.empty() == true || FileExists(CacheFile) == false) { if (Debug == true) - std::clog << "CacheFile doesn't exist" << std::endl; + std::clog << "CacheFile " << CacheFile << " doesn't exist" << std::endl; return false; } @@ -1172,44 +1306,67 @@ static bool CheckValidity(const string &CacheFile, // Map it FileFd CacheF(CacheFile,FileFd::ReadOnly); - SPtr Map = new MMap(CacheF,0); - pkgCache Cache(Map); - if (_error->PendingError() == true || Map->Size() == 0) + std::unique_ptr Map(new MMap(CacheF,0)); + if (unlikely(Map->validData()) == false) + return false; + pkgCache Cache(Map.get()); + if (_error->PendingError() || Map->Size() == 0) { if (Debug == true) - std::clog << "Errors are pending or Map is empty()" << std::endl; - _error->Discard(); + std::clog << "Errors are pending or Map is empty() for " << CacheFile << std::endl; return false; } - - /* Now we check every index file, see if it is in the cache, - verify the IMS data and check that it is on the disk too.. */ - SPtrArray Visited = new bool[Cache.HeaderP->PackageFileCount]; - memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount); - for (; Start != End; ++Start) + + std::unique_ptr RlsVisited(new bool[Cache.HeaderP->ReleaseFileCount]); + memset(RlsVisited.get(),0,sizeof(RlsVisited[0])*Cache.HeaderP->ReleaseFileCount); + std::vector Files; + for (pkgSourceList::const_iterator i = List.begin(); i != List.end(); ++i) { if (Debug == true) - std::clog << "Checking PkgFile " << (*Start)->Describe() << ": "; - if ((*Start)->HasPackages() == false) + std::clog << "Checking RlsFile " << (*i)->Describe() << ": "; + pkgCache::RlsFileIterator const RlsFile = (*i)->FindInCache(Cache, true); + if (RlsFile.end() == true) { - if (Debug == true) - std::clog << "Has NO packages" << std::endl; - continue; + if (Debug == true) + std::clog << "FindInCache returned end-Pointer" << std::endl; + return false; + } + + RlsVisited[RlsFile->ID] = true; + if (Debug == true) + std::clog << "with ID " << RlsFile->ID << " is valid" << std::endl; + + std::vector const * const Indexes = (*i)->GetIndexFiles(); + std::copy_if(Indexes->begin(), Indexes->end(), std::back_inserter(Files), + [](pkgIndexFile const * const I) { return I->HasPackages(); }); + } + for (unsigned I = 0; I != Cache.HeaderP->ReleaseFileCount; ++I) + if (RlsVisited[I] == false) + { + if (Debug == true) + std::clog << "RlsFile with ID" << I << " wasn't visited" << std::endl; + return false; } - - if ((*Start)->Exists() == false) + + std::copy(Start, End, std::back_inserter(Files)); + + /* Now we check every index file, see if it is in the cache, + verify the IMS data and check that it is on the disk too.. */ + std::unique_ptr Visited(new bool[Cache.HeaderP->PackageFileCount]); + memset(Visited.get(),0,sizeof(Visited[0])*Cache.HeaderP->PackageFileCount); + for (std::vector::const_reverse_iterator PkgFile = Files.rbegin(); PkgFile != Files.rend(); ++PkgFile) + { + if (Debug == true) + std::clog << "Checking PkgFile " << (*PkgFile)->Describe() << ": "; + if ((*PkgFile)->Exists() == false) { -#if 0 // mvo: we no longer give a message here (Default Sources spec) - _error->WarningE("stat",_("Couldn't stat source package list %s"), - (*Start)->Describe().c_str()); -#endif if (Debug == true) std::clog << "file doesn't exist" << std::endl; continue; } // FindInCache is also expected to do an IMS check. - pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache); + pkgCache::PkgFileIterator File = (*PkgFile)->FindInCache(Cache); if (File.end() == true) { if (Debug == true) @@ -1221,28 +1378,27 @@ static bool CheckValidity(const string &CacheFile, if (Debug == true) std::clog << "with ID " << File->ID << " is valid" << std::endl; } - + for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++) if (Visited[I] == false) { if (Debug == true) - std::clog << "File with ID" << I << " wasn't visited" << std::endl; + std::clog << "PkgFile with ID" << I << " wasn't visited" << std::endl; return false; } - + if (_error->PendingError() == true) { if (Debug == true) { std::clog << "Validity failed because of pending errors:" << std::endl; - _error->DumpErrors(); + _error->DumpErrors(std::clog, GlobalError::DEBUG, false); } - _error->Discard(); return false; } - + if (OutMap != 0) - *OutMap = Map.UnGuard(); + *OutMap = Map.release(); return true; } /*}}}*/ @@ -1250,9 +1406,20 @@ static bool CheckValidity(const string &CacheFile, // --------------------------------------------------------------------- /* Size is kind of an abstract notion that is only used for the progress meter */ -static map_filesize_t ComputeSize(FileIterator Start,FileIterator End) +static map_filesize_t ComputeSize(pkgSourceList const * const List, FileIterator Start,FileIterator End) { map_filesize_t TotalSize = 0; + if (List != NULL) + { + for (pkgSourceList::const_iterator i = List->begin(); i != List->end(); ++i) + { + std::vector *Indexes = (*i)->GetIndexFiles(); + for (std::vector::const_iterator j = Indexes->begin(); j != Indexes->end(); ++j) + if ((*j)->HasPackages() == true) + TotalSize += (*j)->Size(); + } + } + for (; Start < End; ++Start) { if ((*Start)->HasPackages() == false) @@ -1263,60 +1430,79 @@ static map_filesize_t ComputeSize(FileIterator Start,FileIterator End) } /*}}}*/ // BuildCache - Merge the list of index files into the cache /*{{{*/ -// --------------------------------------------------------------------- -/* */ static bool BuildCache(pkgCacheGenerator &Gen, - OpProgress *Progress, + OpProgress * const Progress, map_filesize_t &CurrentSize,map_filesize_t TotalSize, - FileIterator Start, FileIterator End) + pkgSourceList const * const List, + FileIterator const Start, FileIterator const End) { - FileIterator I; - for (I = Start; I != End; ++I) - { - if ((*I)->HasPackages() == false) - continue; - - if ((*I)->Exists() == false) - continue; + bool mergeFailure = false; - if ((*I)->FindInCache(Gen.GetCache()).end() == false) + auto const indexFileMerge = [&](pkgIndexFile * const I) { + if (I->HasPackages() == false || mergeFailure) + return; + + if (I->Exists() == false) + return; + + if (I->FindInCache(Gen.GetCache()).end() == false) { _error->Warning("Duplicate sources.list entry %s", - (*I)->Describe().c_str()); - continue; + I->Describe().c_str()); + return; } - - map_filesize_t Size = (*I)->Size(); + + map_filesize_t const Size = I->Size(); if (Progress != NULL) - Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists")); + Progress->OverallProgress(CurrentSize, TotalSize, Size, _("Reading package lists")); CurrentSize += Size; - - if ((*I)->Merge(Gen,Progress) == false) - return false; - } - if (Gen.HasFileDeps() == true) + if (I->Merge(Gen,Progress) == false) + mergeFailure = true; + }; + + if (List != NULL) { - if (Progress != NULL) - Progress->Done(); - TotalSize = ComputeSize(Start, End); - CurrentSize = 0; - for (I = Start; I != End; ++I) + for (pkgSourceList::const_iterator i = List->begin(); i != List->end(); ++i) { - map_filesize_t Size = (*I)->Size(); - if (Progress != NULL) - Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Collecting File Provides")); - CurrentSize += Size; - if ((*I)->MergeFileProvides(Gen,Progress) == false) + if ((*i)->FindInCache(Gen.GetCache(), false).end() == false) + { + _error->Warning("Duplicate sources.list entry %s", + (*i)->Describe().c_str()); + continue; + } + + if ((*i)->Merge(Gen, Progress) == false) + return false; + + std::vector *Indexes = (*i)->GetIndexFiles(); + if (Indexes != NULL) + std::for_each(Indexes->begin(), Indexes->end(), indexFileMerge); + if (mergeFailure) return false; } } - + + if (Start != End) + { + Gen.SelectReleaseFile("", ""); + std::for_each(Start, End, indexFileMerge); + if (mergeFailure) + return false; + } return true; } /*}}}*/ -// CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/ -DynamicMMap* pkgCacheGenerator::CreateDynamicMMap(FileFd *CacheF, unsigned long Flags) { +// CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/ +// --------------------------------------------------------------------- +/* This makes sure that the status cache (the cache that has all + index files from the sources list and all local ones) is ready + to be mmaped. If OutMap is not zero then a MMap object representing + the cache will be stored there. This is pretty much mandetory if you + are using AllowMem. AllowMem lets the function be run as non-root + where it builds the cache 'fast' into a memory buffer. */ +static DynamicMMap* CreateDynamicMMap(FileFd * const CacheF, unsigned long Flags) +{ map_filesize_t const MapStart = _config->FindI("APT::Cache-Start", 24*1024*1024); map_filesize_t const MapGrow = _config->FindI("APT::Cache-Grow", 1*1024*1024); map_filesize_t const MapLimit = _config->FindI("APT::Cache-Limit", 0); @@ -1328,36 +1514,59 @@ DynamicMMap* pkgCacheGenerator::CreateDynamicMMap(FileFd *CacheF, unsigned long else return new DynamicMMap(Flags, MapStart, MapGrow, MapLimit); } - /*}}}*/ -// CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/ -// --------------------------------------------------------------------- -/* This makes sure that the status cache (the cache that has all - index files from the sources list and all local ones) is ready - to be mmaped. If OutMap is not zero then a MMap object representing - the cache will be stored there. This is pretty much mandetory if you - are using AllowMem. AllowMem lets the function be run as non-root - where it builds the cache 'fast' into a memory buffer. */ -APT_DEPRECATED bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress, +static bool writeBackMMapToFile(pkgCacheGenerator * const Gen, DynamicMMap * const Map, + std::string const &FileName) +{ + FileFd SCacheF(FileName, FileFd::WriteAtomic); + if (SCacheF.IsOpen() == false || SCacheF.Failed()) + return false; + + fchmod(SCacheF.Fd(),0644); + + // Write out the main data + if (SCacheF.Write(Map->Data(),Map->Size()) == false) + return _error->Error(_("IO Error saving source cache")); + SCacheF.Sync(); + + // Write out the proper header + Gen->GetCache().HeaderP->Dirty = false; + if (SCacheF.Seek(0) == false || + SCacheF.Write(Map->Data(),sizeof(*Gen->GetCache().HeaderP)) == false) + return _error->Error(_("IO Error saving source cache")); + Gen->GetCache().HeaderP->Dirty = true; + SCacheF.Sync(); + return true; +} +static bool loadBackMMapFromFile(std::unique_ptr &Gen, + std::unique_ptr &Map, OpProgress * const Progress, std::string const &FileName) +{ + Map.reset(CreateDynamicMMap(NULL, 0)); + if (unlikely(Map->validData()) == false) + return false; + FileFd CacheF(FileName, FileFd::ReadOnly); + if (CacheF.IsOpen() == false || CacheF.Failed()) + return false; + _error->PushToStack(); + map_pointer_t const alloc = Map->RawAllocate(CacheF.Size()); + bool const newError = _error->PendingError(); + _error->MergeWithStack(); + if (alloc == 0 && newError) + return false; + if (CacheF.Read((unsigned char *)Map->Data() + alloc, CacheF.Size()) == false) + return false; + Gen.reset(new pkgCacheGenerator(Map.get(),Progress)); + return true; +} +bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress, MMap **OutMap, bool AllowMem) { return pkgCacheGenerator::MakeStatusCache(List, &Progress, OutMap, AllowMem); } bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress, - MMap **OutMap,bool AllowMem) + MMap **OutMap,bool) { + // FIXME: deprecate the ignored AllowMem parameter bool const Debug = _config->FindB("Debug::pkgCacheGen", false); std::vector Files; - for (std::vector::const_iterator i = List.begin(); - i != List.end(); - ++i) - { - std::vector *Indexes = (*i)->GetIndexFiles(); - for (std::vector::const_iterator j = Indexes->begin(); - j != Indexes->end(); - ++j) - Files.push_back (*j); - } - - map_filesize_t const EndOfSource = Files.size(); if (_system->AddStatusFiles(Files) == false) return false; @@ -1378,194 +1587,160 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress CreateDirectory(dir, flNotFile(SrcCacheFile)); } - // Decide if we can write to the cache - bool Writeable = false; - if (CacheFile.empty() == false) - Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0; - else - if (SrcCacheFile.empty() == false) - Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0; - if (Debug == true) - std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl; - - if (Writeable == false && AllowMem == false && CacheFile.empty() == false) - return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str()); - if (Progress != NULL) Progress->OverallProgress(0,1,1,_("Reading package lists")); - // Cache is OK, Fin. - if (CheckValidity(CacheFile, List, Files.begin(),Files.end(),OutMap) == true) + bool pkgcache_fine = false; + bool srcpkgcache_fine = false; + bool volatile_fine = List.GetVolatileFiles().empty(); + + if (CheckValidity(CacheFile, List, Files.begin(), Files.end(), volatile_fine ? OutMap : NULL) == true) { - if (Progress != NULL) - Progress->OverallProgress(1,1,1,_("Reading package lists")); if (Debug == true) - std::clog << "pkgcache.bin is valid - no need to build anything" << std::endl; - return true; + std::clog << "pkgcache.bin is valid - no need to build any cache" << std::endl; + pkgcache_fine = true; + srcpkgcache_fine = true; } - else if (Debug == true) - std::clog << "pkgcache.bin is NOT valid" << std::endl; - - /* At this point we know we need to reconstruct the package cache, - begin. */ - SPtr CacheF; - SPtr Map; - if (Writeable == true && CacheFile.empty() == false) + if (pkgcache_fine == false) { - _error->PushToStack(); - unlink(CacheFile.c_str()); - CacheF = new FileFd(CacheFile,FileFd::WriteAtomic); - fchmod(CacheF->Fd(),0644); - Map = CreateDynamicMMap(CacheF, MMap::Public); - if (_error->PendingError() == true) + if (CheckValidity(SrcCacheFile, List, Files.end(), Files.end()) == true) { - delete CacheF.UnGuard(); - delete Map.UnGuard(); if (Debug == true) - std::clog << "Open filebased MMap FAILED" << std::endl; - Writeable = false; - if (AllowMem == false) - { - _error->MergeWithStack(); - return false; - } - _error->RevertToStack(); - } - else - { - _error->MergeWithStack(); - if (Debug == true) - std::clog << "Open filebased MMap" << std::endl; + std::clog << "srcpkgcache.bin is valid - it can be reused" << std::endl; + srcpkgcache_fine = true; } } - if (Writeable == false || CacheFile.empty() == true) + + if (volatile_fine == true && srcpkgcache_fine == true && pkgcache_fine == true) { - // Just build it in memory.. - Map = CreateDynamicMMap(NULL); - if (Debug == true) - std::clog << "Open memory Map (not filebased)" << std::endl; + if (Progress != NULL) + Progress->OverallProgress(1,1,1,_("Reading package lists")); + return true; } - - // Lets try the source cache. - map_filesize_t CurrentSize = 0; - map_filesize_t TotalSize = 0; - if (CheckValidity(SrcCacheFile, List, Files.begin(), - Files.begin()+EndOfSource) == true) + + bool Writeable = false; + if (srcpkgcache_fine == false || pkgcache_fine == false) { + if (CacheFile.empty() == false) + Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0; + else if (SrcCacheFile.empty() == false) + Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0; + if (Debug == true) - std::clog << "srcpkgcache.bin is valid - populate MMap with it." << std::endl; - // Preload the map with the source cache - FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly); - map_pointer_t const alloc = Map->RawAllocate(SCacheF.Size()); - if ((alloc == 0 && _error->PendingError()) - || SCacheF.Read((unsigned char *)Map->Data() + alloc, - SCacheF.Size()) == false) - return false; + std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl; + } - TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end()); + // At this point we know we need to construct something, so get storage ready + std::unique_ptr Map(CreateDynamicMMap(NULL, 0)); + if (unlikely(Map->validData()) == false) + return false; + if (Debug == true) + std::clog << "Open memory Map (not filebased)" << std::endl; - // Build the status cache - pkgCacheGenerator Gen(Map.Get(),Progress); - if (_error->PendingError() == true) - return false; - if (BuildCache(Gen,Progress,CurrentSize,TotalSize, - Files.begin()+EndOfSource,Files.end()) == false) + std::unique_ptr Gen{nullptr}; + map_filesize_t CurrentSize = 0; + std::vector VolatileFiles = List.GetVolatileFiles(); + map_filesize_t TotalSize = ComputeSize(NULL, VolatileFiles.begin(), VolatileFiles.end()); + if (srcpkgcache_fine == true && pkgcache_fine == false) + { + if (Debug == true) + std::clog << "srcpkgcache.bin was valid - populate MMap with it" << std::endl; + if (loadBackMMapFromFile(Gen, Map, Progress, SrcCacheFile) == false) return false; + srcpkgcache_fine = true; + TotalSize += ComputeSize(NULL, Files.begin(), Files.end()); } - else + else if (srcpkgcache_fine == false) { if (Debug == true) std::clog << "srcpkgcache.bin is NOT valid - rebuild" << std::endl; - TotalSize = ComputeSize(Files.begin(),Files.end()); - - // Build the source cache - pkgCacheGenerator Gen(Map.Get(),Progress); - if (_error->PendingError() == true) - return false; - if (BuildCache(Gen,Progress,CurrentSize,TotalSize, - Files.begin(),Files.begin()+EndOfSource) == false) + Gen.reset(new pkgCacheGenerator(Map.get(),Progress)); + + TotalSize += ComputeSize(&List, Files.begin(),Files.end()); + if (BuildCache(*Gen, Progress, CurrentSize, TotalSize, &List, + Files.end(),Files.end()) == false) return false; - - // Write it back + if (Writeable == true && SrcCacheFile.empty() == false) - { - FileFd SCacheF(SrcCacheFile,FileFd::WriteAtomic); - if (_error->PendingError() == true) + if (writeBackMMapToFile(Gen.get(), Map.get(), SrcCacheFile) == false) return false; - - fchmod(SCacheF.Fd(),0644); - - // Write out the main data - if (SCacheF.Write(Map->Data(),Map->Size()) == false) - return _error->Error(_("IO Error saving source cache")); - SCacheF.Sync(); - - // Write out the proper header - Gen.GetCache().HeaderP->Dirty = false; - if (SCacheF.Seek(0) == false || - SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false) - return _error->Error(_("IO Error saving source cache")); - Gen.GetCache().HeaderP->Dirty = true; - SCacheF.Sync(); - } - - // Build the status cache - if (BuildCache(Gen,Progress,CurrentSize,TotalSize, - Files.begin()+EndOfSource,Files.end()) == false) + } + + if (pkgcache_fine == false) + { + if (Debug == true) + std::clog << "Building status cache in pkgcache.bin now" << std::endl; + if (BuildCache(*Gen, Progress, CurrentSize, TotalSize, NULL, + Files.begin(), Files.end()) == false) return false; + + if (Writeable == true && CacheFile.empty() == false) + if (writeBackMMapToFile(Gen.get(), Map.get(), CacheFile) == false) + return false; } + if (Debug == true) - std::clog << "Caches are ready for shipping" << std::endl; + std::clog << "Caches done. Now bring in the volatile files (if any)" << std::endl; - if (_error->PendingError() == true) - return false; - if (OutMap != 0) + if (volatile_fine == false) { - if (CacheF != 0) + if (Gen == nullptr) { - delete Map.UnGuard(); - *OutMap = new MMap(*CacheF,0); + if (Debug == true) + std::clog << "Populate new MMap with cachefile contents" << std::endl; + if (loadBackMMapFromFile(Gen, Map, Progress, CacheFile) == false) + return false; } - else - { - *OutMap = Map.UnGuard(); - } + + Files = List.GetVolatileFiles(); + if (BuildCache(*Gen, Progress, CurrentSize, TotalSize, NULL, + Files.begin(), Files.end()) == false) + return false; } - + + if (OutMap != nullptr) + *OutMap = Map.release(); + + if (Debug == true) + std::clog << "Everything is ready for shipping" << std::endl; return true; } /*}}}*/ // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/ -// --------------------------------------------------------------------- -/* */ -APT_DEPRECATED bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap) +class APT_HIDDEN ScopedErrorMerge { +public: + ScopedErrorMerge() { _error->PushToStack(); } + ~ScopedErrorMerge() { _error->MergeWithStack(); } +}; +bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap) { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress, OutMap); } bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap) { std::vector Files; - map_filesize_t EndOfSource = Files.size(); if (_system->AddStatusFiles(Files) == false) return false; - SPtr Map = CreateDynamicMMap(NULL); + ScopedErrorMerge sem; + std::unique_ptr Map(CreateDynamicMMap(NULL, 0)); + if (unlikely(Map->validData()) == false) + return false; map_filesize_t CurrentSize = 0; map_filesize_t TotalSize = 0; - - TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end()); - + TotalSize = ComputeSize(NULL, Files.begin(), Files.end()); + // Build the status cache if (Progress != NULL) Progress->OverallProgress(0,1,1,_("Reading package lists")); - pkgCacheGenerator Gen(Map.Get(),Progress); + pkgCacheGenerator Gen(Map.get(),Progress); if (_error->PendingError() == true) return false; - if (BuildCache(Gen,Progress,CurrentSize,TotalSize, - Files.begin()+EndOfSource,Files.end()) == false) + if (BuildCache(Gen,Progress,CurrentSize,TotalSize, NULL, + Files.begin(), Files.end()) == false) return false; if (_error->PendingError() == true) return false; - *OutMap = Map.UnGuard(); + *OutMap = Map.release(); return true; } @@ -1583,9 +1758,6 @@ static bool IsDuplicateDescription(pkgCache::DescIterator Desc, return false; } /*}}}*/ -// CacheGenerator::FinishCache /*{{{*/ -bool pkgCacheGenerator::FinishCache(OpProgress * /*Progress*/) -{ - return true; -} - /*}}}*/ + +pkgCacheListParser::pkgCacheListParser() : Owner(NULL), OldDepLast(NULL), d(NULL) {} +pkgCacheListParser::~pkgCacheListParser() {}