diff options
author | David Kalnischkies <david@kalnischkies.de> | 2017-03-19 12:59:44 +0100 |
---|---|---|
committer | David Kalnischkies <david@kalnischkies.de> | 2017-06-26 23:31:15 +0200 |
commit | 24fbb6adb071c39e24f9b0a89aadc7d5673a8775 (patch) | |
tree | 021630fdf588125bad82f2385000e54431c86efa | |
parent | 0cbe571a44468806af95f3d8661b07b01704eb26 (diff) |
Avoid chdir in acquire clean with unlinkat
POSIX.1-2008 gives us a range of *at calls to deal with files
including the unlinkat so we can remove a file from a directory
based on a path to the file relative to the directory.
(In our case here the path we have is just the filename)
We avoid changing directories in this way which e.g. fails if the
directory we started in no longer exists or is otherwise inaccessible.
Closes: 860738
-rw-r--r-- | apt-pkg/acquire.cc | 56 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.cc | 15 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.h | 1 |
3 files changed, 40 insertions, 32 deletions
diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc index b62c50c00..8a6928fb9 100644 --- a/apt-pkg/acquire.cc +++ b/apt-pkg/acquire.cc @@ -770,42 +770,34 @@ bool pkgAcquire::Clean(string Dir) if(Dir == "/") return _error->Error(_("Clean of %s is not supported"), Dir.c_str()); - DIR *D = opendir(Dir.c_str()); - if (D == 0) + 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()); + DIR * const D = fdopendir(dirfd); + if (D == nullptr) return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str()); - - string StartDir = SafeGetCWD(); - if (chdir(Dir.c_str()) != 0) - { - closedir(D); - return _error->Errno("chdir",_("Unable to change to %s"),Dir.c_str()); - } - - for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D)) + + for (struct dirent *E = readdir(D); E != nullptr; E = readdir(D)) { - // Skip some files.. - if (strcmp(Dir->d_name,"lock") == 0 || - strcmp(Dir->d_name,"partial") == 0 || - strcmp(Dir->d_name,"lost+found") == 0 || - strcmp(Dir->d_name,".") == 0 || - strcmp(Dir->d_name,"..") == 0) + // Skip some entries + if (strcmp(E->d_name,"lock") == 0 || + strcmp(E->d_name,"partial") == 0 || + strcmp(E->d_name,"lost+found") == 0 || + strcmp(E->d_name,".") == 0 || + strcmp(E->d_name,"..") == 0) continue; - - // Look in the get list - ItemCIterator I = Items.begin(); - for (; I != Items.end(); ++I) - if (flNotDir((*I)->DestFile) == Dir->d_name) - break; - - // Nothing found, nuke it - if (I == Items.end()) - RemoveFile("Clean", Dir->d_name); - }; - + + // Look in the get list and if not found nuke + if (std::any_of(Items.cbegin(), Items.cend(), + [&E](pkgAcquire::Item const * const I) { + return flNotDir(I->DestFile) == E->d_name; + }) == false) + { + RemoveFileAt("pkgAcquire::Clean", dirfd, E->d_name); + } + } closedir(D); - if (chdir(StartDir.c_str()) != 0) - return _error->Errno("chdir",_("Unable to change to %s"),StartDir.c_str()); - return true; + return true; } /*}}}*/ // Acquire::TotalNeeded - Number of bytes to fetch /*{{{*/ diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index e4c40fb4f..8ce8d5baf 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -178,6 +178,21 @@ bool CopyFile(FileFd &From,FileFd &To) return true; } /*}}}*/ +bool RemoveFileAt(char const * const Function, int const dirfd, std::string const &FileName)/*{{{*/ +{ + if (FileName == "/dev/null") + return true; + errno = 0; + if (unlinkat(dirfd, FileName.c_str(), 0) != 0) + { + if (errno == ENOENT) + return true; + + return _error->WarningE(Function,_("Problem unlinking the file %s"), FileName.c_str()); + } + return true; +} + /*}}}*/ bool RemoveFile(char const * const Function, std::string const &FileName)/*{{{*/ { if (FileName == "/dev/null") diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index dddeb70f5..b3804cccc 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -161,6 +161,7 @@ class FileFd bool RunScripts(const char *Cnf); bool CopyFile(FileFd &From,FileFd &To); bool RemoveFile(char const * const Function, std::string const &FileName); +bool RemoveFileAt(char const * const Function, int const dirfd, std::string const &FileName); int GetLock(std::string File,bool Errors = true); bool FileExists(std::string File); bool RealFileExists(std::string File); |