From 7fe505ca3c372ddedc801f6607127c02a62a5133 Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Thu, 31 Oct 2019 10:35:52 -0700 Subject: [PATCH] Duplicate the directory fd in fml::VisitFiles (#13448) The fd passed to fdopendir will be unusable afterward. Using a duplicate preserves the validity of the original directory fd passed to VisitFiles. Fixes https://github.com/flutter/flutter/issues/43844 --- fml/platform/posix/file_posix.cc | 21 ++++++++++++++------- fml/unique_fd.cc | 4 ++++ fml/unique_fd.h | 8 ++++++++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/fml/platform/posix/file_posix.cc b/fml/platform/posix/file_posix.cc index 516565e9f..c275f606d 100644 --- a/fml/platform/posix/file_posix.cc +++ b/fml/platform/posix/file_posix.cc @@ -223,20 +223,26 @@ bool WriteAtomically(const fml::UniqueFD& base_directory, } bool VisitFiles(const fml::UniqueFD& directory, FileVisitor visitor) { - // We cannot call closedir(dir) because it will also close the corresponding - // UniqueFD, and later reference to that UniqueFD will fail. Also, we don't - // have to call closedir because UniqueFD will call close on its destructor. - DIR* dir = ::fdopendir(directory.get()); - if (dir == nullptr) { + fml::UniqueFD dup_fd(dup(directory.get())); + if (!dup_fd.is_valid()) { + FML_DLOG(ERROR) << "Can't dup the directory fd. Error: " << strerror(errno); + return true; // continue to visit other files + } + + fml::UniqueDir dir(::fdopendir(dup_fd.get())); + if (!dir.is_valid()) { FML_DLOG(ERROR) << "Can't open the directory. Error: " << strerror(errno); return true; // continue to visit other files } + // The directory fd will be closed by `closedir`. + (void)dup_fd.release(); + // Without `rewinddir`, `readir` will directly return NULL (end of dir is // reached) after a previuos `VisitFiles` call for the same `const // fml::UniqueFd& directory`. - rewinddir(dir); - while (dirent* ent = readdir(dir)) { + rewinddir(dir.get()); + while (dirent* ent = readdir(dir.get())) { std::string filename = ent->d_name; if (filename != "." && filename != "..") { if (!visitor(directory, filename)) { @@ -244,6 +250,7 @@ bool VisitFiles(const fml::UniqueFD& directory, FileVisitor visitor) { } } } + return true; } diff --git a/fml/unique_fd.cc b/fml/unique_fd.cc index dd115c200..2da6d938f 100644 --- a/fml/unique_fd.cc +++ b/fml/unique_fd.cc @@ -27,6 +27,10 @@ void UniqueFDTraits::Free(int fd) { close(fd); } +void UniqueDirTraits::Free(DIR* dir) { + closedir(dir); +} + } // namespace os_unix #endif // OS_WIN diff --git a/fml/unique_fd.h b/fml/unique_fd.h index 17f1a3cda..e728aa9a5 100644 --- a/fml/unique_fd.h +++ b/fml/unique_fd.h @@ -14,6 +14,7 @@ #else // OS_WIN +#include #include #endif // OS_WIN @@ -43,6 +44,12 @@ struct UniqueFDTraits { static void Free(int fd); }; +struct UniqueDirTraits { + static DIR* InvalidValue() { return nullptr; } + static bool IsValid(DIR* value) { return value != nullptr; } + static void Free(DIR* dir); +}; + } // namespace os_unix #endif // OS_WIN @@ -56,6 +63,7 @@ using UniqueFD = UniqueObject; #else // OS_WIN using UniqueFD = UniqueObject; +using UniqueDir = UniqueObject; #endif // OS_WIN -- GitLab