X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/c67dc114eafe034b8223ce3df6474f7c25f150a8..8d3489abd90a64715b92976a7c60b42a386a4c5c:/apt-pkg/depcache.cc diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 75f69ee11..bc663a8e9 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -165,7 +165,7 @@ bool pkgDepCache::Init(OpProgress *Prog) bool pkgDepCache::readStateFile(OpProgress *Prog) /*{{{*/ { FileFd state_file; - string const state = _config->FindDir("Dir::State") + "extended_states"; + string const state = _config->FindFile("Dir::State::extended_states"); if(FileExists(state)) { state_file.Open(state, FileFd::ReadOnly); int const file_size = state_file.Size(); @@ -192,7 +192,7 @@ bool pkgDepCache::readStateFile(OpProgress *Prog) /*{{{*/ { PkgState[pkg->ID].Flags |= Flag::Auto; if (unlikely(debug_autoremove)) - std::cout << "Auto-Installed : " << pkg.FullName() << std::endl; + std::clog << "Auto-Installed : " << pkg.FullName() << std::endl; if (pkgarch == "any") { pkgCache::GrpIterator G = pkg.Group(); @@ -222,7 +222,7 @@ bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/ std::clog << "pkgDepCache::writeStateFile()" << std::endl; FileFd StateFile; - string const state = _config->FindDir("Dir::State") + "extended_states"; + string const state = _config->FindFile("Dir::State::extended_states"); // if it does not exist, create a empty one if(!FileExists(state)) @@ -338,7 +338,7 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) /* Check simple depends. A depends -should- never self match but we allow it anyhow because dpkg does. Technically it is a packaging bug. Conflicts may never self match */ - if (Dep.TargetPkg() != Dep.ParentPkg() || + if (Dep.TargetPkg()->Group != Dep.ParentPkg()->Group || (Dep->Type != Dep::Conflicts && Dep->Type != Dep::DpkgBreaks && Dep->Type != Dep::Obsoletes)) { PkgIterator Pkg = Dep.TargetPkg(); @@ -367,9 +367,9 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) PkgIterator Pkg = Dep.ParentPkg(); for (; P.end() != true; P++) { - /* Provides may never be applied against the same package if it is - a conflicts. See the comment above. */ - if (P.OwnerPkg() == Pkg && + /* Provides may never be applied against the same package (or group) + if it is a conflicts. See the comment above. */ + if (P.OwnerPkg()->Group == Pkg->Group && (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks)) continue; @@ -407,8 +407,11 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res) /*}}}*/ // DepCache::AddSizes - Add the packages sizes to the counters /*{{{*/ // --------------------------------------------------------------------- -/* Call with Mult = -1 to preform the inverse opration */ -void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult) +/* Call with Mult = -1 to preform the inverse opration + The Mult increases the complexity of the calulations here and is unused - + or do we really have a usecase for removing the size of a package two + times? So let us replace it with a simple bool and be done with it… */ +__deprecated void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult) { StateCache &P = PkgState[Pkg->ID]; @@ -422,8 +425,8 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult) // Compute the size data if (P.NewInstall() == true) { - iUsrSize += (signed)(Mult*P.InstVerIter(*this)->InstalledSize); - iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size); + iUsrSize += (signed long long)(Mult*P.InstVerIter(*this)->InstalledSize); + iDownloadSize += (signed long long)(Mult*P.InstVerIter(*this)->Size); return; } @@ -432,9 +435,9 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult) (P.InstallVer != (Version *)Pkg.CurrentVer() || (P.iFlags & ReInstall) == ReInstall) && P.InstallVer != 0) { - iUsrSize += (signed)(Mult*((signed)P.InstVerIter(*this)->InstalledSize - - (signed)Pkg.CurrentVer()->InstalledSize)); - iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size); + iUsrSize += (signed long long)(Mult*((signed long long)P.InstVerIter(*this)->InstalledSize - + (signed long long)Pkg.CurrentVer()->InstalledSize)); + iDownloadSize += (signed long long)(Mult*P.InstVerIter(*this)->Size); return; } @@ -442,14 +445,80 @@ void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult) if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack && P.Delete() == false) { - iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size); + iDownloadSize += (signed long long)(Mult*P.InstVerIter(*this)->Size); return; } // Removing if (Pkg->CurrentVer != 0 && P.InstallVer == 0) { - iUsrSize -= (signed)(Mult*Pkg.CurrentVer()->InstalledSize); + iUsrSize -= (signed long long)(Mult*Pkg.CurrentVer()->InstalledSize); + return; + } +} + /*}}}*/ +// DepCache::AddSizes - Add the packages sizes to the counters /*{{{*/ +// --------------------------------------------------------------------- +/* Call with Inverse = true to preform the inverse opration */ +void pkgDepCache::AddSizes(const PkgIterator &Pkg, bool const &Inverse) +{ + StateCache &P = PkgState[Pkg->ID]; + + if (Pkg->VersionList == 0) + return; + + if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure && + P.Keep() == true) + return; + + // Compute the size data + if (P.NewInstall() == true) + { + if (Inverse == false) { + iUsrSize += P.InstVerIter(*this)->InstalledSize; + iDownloadSize += P.InstVerIter(*this)->Size; + } else { + iUsrSize -= P.InstVerIter(*this)->InstalledSize; + iDownloadSize -= P.InstVerIter(*this)->Size; + } + return; + } + + // Upgrading + if (Pkg->CurrentVer != 0 && + (P.InstallVer != (Version *)Pkg.CurrentVer() || + (P.iFlags & ReInstall) == ReInstall) && P.InstallVer != 0) + { + if (Inverse == false) { + iUsrSize -= Pkg.CurrentVer()->InstalledSize; + iUsrSize += P.InstVerIter(*this)->InstalledSize; + iDownloadSize += P.InstVerIter(*this)->Size; + } else { + iUsrSize -= P.InstVerIter(*this)->InstalledSize; + iUsrSize += Pkg.CurrentVer()->InstalledSize; + iDownloadSize -= P.InstVerIter(*this)->Size; + } + return; + } + + // Reinstall + if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack && + P.Delete() == false) + { + if (Inverse == false) + iDownloadSize += P.InstVerIter(*this)->Size; + else + iDownloadSize -= P.InstVerIter(*this)->Size; + return; + } + + // Removing + if (Pkg->CurrentVer != 0 && P.InstallVer == 0) + { + if (Inverse == false) + iUsrSize -= Pkg.CurrentVer()->InstalledSize; + else + iUsrSize += Pkg.CurrentVer()->InstalledSize; return; } } @@ -804,17 +873,18 @@ void pkgDepCache::Update(OpProgress *Prog) /* FIXME: recheck breaks proper progress reporting as we don't know how many packages we need to recheck. To lower the effect a bit we increase with a kill, but we should do something more clever… */ - for(std::set::const_iterator p = recheck.begin(); - p != recheck.end(); ++p) { - if (Prog != 0 && Done%20 == 0) - Prog->Progress(Done); - PkgIterator P = PkgIterator(*Cache, Cache->PkgP + *p); - if (RemovePseudoInstalledPkg(P, recheck) == true) { - ++killed; - ++Done; + while(recheck.empty() == false) + for (std::set::const_iterator p = recheck.begin(); + p != recheck.end();) { + if (Prog != 0 && Done%20 == 0) + Prog->Progress(Done); + PkgIterator P = PkgIterator(*Cache, Cache->PkgP + *p); + if (RemovePseudoInstalledPkg(P, recheck) == true) { + ++killed; + ++Done; + } + recheck.erase(p++); } - recheck.erase(p); - } /* Okay, we have killed a great amount of pseudopackages - we have killed so many that we have now arch "all" packages @@ -841,42 +911,15 @@ void pkgDepCache::Update(OpProgress *Prog) if (installed == false) recheck.insert(G.Index()); } - std::vector Archs = APT::Configuration::getArchitectures(); - bool checkChanged = false; - do { - for(std::set::const_iterator g = recheck.begin(); - g != recheck.end(); ++g) { - GrpIterator G = GrpIterator(*Cache, Cache->GrpP + *g); - VerIterator allV = G.FindPkg("all").CurrentVer(); - for (std::vector::const_iterator a = Archs.begin(); - a != Archs.end(); ++a) - { - PkgIterator P = G.FindPkg(*a); - if (P.end() == true) continue; - for (VerIterator V = P.VersionList(); V.end() != true; ++V) - { - // FIXME: String comparison isn't a save indicator! - if (strcmp(allV.VerStr(),V.VerStr()) != 0) - continue; - unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy); - if ((CurDepState & DepInstMin) != DepInstMin) - break; // we found the correct version, but it is broken. Better try another arch or later again - P->CurrentVer = V.Index(); - AddStates(P); - Update(P); - AddSizes(P); - checkChanged = true; - break; - } - } - recheck.erase(g); - } - } while (checkChanged == true && recheck.empty() == false); - if (_config->FindB("Debug::MultiArchKiller", false) == true) - for(std::set::const_iterator g = recheck.begin(); - g != recheck.end(); ++g) - std::cout << "No pseudo package for »" << GrpIterator(*Cache, Cache->GrpP + *g).Name() << "« installed" << std::endl; + while (recheck.empty() != true) + { + std::set::const_iterator g = recheck.begin(); + unsigned long const G = *g; + recheck.erase(g); + if (unlikely(ReInstallPseudoForGroup(G, recheck) == false)) + _error->Warning(_("Internal error, group '%s' has no installable pseudo package"), GrpIterator(*Cache, Cache->GrpP + G).Name()); + } } if (Prog != 0) @@ -885,6 +928,80 @@ void pkgDepCache::Update(OpProgress *Prog) readStateFile(Prog); } /*}}}*/ +// DepCache::ReInstallPseudoForGroup - MultiArch helper for Update() /*{{{*/ +// --------------------------------------------------------------------- +/* RemovePseudoInstalledPkg() is very successful. It even kills packages + to an amount that no pseudo package is left, but we need a pseudo package + for upgrading senarios so we need to reinstall one pseudopackage which + doesn't break everything. Thankfully we can't have architecture depending + negative dependencies so this problem is already eliminated */ +bool pkgDepCache::ReInstallPseudoForGroup(pkgCache::PkgIterator const &P, std::set &recheck) +{ + if (P->CurrentVer != 0) + return true; + // recursive call for packages which provide this package + for (pkgCache::PrvIterator Prv = P.ProvidesList(); Prv.end() != true; ++Prv) + ReInstallPseudoForGroup(Prv.OwnerPkg(), recheck); + // check if we actually need to look at this group + unsigned long const G = P->Group; + std::set::const_iterator Pi = recheck.find(G); + if (Pi == recheck.end()) + return true; + recheck.erase(Pi); // remove here, so we can't fall into an endless loop + if (unlikely(ReInstallPseudoForGroup(G, recheck) == false)) + { + recheck.insert(G); + return false; + } + return true; +} +bool pkgDepCache::ReInstallPseudoForGroup(unsigned long const &G, std::set &recheck) +{ + std::vector static const Archs = APT::Configuration::getArchitectures(); + pkgCache::GrpIterator Grp(*Cache, Cache->GrpP + G); + if (unlikely(Grp.end() == true)) + return false; + for (std::vector::const_iterator a = Archs.begin(); + a != Archs.end(); ++a) + { + pkgCache::PkgIterator P = Grp.FindPkg(*a); + if (P.end() == true) + continue; + pkgCache::VerIterator allV = Grp.FindPkg("all").CurrentVer(); + for (VerIterator V = P.VersionList(); V.end() != true; ++V) + { + // search for the same version as the all package + if (allV->Hash != V->Hash || strcmp(allV.VerStr(),V.VerStr()) != 0) + continue; + unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy); + // If it is broken, try to install dependencies first before retry + if ((CurDepState & DepInstMin) != DepInstMin) + { + for (pkgCache::DepIterator D = V.DependsList(); D.end() != true; ++D) + { + if (D->Type != pkgCache::Dep::PreDepends && D->Type != pkgCache::Dep::Depends) + continue; + ReInstallPseudoForGroup(D.TargetPkg(), recheck); + } + unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy); + // if package ist still broken… try another arch + if ((CurDepState & DepInstMin) != DepInstMin) + break; + } + // dependencies satisfied: reinstall the package + RemoveSizes(P); + RemoveStates(P); + P->CurrentVer = V.Index(); + PkgState[P->ID].InstallVer = V; + AddStates(P); + Update(P); + AddSizes(P); + return true; + } + } + return false; +} + /*}}}*/ // DepCache::Update - Update the deps list of a package /*{{{*/ // --------------------------------------------------------------------- /* This is a helper for update that only does the dep portion of the scan. @@ -1138,6 +1255,10 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, Update(Pkg); AddSizes(Pkg); + // always trigger the install of the all package for a pseudo package + if (P.CandidateVerIter(*Cache).Pseudo() == true) + MarkInstall(Pkg.Group().FindPkg("all"), AutoInst, Depth, FromUser, ForceImportantDeps); + if (AutoInst == false) return; @@ -1336,6 +1457,9 @@ bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst, /* */ void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To) { + if (unlikely(Pkg.end() == true)) + return; + ActionGroup group(*this); RemoveSizes(Pkg); @@ -1349,12 +1473,17 @@ void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To) AddStates(Pkg); AddSizes(Pkg); + + if (unlikely(Pkg.CurrentVer().end() == true) || Pkg.CurrentVer().Pseudo() == false) + return; + + SetReInstall(Pkg.Group().FindPkg("all"), To); } /*}}}*/ // DepCache::SetCandidateVersion - Change the candidate version /*{{{*/ // --------------------------------------------------------------------- /* */ -void pkgDepCache::SetCandidateVersion(VerIterator TargetVer) +void pkgDepCache::SetCandidateVersion(VerIterator TargetVer, bool const &Pseudo) { ActionGroup group(*this); @@ -1372,6 +1501,28 @@ void pkgDepCache::SetCandidateVersion(VerIterator TargetVer) AddStates(Pkg); Update(Pkg); AddSizes(Pkg); + + if (TargetVer.Pseudo() == false || Pseudo == false) + return; + + // the version was pseudo: set all other pseudos also + pkgCache::GrpIterator Grp = Pkg.Group(); + for (Pkg = Grp.FindPkg("any"); Pkg.end() == false; ++Pkg) + { + StateCache &P = PkgState[Pkg->ID]; + if (TargetVer.SimilarVer(P.CandidateVerIter(*this)) == true || + (P.CandidateVerIter(*this).Pseudo() == false && + strcmp(Pkg.Arch(), "all") != 0)) + continue; + + for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver) + { + if (TargetVer.SimilarVer(Ver) == false) + continue; + SetCandidateVersion(Ver, false); + break; + } + } } void pkgDepCache::MarkAuto(const PkgIterator &Pkg, bool Auto) @@ -1434,7 +1585,7 @@ const char *pkgDepCache::StateCache::StripEpoch(const char *Ver) // --------------------------------------------------------------------- /* The default just returns the highest available version that is not a source and automatic. */ -pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg) +pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator const &Pkg) { /* Not source/not automatic versions cannot be a candidate version unless they are already installed */ @@ -1469,7 +1620,7 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg) // Policy::IsImportantDep - True if the dependency is important /*{{{*/ // --------------------------------------------------------------------- /* */ -bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep) +bool pkgDepCache::Policy::IsImportantDep(DepIterator const &Dep) { if(Dep.IsCritical()) return true; @@ -1488,54 +1639,6 @@ bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep) else if(Dep->Type == pkgCache::Dep::Suggests) return _config->FindB("APT::Install-Suggests", false); - return false; -} - /*}}}*/ -pkgDepCache::DefaultRootSetFunc::DefaultRootSetFunc() /*{{{*/ - : constructedSuccessfully(false) -{ - Configuration::Item const *Opts; - Opts = _config->Tree("APT::NeverAutoRemove"); - if (Opts != 0 && Opts->Child != 0) - { - Opts = Opts->Child; - for (; Opts != 0; Opts = Opts->Next) - { - if (Opts->Value.empty() == true) - continue; - - regex_t *p = new regex_t; - if(regcomp(p,Opts->Value.c_str(), - REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0) - { - regfree(p); - delete p; - _error->Error("Regex compilation error for APT::NeverAutoRemove"); - return; - } - - rootSetRegexp.push_back(p); - } - } - - constructedSuccessfully = true; -} - /*}}}*/ -pkgDepCache::DefaultRootSetFunc::~DefaultRootSetFunc() /*{{{*/ -{ - for(unsigned int i = 0; i < rootSetRegexp.size(); i++) - { - regfree(rootSetRegexp[i]); - delete rootSetRegexp[i]; - } -} - /*}}}*/ -bool pkgDepCache::DefaultRootSetFunc::InRootSet(const pkgCache::PkgIterator &pkg) /*{{{*/ -{ - for(unsigned int i = 0; i < rootSetRegexp.size(); i++) - if (regexec(rootSetRegexp[i], pkg.Name(), 0, 0, 0) == 0) - return true; - return false; } /*}}}*/ @@ -1590,8 +1693,11 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc) { if(!(PkgState[p->ID].Flags & Flag::Auto) || (p->Flags & Flag::Essential) || - userFunc.InRootSet(p)) - + userFunc.InRootSet(p) || + // be nice even then a required package violates the policy (#583517) + // and do the full mark process also for required packages + (p.CurrentVer().end() != true && + p.CurrentVer()->Priority == pkgCache::State::Required)) { // the package is installed (and set to keep) if(PkgState[p->ID].Keep() && !p.CurrentVer().end()) @@ -1668,10 +1774,6 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, // If the version belongs to a Multi-Arch all package // we will mark all others in this Group with this version also - // Beware: We compare versions here the lazy way: string comparision - // this is bad if multiple repositories provide different versions - // of the package with an identical version number - but even in this - // case the dependencies are likely the same. if (ver->MultiArch == pkgCache::Version::All && strcmp(ver.Arch(true), "all") == 0) { @@ -1683,7 +1785,8 @@ void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg, for (VerIterator V = P.VersionList(); V.end() != true; ++V) { - if (strcmp(VerStr, V.VerStr()) != 0) + if (ver->Hash != V->Hash || + strcmp(VerStr, V.VerStr()) != 0) continue; MarkPackage(P, V, follow_recommends, follow_suggests); break; @@ -1772,7 +1875,7 @@ bool pkgDepCache::Sweep() /*{{{*/ { state.Garbage=true; if(debug_autoremove) - std::cout << "Garbage: " << p.FullName() << std::endl; + std::clog << "Garbage: " << p.FullName() << std::endl; } }