| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "flutter/fml/file.h" |
| |
| #include "flutter/fml/logging.h" |
| #include "flutter/fml/unique_fd.h" |
| |
| namespace fml { |
| |
| static fml::UniqueFD CreateDirectory(const fml::UniqueFD& base_directory, |
| const std::vector<std::string>& components, |
| FilePermission permission, |
| size_t index) { |
| FML_DCHECK(index <= components.size()); |
| |
| const char* file_path = components[index].c_str(); |
| |
| auto directory = OpenDirectory(base_directory, file_path, true, permission); |
| |
| if (!directory.is_valid()) { |
| return {}; |
| } |
| |
| if (index == components.size() - 1) { |
| return directory; |
| } |
| |
| return CreateDirectory(directory, components, permission, index + 1); |
| } |
| |
| fml::UniqueFD CreateDirectory(const fml::UniqueFD& base_directory, |
| const std::vector<std::string>& components, |
| FilePermission permission) { |
| if (!IsDirectory(base_directory)) { |
| return {}; |
| } |
| |
| if (components.size() == 0) { |
| return {}; |
| } |
| |
| return CreateDirectory(base_directory, components, permission, 0); |
| } |
| |
| ScopedTemporaryDirectory::ScopedTemporaryDirectory() { |
| path_ = CreateTemporaryDirectory(); |
| if (path_ != "") { |
| dir_fd_ = OpenDirectory(path_.c_str(), false, FilePermission::kRead); |
| } |
| } |
| |
| ScopedTemporaryDirectory::~ScopedTemporaryDirectory() { |
| // Windows has to close UniqueFD first before UnlinkDirectory |
| dir_fd_.reset(); |
| if (path_ != "") { |
| if (!UnlinkDirectory(path_.c_str())) { |
| FML_LOG(ERROR) << "Could not remove directory: " << path_; |
| } |
| } |
| } |
| |
| bool VisitFilesRecursively(const fml::UniqueFD& directory, |
| const FileVisitor& visitor) { |
| FileVisitor recursive_visitor = [&recursive_visitor, &visitor]( |
| const UniqueFD& directory, |
| const std::string& filename) { |
| if (!visitor(directory, filename)) { |
| return false; |
| } |
| if (IsDirectory(directory, filename.c_str())) { |
| UniqueFD sub_dir = OpenDirectoryReadOnly(directory, filename.c_str()); |
| if (!sub_dir.is_valid()) { |
| FML_LOG(ERROR) << "Can't open sub-directory: " << filename; |
| return true; |
| } |
| return VisitFiles(sub_dir, recursive_visitor); |
| } |
| return true; |
| }; |
| return VisitFiles(directory, recursive_visitor); |
| } |
| |
| fml::UniqueFD OpenFileReadOnly(const fml::UniqueFD& base_directory, |
| const char* path) { |
| return OpenFile(base_directory, path, false, FilePermission::kRead); |
| } |
| |
| fml::UniqueFD OpenDirectoryReadOnly(const fml::UniqueFD& base_directory, |
| const char* path) { |
| return OpenDirectory(base_directory, path, false, FilePermission::kRead); |
| } |
| |
| bool RemoveFilesInDirectory(const fml::UniqueFD& directory) { |
| fml::FileVisitor recursive_cleanup = [&recursive_cleanup]( |
| const fml::UniqueFD& directory, |
| const std::string& filename) { |
| bool removed; |
| if (fml::IsDirectory(directory, filename.c_str())) { |
| fml::UniqueFD sub_dir = |
| OpenDirectoryReadOnly(directory, filename.c_str()); |
| removed = VisitFiles(sub_dir, recursive_cleanup) && |
| fml::UnlinkDirectory(directory, filename.c_str()); |
| } else { |
| removed = fml::UnlinkFile(directory, filename.c_str()); |
| } |
| return removed; |
| }; |
| return VisitFiles(directory, recursive_cleanup); |
| } |
| |
| bool RemoveDirectoryRecursively(const fml::UniqueFD& parent, |
| const char* directory_name) { |
| auto dir = fml::OpenDirectory(parent, directory_name, false, |
| fml::FilePermission::kReadWrite); |
| return RemoveFilesInDirectory(dir) && UnlinkDirectory(parent, directory_name); |
| } |
| |
| } // namespace fml |