]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/depcache.h
close server if parsing of header field failed
[apt.git] / apt-pkg / depcache.h
index 8d90a529ff772185263be8eac83b5324b74409aa..03a2cb0a8230d6afdf8d42e212dddebfe96bf46b 100644 (file)
@@ -1,6 +1,5 @@
-// -*- mode: cpp; mode: fold -*-
+// -*- mode: c++; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: depcache.h,v 1.4 1998/09/07 05:28:35 jgg Exp $
 /* ######################################################################
 
    DepCache - Dependency Extension data for the cache
@@ -15,7 +14,7 @@
    
    This structure is important to support the readonly status of the cache 
    file. When the data is saved the cache will be refereshed from our 
-   internal rep and written to disk. Then the actual persistant data 
+   internal rep and written to disk. Then the actual persistent data
    files will be put on the disk.
 
    Each dependency is compared against 3 target versions to produce to
    
    ##################################################################### */
                                                                        /*}}}*/
-// Header section: pkglib
 #ifndef PKGLIB_DEPCACHE_H
 #define PKGLIB_DEPCACHE_H
 
-#ifdef __GNUG__
-#pragma interface "apt-pkg/depcache.h"
-#endif
-
+#include <apt-pkg/configuration.h>
 #include <apt-pkg/pkgcache.h>
+#include <apt-pkg/cacheiterators.h>
+#include <apt-pkg/macros.h>
+
+#include <stddef.h>
+
+#include <memory>
+#include <list>
+#include <string>
+#include <utility>
+
+#ifndef APT_8_CLEANER_HEADERS
 #include <apt-pkg/progress.h>
+#include <apt-pkg/error.h>
+#endif
+#ifndef APT_10_CLEANER_HEADERS
+#include <set>
+#include <vector>
+#endif
+
+class OpProgress;
+class pkgVersioningSystem;
 
-class pkgDepCache : public pkgCache
+class pkgDepCache : protected pkgCache::Namespace
 {
    public:
+
+   /** \brief An arbitrary predicate on packages. */
+   class InRootSetFunc
+   {
+   public:
+     virtual bool InRootSet(const pkgCache::PkgIterator &/*pkg*/) {return false;};
+     virtual ~InRootSetFunc() {};
+   };
+
+   private:
+   /** \brief Mark a single package and all its unmarked important
+    *  dependencies during mark-and-sweep.
+    *
+    *  Recursively invokes itself to mark all dependencies of the
+    *  package.
+    *
+    *  \param pkg The package to mark.
+    *
+    *  \param ver The version of the package that is to be marked.
+    *
+    *  \param follow_recommends If \b true, recommendations of the
+    *  package will be recursively marked.
+    *
+    *  \param follow_suggests If \b true, suggestions of the package
+    *  will be recursively marked.
+    */
+   APT_HIDDEN void MarkPackage(const pkgCache::PkgIterator &pkg,
+                   const pkgCache::VerIterator &ver,
+                   bool const &follow_recommends,
+                   bool const &follow_suggests);
+
+   /** \brief Update the Marked field of all packages.
+    *
+    *  Each package's StateCache::Marked field will be set to \b true
+    *  if and only if it can be reached from the root set.  By
+    *  default, the root set consists of the set of manually installed
+    *  or essential packages, but it can be extended using the
+    *  parameter #rootFunc.
+    *
+    *  \param rootFunc A callback that can be used to add extra
+    *  packages to the root set.
+    *
+    *  \return \b false if an error occurred.
+    */
+   bool MarkRequired(InRootSetFunc &rootFunc);
+
+   /** \brief Set the StateCache::Garbage flag on all packages that
+    *  should be removed.
+    *
+    *  Packages that were not marked by the last call to #MarkRequired
+    *  are tested to see whether they are actually garbage.  If so,
+    *  they are marked as such.
+    *
+    *  \return \b false if an error occurred.
+    */
+   bool Sweep();
+
+   public:
    
    // These flags are used in DepState
    enum DepFlags {DepNow = (1 << 0),DepInstall = (1 << 1),DepCVer = (1 << 2),
@@ -60,13 +133,83 @@ class pkgDepCache : public pkgCache
                        DepCandPolicy = (1 << 4), DepCandMin = (1 << 5)};
    
    // These flags are used in StateCache::iFlags
-   enum InternalFlags {AutoKept = (1 << 0)};
+   enum InternalFlags {AutoKept = (1 << 0), Purge = (1 << 1), ReInstall = (1 << 2), Protected = (1 << 3)};
       
    enum VersionTypes {NowVersion, InstallVersion, CandidateVersion};
-   enum ModeList {ModeDelete = 0, ModeKeep = 1, ModeInstall = 2};
+   enum ModeList {ModeDelete = 0, ModeKeep = 1, ModeInstall = 2, ModeGarbage = 3};
+
+   /** \brief Represents an active action group.
+    *
+    *  An action group is a group of actions that are currently being
+    *  performed.  While an active group is active, certain routine
+    *  clean-up actions that would normally be performed after every
+    *  cache operation are delayed until the action group is
+    *  completed.  This is necessary primarily to avoid inefficiencies
+    *  when modifying a large number of packages at once.
+    *
+    *  This class represents an active action group.  Creating an
+    *  instance will create an action group; destroying one will
+    *  destroy the corresponding action group.
+    *
+    *  The following operations are suppressed by this class:
+    *
+    *    - Keeping the Marked and Garbage flags up to date.
+    *
+    *  \note This can be used in the future to easily accumulate
+    *  atomic actions for undo or to display "what apt did anyway";
+    *  e.g., change the counter of how many action groups are active
+    *  to a std::set of pointers to them and use those to store
+    *  information about what happened in a group in the group.
+    */
+   class ActionGroup
+   {
+       void * const d;
+       pkgDepCache &cache;
+
+       bool released;
+
+       /** Action groups are noncopyable. */
+       APT_HIDDEN ActionGroup(const ActionGroup &other);
+   public:
+       /** \brief Create a new ActionGroup.
+       *
+       *  \param cache The cache that this ActionGroup should
+       *  manipulate.
+       *
+       *  As long as this object exists, no automatic cleanup
+       *  operations will be undertaken.
+       */
+       explicit ActionGroup(pkgDepCache &cache);
+
+       /** \brief Clean up the action group before it is destroyed.
+        *
+        *  If it is destroyed later, no second cleanup wil be run.
+       */
+       void release();
+
+       /** \brief Destroy the action group.
+       *
+       *  If this is the last action group, the automatic cache
+       *  cleanup operations will be undertaken.
+       */
+       virtual ~ActionGroup();
+   };
+
+   /** \brief Returns \b true for packages matching a regular
+    *  expression in APT::NeverAutoRemove.
+    */
+   class DefaultRootSetFunc : public InRootSetFunc, public Configuration::MatchAgainstConfig
+   {
+   public:
+     DefaultRootSetFunc() : Configuration::MatchAgainstConfig("APT::NeverAutoRemove") {};
+     virtual ~DefaultRootSetFunc() {};
+
+     bool InRootSet(const pkgCache::PkgIterator &pkg) APT_OVERRIDE { return pkg.end() == false && Match(pkg.Name()); };
+   };
+
    struct StateCache
    {
-      // Epoch stripped text versions of the two version fields
+      // text versions of the two version fields
       const char *CandVersion;
       const char *CurVersion;
 
@@ -75,31 +218,47 @@ class pkgDepCache : public pkgCache
 
       // Pointer to the install version.
       Version *InstallVer;
+      
+      // Copy of Package::Flags
+      unsigned short Flags;
+      unsigned short iFlags;           // Internal flags
+
+      /** \brief \b true if this package can be reached from the root set. */
+      bool Marked;
+
+      /** \brief \b true if this package is unused and should be removed.
+       *
+       *  This differs from !#Marked, because it is possible that some
+       *  unreachable packages will be protected from becoming
+       *  garbage.
+       */
+      bool Garbage;
 
       // Various tree indicators
       signed char Status;              // -1,0,1,2
       unsigned char Mode;              // ModeList
       unsigned char DepState;          // DepState Flags
 
-      // Copy of Package::Flags
-      unsigned short Flags;
-      unsigned short iFlags;           // Internal flags
-
       // Update of candidate version
-      const char *StripEpoch(const char *Ver);
+      APT_DEPRECATED_MSG("Use the method of the same name in contrib/strutl.h instead if you must") const char *StripEpoch(const char *Ver) APT_PURE;
       void Update(PkgIterator Pkg,pkgCache &Cache);
       
       // Various test members for the current status of the package
       inline bool NewInstall() const {return Status == 2 && Mode == ModeInstall;};
       inline bool Delete() const {return Mode == ModeDelete;};
+      inline bool Purge() const {return Delete() == true && (iFlags & pkgDepCache::Purge) == pkgDepCache::Purge; };
       inline bool Keep() const {return Mode == ModeKeep;};
+      inline bool Protect() const {return (iFlags & Protected) == Protected;};
       inline bool Upgrade() const {return Status > 0 && Mode == ModeInstall;};
-      inline bool Upgradable() const {return Status == 1;};
-      inline bool Downgrade() const {return Status < 0;};
+      inline bool Upgradable() const {return Status >= 1 && CandidateVer != NULL;};
+      inline bool Downgrade() const {return Status < 0 && Mode == ModeInstall;};
       inline bool Held() const {return Status != 0 && Keep();};
       inline bool NowBroken() const {return (DepState & DepNowMin) != DepNowMin;};
+      inline bool NowPolicyBroken() const {return (DepState & DepNowPolicy) != DepNowPolicy;};
       inline bool InstBroken() const {return (DepState & DepInstMin) != DepInstMin;};
+      inline bool InstPolicyBroken() const {return (DepState & DepInstPolicy) != DepInstPolicy;};
       inline bool Install() const {return Mode == ModeInstall;};
+      inline bool ReInstall() const {return Delete() == false && (iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall;};
       inline VerIterator InstVerIter(pkgCache &Cache)
                 {return VerIterator(Cache,InstallVer);};
       inline VerIterator CandidateVerIter(pkgCache &Cache)
@@ -108,77 +267,259 @@ class pkgDepCache : public pkgCache
    
    // Helper functions
    void BuildGroupOrs(VerIterator const &V);
-   void UpdateVerState(PkgIterator Pkg);
+   void UpdateVerState(PkgIterator const &Pkg);
+
+   // User Policy control
+   class Policy
+   {
+      public:
+      Policy() {
+         InstallRecommends = _config->FindB("APT::Install-Recommends", false);
+         InstallSuggests = _config->FindB("APT::Install-Suggests", false);
+      }
 
-   bool Init(OpProgress *Prog);
+      virtual VerIterator GetCandidateVer(PkgIterator const &Pkg);
+      virtual bool IsImportantDep(DepIterator const &Dep) const;
+      virtual signed short GetPriority(PkgIterator const &Pkg);
+      virtual signed short GetPriority(VerIterator const &Ver, bool ConsiderFiles=true);
+      virtual signed short GetPriority(PkgFileIterator const &File);
 
+      virtual ~Policy() {};
+
+      private:
+      bool InstallRecommends;
+      bool InstallSuggests;
+   };
+
+   private:
+   /** The number of open "action groups"; certain post-action
+    *  operations are suppressed if this number is > 0.
+    */
+   int group_level;
+
+   friend class ActionGroup;
+     
    protected:
 
    // State information
+   pkgCache *Cache;
    StateCache *PkgState;
    unsigned char *DepState;
+
+   /** Stores the space changes after installation */
+   signed long long iUsrSize;
+   /** Stores how much we need to download to get the packages */
+   unsigned long long iDownloadSize;
+   unsigned long iInstCount;
+   unsigned long iDelCount;
+   unsigned long iKeepCount;
+   unsigned long iBrokenCount;
+   unsigned long iPolicyBrokenCount;
+   unsigned long iBadCount;
+
+   bool DebugMarker;
+   bool DebugAutoInstall;
+
+   Policy *delLocalPolicy;           // For memory clean up..
+   Policy *LocalPolicy;
    
-   long iUsrSize;
-   long iDownloadSize;
-   long iInstCount;
-   long iDelCount;
-   long iKeepCount;
-   long iBrokenCount;
-   long iBadCount;
-      
    // Check for a matching provides
-   bool CheckDep(DepIterator Dep,int Type,PkgIterator &Res);
-   inline bool CheckDep(DepIterator Dep,int Type)
+   bool CheckDep(DepIterator const &Dep,int const Type,PkgIterator &Res);
+   inline bool CheckDep(DepIterator const &Dep,int const Type)
    {
-      PkgIterator Res(*this);
+      PkgIterator Res(*this,0);
       return CheckDep(Dep,Type,Res);
-   } 
+   }
    
    // Computes state information for deps and versions (w/o storing)
-   unsigned char DependencyState(DepIterator &D);
-   unsigned char VersionState(DepIterator D,unsigned char Check,
-                             unsigned char SetMin,
-                             unsigned char SetPolicy);
+   unsigned char DependencyState(DepIterator const &D);
+   unsigned char VersionState(DepIterator D,unsigned char const Check,
+                             unsigned char const SetMin,
+                             unsigned char const SetPolicy) const;
 
    // Recalculates various portions of the cache, call after changing something
    void Update(DepIterator Dep);           // Mostly internal
    void Update(PkgIterator const &P);
    
    // Count manipulators
-   void AddSizes(const PkgIterator &Pkg,long Mult = 1);
-   inline void RemoveSizes(const PkgIterator &Pkg) {AddSizes(Pkg,-1);};
-   void AddStates(const PkgIterator &Pkg,int Add = 1);
-   inline void RemoveStates(const PkgIterator &Pkg) {AddStates(Pkg,-1);};
-
+   void AddSizes(const PkgIterator &Pkg, bool const Invert = false);
+   inline void RemoveSizes(const PkgIterator &Pkg) {AddSizes(Pkg, true);};
+   void AddStates(const PkgIterator &Pkg, bool const Invert = false);
+   inline void RemoveStates(const PkgIterator &Pkg) {AddStates(Pkg,true);};
+   
    public:
 
+   // Legacy.. We look like a pkgCache
+   inline operator pkgCache &() {return *Cache;};
+   inline Header &Head() {return *Cache->HeaderP;};
+   inline GrpIterator GrpBegin() {return Cache->GrpBegin();};
+   inline PkgIterator PkgBegin() {return Cache->PkgBegin();};
+   inline GrpIterator FindGrp(std::string const &Name) {return Cache->FindGrp(Name);};
+   inline PkgIterator FindPkg(std::string const &Name) {return Cache->FindPkg(Name);};
+   inline PkgIterator FindPkg(std::string const &Name, std::string const &Arch) {return Cache->FindPkg(Name, Arch);};
+
+   inline pkgCache &GetCache() {return *Cache;};
+   inline pkgVersioningSystem &VS() {return *Cache->VS;};
+
    // Policy implementation
-   virtual VerIterator GetCandidateVer(PkgIterator Pkg);
-   virtual bool IsImportantDep(DepIterator Dep);
-         
+   APT_DEPRECATED_MSG("Confusingly named method which returns the candidate as chosen by policy (NOT as chosen via .SetCandidateVersion!). You probably want to use .GetCandidateVersion instead.") inline VerIterator GetCandidateVer(PkgIterator const &Pkg) {return /* GetCandidateVersion(Pkg); but for API compat: */ LocalPolicy->GetCandidateVer(Pkg);};
+
+   inline bool IsImportantDep(DepIterator Dep) const {return LocalPolicy->IsImportantDep(Dep);};
+   inline Policy &GetPolicy() {return *LocalPolicy;};
+   
    // Accessors
    inline StateCache &operator [](PkgIterator const &I) {return PkgState[I->ID];};
+   inline StateCache &operator [](PkgIterator const &I) const {return PkgState[I->ID];};
    inline unsigned char &operator [](DepIterator const &I) {return DepState[I->ID];};
 
-   // Manipulators
-   void MarkKeep(PkgIterator const &Pkg,bool Soft = false);
-   void MarkDelete(PkgIterator const &Pkg);
-   void MarkInstall(PkgIterator const &Pkg,bool AutoInst = true);
-   
-   // This is for debuging
-   void Update(OpProgress *Prog = 0);
+   /** \return A function identifying packages in the root set other
+    *  than manually installed packages and essential packages, or \b
+    *  NULL if an error occurs.
+    *
+    *  \todo Is this the best place for this function?  Perhaps the
+    *  settings for mark-and-sweep should be stored in a single
+    *  external class?
+    */
+   virtual InRootSetFunc *GetRootSetFunc();
 
-   // Size queries
-   inline long UsrSize() {return iUsrSize;};
-   inline long DebSize() {return iDownloadSize;};
-   inline long DelCount() {return iDelCount;};
-   inline long KeepCount() {return iKeepCount;};
-   inline long InstCount() {return iInstCount;};
-   inline long BrokenCount() {return iBrokenCount;};
-   inline long BadCount() {return iBadCount;};
+   /** \return \b true if the garbage collector should follow recommendations.
+    */
+   virtual bool MarkFollowsRecommends();
+
+   /** \return \b true if the garbage collector should follow suggestions.
+    */
+   virtual bool MarkFollowsSuggests();
+
+   /** \brief Update the Marked and Garbage fields of all packages.
+    *
+    *  This routine is implicitly invoked after all state manipulators
+    *  and when an ActionGroup is destroyed.  It invokes the private
+    *  MarkRequired() and Sweep() to do its dirty work.
+    *
+    *  \param rootFunc A predicate that returns \b true for packages
+    *  that should be added to the root set.
+    */
+   bool MarkAndSweep(InRootSetFunc &rootFunc);
+   bool MarkAndSweep();
+
+   /** \name State Manipulators
+    */
+   // @{
+   bool MarkKeep(PkgIterator const &Pkg, bool Soft = false,
+                bool FromUser = true, unsigned long Depth = 0);
+   bool MarkDelete(PkgIterator const &Pkg, bool MarkPurge = false,
+                   unsigned long Depth = 0, bool FromUser = true);
+   bool MarkInstall(PkgIterator const &Pkg,bool AutoInst = true,
+                   unsigned long Depth = 0, bool FromUser = true,
+                   bool ForceImportantDeps = false);
+   void MarkProtected(PkgIterator const &Pkg) { PkgState[Pkg->ID].iFlags |= Protected; };
+
+   void SetReInstall(PkgIterator const &Pkg,bool To);
+
+   /** @return 'the' candidate version of a package
+    *
+    * The version returned is the version previously set explicitly via
+    * SetCandidate* methods like #SetCandidateVersion or if there wasn't one
+    * set the version as chosen via #Policy.
+    *
+    * @param Pkg is the package to return the candidate for
+    */
+   pkgCache::VerIterator GetCandidateVersion(pkgCache::PkgIterator const &Pkg);
+   void SetCandidateVersion(VerIterator TargetVer);
+   bool SetCandidateRelease(pkgCache::VerIterator TargetVer,
+                               std::string const &TargetRel);
+   /** Set the candidate version for dependencies too if needed.
+    *
+    *  Sets not only the candidate version as SetCandidateVersion does,
+    *  but walks also down the dependency tree and checks if it is required
+    *  to set the candidate of the dependency to a version from the given
+    *  release, too.
+    *
+    *  \param TargetVer new candidate version of the package
+    *  \param TargetRel try to switch to this release if needed
+    *  \param[out] Changed a list of pairs consisting of the \b old
+    *              version of the changed package and the version which
+    *              required the switch of this dependency
+    *  \return \b true if the switch was successful, \b false otherwise
+    */
+   bool SetCandidateRelease(pkgCache::VerIterator TargetVer,
+                           std::string const &TargetRel,
+                           std::list<std::pair<pkgCache::VerIterator, pkgCache::VerIterator> > &Changed);
+
+   /** Set the "is automatically installed" flag of Pkg. */
+   void MarkAuto(const PkgIterator &Pkg, bool Auto);
+   // @}
+
+   /** \return \b true if it's OK for MarkInstall to install
+    *  the given package.
+    *
+    *  The default implementation simply calls all IsInstallOk*
+    *  method mentioned below.
+    *
+    *  Overriding implementations should use the hold-state-flag to
+    *  cache results from previous checks of this package - if possible.
+    *
+    *  The parameters are the same as in the calling MarkInstall:
+    *  \param Pkg       the package that MarkInstall wants to install.
+    *  \param AutoInst  install this and all its dependencies
+    *  \param Depth     recursive deep of this Marker call
+    *  \param FromUser  was the install requested by the user?
+    */
+   virtual bool IsInstallOk(const PkgIterator &Pkg,bool AutoInst = true,
+                           unsigned long Depth = 0, bool FromUser = true);
+
+   /** \return \b true if it's OK for MarkDelete to remove
+    *  the given package.
+    *
+    *  The default implementation simply calls all IsDeleteOk*
+    *  method mentioned below, see also #IsInstallOk.
+    *
+    *  The parameters are the same as in the calling MarkDelete:
+    *  \param Pkg       the package that MarkDelete wants to remove.
+    *  \param MarkPurge should we purge instead of "only" remove?
+    *  \param Depth     recursive deep of this Marker call
+    *  \param FromUser  was the remove requested by the user?
+    */
+   virtual bool IsDeleteOk(const PkgIterator &Pkg,bool MarkPurge = false,
+                           unsigned long Depth = 0, bool FromUser = true);
+
+   // read persistent states
+   bool readStateFile(OpProgress * const prog);
+   bool writeStateFile(OpProgress * const prog, bool const InstalledOnly=true);
    
-   pkgDepCache(MMap &Map,OpProgress &Prog);
+   // Size queries
+   inline signed long long UsrSize() {return iUsrSize;};
+   inline unsigned long long DebSize() {return iDownloadSize;};
+   inline unsigned long DelCount() {return iDelCount;};
+   inline unsigned long KeepCount() {return iKeepCount;};
+   inline unsigned long InstCount() {return iInstCount;};
+   inline unsigned long BrokenCount() {return iBrokenCount;};
+   inline unsigned long PolicyBrokenCount() {return iPolicyBrokenCount;};
+   inline unsigned long BadCount() {return iBadCount;};
+
+   bool Init(OpProgress * const Prog);
+   // Generate all state information
+   void Update(OpProgress * const Prog = 0);
+
+   pkgDepCache(pkgCache * const Cache,Policy * const Plcy = 0);
    virtual ~pkgDepCache();
+
+   protected:
+   // methods call by IsInstallOk
+   bool IsInstallOkMultiArchSameVersionSynced(PkgIterator const &Pkg,
+        bool const AutoInst, unsigned long const Depth, bool const FromUser);
+   bool IsInstallOkDependenciesSatisfiableByCandidates(PkgIterator const &Pkg,
+      bool const AutoInst, unsigned long const Depth, bool const FromUser);
+
+   // methods call by IsDeleteOk
+   bool IsDeleteOkProtectInstallRequests(PkgIterator const &Pkg,
+        bool const rPurge, unsigned long const Depth, bool const FromUser);
+
+   private:
+   void * const d;
+
+   APT_HIDDEN bool IsModeChangeOk(ModeList const mode, PkgIterator const &Pkg,
+                       unsigned long const Depth, bool const FromUser);
 };
 
 #endif