summaryrefslogtreecommitdiffstats
path: root/apt-pkg/clean.cc
blob: f335554a3dfe3b301053de780cd58556495aaa5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// -*- mode: cpp; mode: fold -*-
// Description								/*{{{*/
/* ######################################################################

   Clean - Clean out downloaded directories
   
   ##################################################################### */
									/*}}}*/
// Includes								/*{{{*/
#include <config.h>

#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/clean.h>
#include <apt-pkg/configuration.h>
#include <apt-pkg/error.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/pkgcache.h>
#include <apt-pkg/strutl.h>

#include <string>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <apti18n.h>
									/*}}}*/
// ArchiveCleaner::Go - Perform smart cleanup of the archive		/*{{{*/
// ---------------------------------------------------------------------
/* Scan the directory for files to erase, we check the version information
   against our database to see if it is interesting */
bool pkgArchiveCleaner::Go(std::string Dir,pkgCache &Cache)
{
   bool CleanInstalled = _config->FindB("APT::Clean-Installed",true);

   if(Dir == "/")
      return _error->Error(_("Clean of %s is not supported"), Dir.c_str());

   // non-existing directories are always clean
   // we do not check for a directory explicitly to support symlinks
   if (FileExists(Dir) == false)
      return true;

   auto const withoutChangingDir = dynamic_cast<pkgArchiveCleaner2*>(this);
   int const dirfd = open(Dir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
   if (dirfd == -1)
      return _error->Errno("open",_("Unable to read %s"),Dir.c_str());
   std::string CWD;
   if (withoutChangingDir == nullptr)
   {
      CWD = SafeGetCWD();
      if (fchdir(dirfd) != 0)
	 return _error->Errno("fchdir",_("Unable to change to %s"),Dir.c_str());
   }
   DIR * const D = fdopendir(dirfd);
   if (D == nullptr)
      return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());

   for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
   {
      // Skip some files..
      if (strcmp(Dir->d_name, "lock") == 0 ||
	  strcmp(Dir->d_name, "partial") == 0 ||
	  strcmp(Dir->d_name, "auxfiles") == 0 ||
	  strcmp(Dir->d_name, "lost+found") == 0 ||
	  strcmp(Dir->d_name, ".") == 0 ||
	  strcmp(Dir->d_name, "..") == 0)
	 continue;

      struct stat St;
      if (fstatat(dirfd, Dir->d_name,&St, 0) != 0)
      {
	 _error->Errno("stat",_("Unable to stat %s."),Dir->d_name);
	 closedir(D);
	 return false;
      }

      // Grab the package name
      const char *I = Dir->d_name;
      for (; *I != 0 && *I != '_';I++);
      if (*I != '_')
	 continue;
      std::string Pkg = DeQuoteString(std::string(Dir->d_name,I-Dir->d_name));

      // Grab the version
      const char *Start = I + 1;
      for (I = Start; *I != 0 && *I != '_';I++);
      if (*I != '_')
	 continue;
      std::string Ver = DeQuoteString(std::string(Start,I-Start));

      // Grab the arch
      Start = I + 1;
      for (I = Start; *I != 0 && *I != '.' ;I++);
      if (*I != '.')
	 continue;
      std::string const Arch = DeQuoteString(std::string(Start,I-Start));

      // ignore packages of unconfigured architectures
      if (APT::Configuration::checkArchitecture(Arch) == false)
	 continue;

      // Lookup the package
      pkgCache::PkgIterator P = Cache.FindPkg(Pkg, Arch);
      if (P.end() != true)
      {
	 pkgCache::VerIterator V = P.VersionList();
	 for (; V.end() == false; ++V)
	 {
	    // See if we can fetch this version at all
	    bool IsFetchable = false;
	    for (pkgCache::VerFileIterator J = V.FileList(); 
		 J.end() == false; ++J)
	    {
	       if (CleanInstalled == true &&
		   J.File().Flagged(pkgCache::Flag::NotSource))
		  continue;
	       IsFetchable = true;
	       break;
	    }

	    // See if this version matches the file
	    if (IsFetchable == true && Ver == V.VerStr())
	       break;
	 }

	 // We found a match, keep the file
	 if (V.end() == false)
	    continue;
      }

      if (withoutChangingDir == nullptr)
      {
	 APT_IGNORE_DEPRECATED_PUSH
	 Erase(Dir->d_name, Pkg, Ver, St);
	 APT_IGNORE_DEPRECATED_POP
      }
      else
	 withoutChangingDir->Erase(dirfd, Dir->d_name, Pkg, Ver, St);
   }
   closedir(D);
   if (withoutChangingDir == nullptr && chdir(CWD.c_str()) != 0)
      return _error->Errno("chdir", _("Unable to change to %s"),Dir.c_str());
   return true;
}
									/*}}}*/

pkgArchiveCleaner::pkgArchiveCleaner() : d(NULL) {}
pkgArchiveCleaner::~pkgArchiveCleaner() {}