X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/6c55f07a5fa3612a5d59c61a17da5fe640eadc8b..d27daedb6a0bf672508072100f20233d08ccf0e0:/apt-pkg/pkgcachegen.cc?ds=sidebyside diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc index 0eba5795f..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,16 +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), - CurrentRlsFile(NULL), CurrentFile(NULL), FoundFileDeps(0), d(NULL) + CurrentRlsFile(NULL), CurrentFile(NULL), d(NULL) { - 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])); @@ -123,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; @@ -227,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); @@ -265,10 +251,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List, } if (OutVer != 0) - { - FoundFileDeps |= List.HasFileDeps(); return true; - } } if (Cache.HeaderP->PackageCount >= std::numeric_limits::max()) @@ -284,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 /*{{{*/ @@ -401,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); @@ -442,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)"), @@ -523,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); @@ -545,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 */ @@ -648,6 +545,16 @@ 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 { @@ -662,6 +569,61 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name } 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->NextPackage = LastPkg->NextPackage; @@ -669,16 +631,36 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name } Grp->LastPackage = 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++; - + // 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; } /*}}}*/ @@ -709,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); } } @@ -737,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; @@ -910,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(VERSIONNUMBER, 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(); @@ -950,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) @@ -974,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; } /*}}}*/ @@ -984,91 +991,167 @@ 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); + + 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; + } - /* 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; @@ -1193,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; } @@ -1217,18 +1306,19 @@ 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; } - SPtrArray RlsVisited = new bool[Cache.HeaderP->ReleaseFileCount]; - memset(RlsVisited,0,sizeof(*RlsVisited)*Cache.HeaderP->ReleaseFileCount); + 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) { @@ -1246,10 +1336,9 @@ static bool CheckValidity(const string &CacheFile, if (Debug == true) std::clog << "with ID " << RlsFile->ID << " is valid" << std::endl; - std::vector *Indexes = (*i)->GetIndexFiles(); - for (std::vector::const_iterator j = Indexes->begin(); j != Indexes->end(); ++j) - if ((*j)->HasPackages()) - Files.push_back (*j); + 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) @@ -1259,13 +1348,12 @@ static bool CheckValidity(const string &CacheFile, return false; } - for (; Start != End; ++Start) - Files.push_back(*Start); + 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.. */ - SPtrArray Visited = new bool[Cache.HeaderP->PackageFileCount]; - memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount); + 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) @@ -1304,14 +1392,13 @@ static bool CheckValidity(const string &CacheFile, 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; } /*}}}*/ @@ -1343,16 +1430,36 @@ static map_filesize_t ComputeSize(pkgSourceList const * const List, FileIterator } /*}}}*/ // 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, pkgSourceList const * const List, - FileIterator Start, FileIterator End) + FileIterator const Start, FileIterator const End) { - std::vector Files; - bool const HasFileDeps = Gen.HasFileDeps(); + bool mergeFailure = 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()); + return; + } + + map_filesize_t const Size = I->Size(); + if (Progress != NULL) + Progress->OverallProgress(CurrentSize, TotalSize, Size, _("Reading package lists")); + CurrentSize += Size; + + if (I->Merge(Gen,Progress) == false) + mergeFailure = true; + }; if (List != NULL) { @@ -1369,86 +1476,33 @@ static bool BuildCache(pkgCacheGenerator &Gen, return false; std::vector *Indexes = (*i)->GetIndexFiles(); - for (std::vector::const_iterator I = Indexes->begin(); I != Indexes->end(); ++I) - { - if (HasFileDeps) - Files.push_back(*I); - - if ((*I)->HasPackages() == false) - continue; - - if ((*I)->Exists() == false) - continue; - - if ((*I)->FindInCache(Gen.GetCache()).end() == false) - { - _error->Warning("Duplicate sources.list entry %s", - (*I)->Describe().c_str()); - continue; - } - - map_filesize_t Size = (*I)->Size(); - if (Progress != NULL) - Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists")); - CurrentSize += Size; - - if ((*I)->Merge(Gen,Progress) == false) - return false; - } + if (Indexes != NULL) + std::for_each(Indexes->begin(), Indexes->end(), indexFileMerge); + if (mergeFailure) + return false; } } - Gen.SelectReleaseFile("", ""); - FileIterator I; - for (I = Start; I != End; ++I) + if (Start != End) { - if (HasFileDeps) - Files.push_back(*I); - - if ((*I)->HasPackages() == false) - continue; - - if ((*I)->Exists() == false) - continue; - - if ((*I)->FindInCache(Gen.GetCache()).end() == false) - { - _error->Warning("Duplicate sources.list entry %s", - (*I)->Describe().c_str()); - continue; - } - - map_filesize_t Size = (*I)->Size(); - if (Progress != NULL) - Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists")); - CurrentSize += Size; - - if ((*I)->Merge(Gen,Progress) == false) + Gen.SelectReleaseFile("", ""); + std::for_each(Start, End, indexFileMerge); + if (mergeFailure) return false; - } - - if (HasFileDeps == true) - { - if (Progress != NULL) - Progress->Done(); - TotalSize = ComputeSize(List, Start, End); - CurrentSize = 0; - for (std::vector::const_iterator I = Files.begin(); I != Files.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) - 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); @@ -1460,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); - } -*/ if (_system->AddStatusFiles(Files) == false) return false; @@ -1510,167 +1587,132 @@ 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) - { - 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 + if (CheckValidity(SrcCacheFile, List, Files.end(), Files.end()) == true) { - _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.end(), - Files.end()) == 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(NULL, Files.begin(), 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, NULL, - Files.begin(),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(&List, 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, &List, - Files.end(),Files.end()) == 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, NULL, - Files.begin(), 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) { @@ -1678,16 +1720,18 @@ bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **O 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(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, NULL, @@ -1696,7 +1740,7 @@ bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **O if (_error->PendingError() == true) return false; - *OutMap = Map.UnGuard(); + *OutMap = Map.release(); return true; } @@ -1714,12 +1758,6 @@ static bool IsDuplicateDescription(pkgCache::DescIterator Desc, return false; } /*}}}*/ -// CacheGenerator::FinishCache /*{{{*/ -bool pkgCacheGenerator::FinishCache(OpProgress * /*Progress*/) -{ - return true; -} - /*}}}*/ -pkgCacheGenerator::ListParser::ListParser() : Owner(NULL), OldDepLast(NULL), FoundFileDeps(false), d(NULL) {} -pkgCacheGenerator::ListParser::~ListParser() {} +pkgCacheListParser::pkgCacheListParser() : Owner(NULL), OldDepLast(NULL), d(NULL) {} +pkgCacheListParser::~pkgCacheListParser() {}