diff options
Diffstat (limited to 'google/zip.cc')
-rw-r--r-- | google/zip.cc | 318 |
1 files changed, 159 insertions, 159 deletions
diff --git a/google/zip.cc b/google/zip.cc index 907e5da..1a43196 100644 --- a/google/zip.cc +++ b/google/zip.cc @@ -4,17 +4,18 @@ #include "third_party/zlib/google/zip.h" -#include <list> #include <string> #include <vector> #include "base/bind.h" #include "base/files/file.h" #include "base/files/file_enumerator.h" +#include "base/files/file_util.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/strings/string_util.h" #include "build/build_config.h" +#include "third_party/zlib/google/redact.h" #include "third_party/zlib/google/zip_internal.h" #include "third_party/zlib/google/zip_reader.h" #include "third_party/zlib/google/zip_writer.h" @@ -26,18 +27,13 @@ bool IsHiddenFile(const base::FilePath& file_path) { return file_path.BaseName().value()[0] == '.'; } -bool ExcludeNoFilesFilter(const base::FilePath& file_path) { - return true; -} - -bool ExcludeHiddenFilesFilter(const base::FilePath& file_path) { - return !IsHiddenFile(file_path); -} - // Creates a directory at |extract_dir|/|entry_path|, including any parents. bool CreateDirectory(const base::FilePath& extract_dir, const base::FilePath& entry_path) { - return base::CreateDirectory(extract_dir.Append(entry_path)); + const base::FilePath dir = extract_dir.Append(entry_path); + const bool ok = base::CreateDirectory(dir); + PLOG_IF(ERROR, !ok) << "Cannot create directory " << Redact(dir); + return ok; } // Creates a WriterDelegate that can write a file at |extract_dir|/|entry_path|. @@ -50,222 +46,226 @@ std::unique_ptr<WriterDelegate> CreateFilePathWriterDelegate( class DirectFileAccessor : public FileAccessor { public: - explicit DirectFileAccessor(base::FilePath src_dir) : src_dir_(src_dir) {} + explicit DirectFileAccessor(base::FilePath src_dir) + : src_dir_(std::move(src_dir)) {} + ~DirectFileAccessor() override = default; - std::vector<base::File> OpenFilesForReading( - const std::vector<base::FilePath>& paths) override { - std::vector<base::File> files; - for (const auto& path : paths) { - base::File file; - if (base::PathExists(path) && !base::DirectoryExists(path)) { - file = base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ); + bool Open(const Paths paths, std::vector<base::File>* const files) override { + DCHECK(files); + files->reserve(files->size() + paths.size()); + + for (const base::FilePath& path : paths) { + DCHECK(!path.IsAbsolute()); + const base::FilePath absolute_path = src_dir_.Append(path); + if (base::DirectoryExists(absolute_path)) { + files->emplace_back(); + LOG(ERROR) << "Cannot open " << Redact(path) << ": It is a directory"; + } else { + const base::File& file = files->emplace_back( + absolute_path, base::File::FLAG_OPEN | base::File::FLAG_READ); + LOG_IF(ERROR, !file.IsValid()) + << "Cannot open " << Redact(path) << ": " + << base::File::ErrorToString(file.error_details()); } - files.push_back(std::move(file)); } - return files; - } - bool DirectoryExists(const base::FilePath& file) override { - return base::DirectoryExists(file); + return true; } - std::vector<DirectoryContentEntry> ListDirectoryContent( - const base::FilePath& dir) override { - std::vector<DirectoryContentEntry> files; + bool List(const base::FilePath& path, + std::vector<base::FilePath>* const files, + std::vector<base::FilePath>* const subdirs) override { + DCHECK(!path.IsAbsolute()); + DCHECK(files); + DCHECK(subdirs); + base::FileEnumerator file_enumerator( - dir, false /* recursive */, + src_dir_.Append(path), false /* recursive */, base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); - for (base::FilePath path = file_enumerator.Next(); !path.value().empty(); - path = file_enumerator.Next()) { - files.push_back(DirectoryContentEntry(path, base::DirectoryExists(path))); + + while (!file_enumerator.Next().empty()) { + const base::FileEnumerator::FileInfo info = file_enumerator.GetInfo(); + (info.IsDirectory() ? subdirs : files) + ->push_back(path.Append(info.GetName())); } - return files; + + return true; } - base::Time GetLastModifiedTime(const base::FilePath& path) override { + bool GetInfo(const base::FilePath& path, Info* const info) override { + DCHECK(!path.IsAbsolute()); + DCHECK(info); + base::File::Info file_info; - if (!base::GetFileInfo(path, &file_info)) { - LOG(ERROR) << "Failed to retrieve file modification time for " - << path.value(); + if (!base::GetFileInfo(src_dir_.Append(path), &file_info)) { + PLOG(ERROR) << "Cannot get info of " << Redact(path); + return false; } - return file_info.last_modified; + + info->is_directory = file_info.is_directory; + info->last_modified = file_info.last_modified; + + return true; } private: - base::FilePath src_dir_; - - DISALLOW_COPY_AND_ASSIGN(DirectFileAccessor); + const base::FilePath src_dir_; }; } // namespace -ZipParams::ZipParams(const base::FilePath& src_dir, - const base::FilePath& dest_file) - : src_dir_(src_dir), - dest_file_(dest_file), - file_accessor_(new DirectFileAccessor(src_dir)) {} - -#if defined(OS_POSIX) -// Does not take ownership of |fd|. -ZipParams::ZipParams(const base::FilePath& src_dir, int dest_fd) - : src_dir_(src_dir), - dest_fd_(dest_fd), - file_accessor_(new DirectFileAccessor(src_dir)) {} -#endif +std::ostream& operator<<(std::ostream& out, const Progress& progress) { + return out << progress.bytes << " bytes, " << progress.files << " files, " + << progress.directories << " dirs, " << progress.errors + << " errors"; +} bool Zip(const ZipParams& params) { - // Using a pointer to avoid copies of a potentially large array. - const std::vector<base::FilePath>* files_to_add = ¶ms.files_to_zip(); - std::vector<base::FilePath> all_files; - if (files_to_add->empty()) { - // Include all files from the src_dir (modulo the src_dir itself and - // filtered and hidden files). - - files_to_add = &all_files; - // Using a list so we can call push_back while iterating. - std::list<FileAccessor::DirectoryContentEntry> entries; - entries.push_back(FileAccessor::DirectoryContentEntry( - params.src_dir(), true /* is directory*/)); - const FilterCallback& filter_callback = params.filter_callback(); - for (auto iter = entries.begin(); iter != entries.end(); ++iter) { - const base::FilePath& entry_path = iter->path; - if (iter != entries.begin() && // Don't filter the root dir. - ((!params.include_hidden_files() && IsHiddenFile(entry_path)) || - (filter_callback && !filter_callback.Run(entry_path)))) { - continue; - } - - if (iter != entries.begin()) { // Exclude the root dir from the ZIP file. - // Make the path relative for AddEntryToZip. - base::FilePath relative_path; - bool success = - params.src_dir().AppendRelativePath(entry_path, &relative_path); - DCHECK(success); - all_files.push_back(relative_path); - } - - if (iter->is_directory) { - std::vector<FileAccessor::DirectoryContentEntry> subentries = - params.file_accessor()->ListDirectoryContent(entry_path); - entries.insert(entries.end(), subentries.begin(), subentries.end()); - } - } - } + DirectFileAccessor default_accessor(params.src_dir); + FileAccessor* const file_accessor = params.file_accessor ?: &default_accessor; std::unique_ptr<internal::ZipWriter> zip_writer; -#if defined(OS_POSIX) - if (params.dest_fd() != base::kInvalidPlatformFile) { - DCHECK(params.dest_file().empty()); - zip_writer = internal::ZipWriter::CreateWithFd( - params.dest_fd(), params.src_dir(), params.file_accessor()); + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) + if (params.dest_fd != base::kInvalidPlatformFile) { + DCHECK(params.dest_file.empty()); + zip_writer = + internal::ZipWriter::CreateWithFd(params.dest_fd, file_accessor); if (!zip_writer) return false; } #endif + if (!zip_writer) { - zip_writer = internal::ZipWriter::Create( - params.dest_file(), params.src_dir(), params.file_accessor()); + zip_writer = internal::ZipWriter::Create(params.dest_file, file_accessor); if (!zip_writer) return false; } - return zip_writer->WriteEntries(*files_to_add); -} -bool Unzip(const base::FilePath& src_file, const base::FilePath& dest_dir) { - return UnzipWithFilterCallback( - src_file, dest_dir, base::BindRepeating(&ExcludeNoFilesFilter), true); + zip_writer->SetProgressCallback(params.progress_callback, + params.progress_period); + zip_writer->SetRecursive(params.recursive); + zip_writer->ContinueOnError(params.continue_on_error); + + if (!params.include_hidden_files || params.filter_callback) + zip_writer->SetFilterCallback(base::BindRepeating( + [](const ZipParams* const params, const base::FilePath& path) -> bool { + return (params->include_hidden_files || !IsHiddenFile(path)) && + (!params->filter_callback || + params->filter_callback.Run(params->src_dir.Append(path))); + }, + ¶ms)); + + if (params.src_files.empty()) { + // No source items are specified. Zip the entire source directory. + zip_writer->SetRecursive(true); + if (!zip_writer->AddDirectoryContents(base::FilePath())) + return false; + } else { + // Only zip the specified source items. + if (!zip_writer->AddMixedEntries(params.src_files)) + return false; + } + + return zip_writer->Close(); } -bool UnzipWithFilterCallback(const base::FilePath& src_file, - const base::FilePath& dest_dir, - const FilterCallback& filter_cb, - bool log_skipped_files) { +bool Unzip(const base::FilePath& src_file, + const base::FilePath& dest_dir, + UnzipOptions options) { base::File file(src_file, base::File::FLAG_OPEN | base::File::FLAG_READ); if (!file.IsValid()) { - DLOG(WARNING) << "Failed to open " << src_file.value(); + PLOG(ERROR) << "Cannot open " << Redact(src_file) << ": " + << base::File::ErrorToString(file.error_details()); return false; } - return UnzipWithFilterAndWriters( - file.GetPlatformFile(), - base::BindRepeating(&CreateFilePathWriterDelegate, dest_dir), - base::BindRepeating(&CreateDirectory, dest_dir), filter_cb, - log_skipped_files); + + DLOG_IF(WARNING, !base::IsDirectoryEmpty(dest_dir)) + << "ZIP extraction directory is not empty: " << dest_dir; + + return Unzip(file.GetPlatformFile(), + base::BindRepeating(&CreateFilePathWriterDelegate, dest_dir), + base::BindRepeating(&CreateDirectory, dest_dir), + std::move(options)); } -bool UnzipWithFilterAndWriters(const base::PlatformFile& src_file, - const WriterFactory& writer_factory, - const DirectoryCreator& directory_creator, - const FilterCallback& filter_cb, - bool log_skipped_files) { +bool Unzip(const base::PlatformFile& src_file, + WriterFactory writer_factory, + DirectoryCreator directory_creator, + UnzipOptions options) { ZipReader reader; + reader.SetEncoding(std::move(options.encoding)); + reader.SetPassword(std::move(options.password)); + if (!reader.OpenFromPlatformFile(src_file)) { - DLOG(WARNING) << "Failed to open src_file " << src_file; + LOG(ERROR) << "Cannot open ZIP from file handle " << src_file; return false; } - while (reader.HasMore()) { - if (!reader.OpenCurrentEntryInZip()) { - DLOG(WARNING) << "Failed to open the current file in zip"; - return false; + + while (const ZipReader::Entry* const entry = reader.Next()) { + if (entry->is_unsafe) { + LOG(ERROR) << "Found unsafe entry " << Redact(entry->path) << " in ZIP"; + if (!options.continue_on_error) + return false; + continue; } - const base::FilePath& entry_path = reader.current_entry_info()->file_path(); - if (reader.current_entry_info()->is_unsafe()) { - DLOG(WARNING) << "Found an unsafe file in zip " << entry_path; - return false; + + if (options.filter && !options.filter.Run(entry->path)) { + VLOG(1) << "Skipped ZIP entry " << Redact(entry->path); + continue; } - if (filter_cb.Run(entry_path)) { - if (reader.current_entry_info()->is_directory()) { - if (!directory_creator.Run(entry_path)) - return false; - } else { - std::unique_ptr<WriterDelegate> writer = writer_factory.Run(entry_path); - if (!reader.ExtractCurrentEntry(writer.get(), - std::numeric_limits<uint64_t>::max())) { - DLOG(WARNING) << "Failed to extract " << entry_path; + + if (entry->is_directory) { + // It's a directory. + if (!directory_creator.Run(entry->path)) { + LOG(ERROR) << "Cannot create directory " << Redact(entry->path); + if (!options.continue_on_error) return false; - } } - } else if (log_skipped_files) { - DLOG(WARNING) << "Skipped file " << entry_path; + + continue; } - if (!reader.AdvanceToNextEntry()) { - DLOG(WARNING) << "Failed to advance to the next file"; - return false; + // It's a file. + std::unique_ptr<WriterDelegate> writer = writer_factory.Run(entry->path); + if (!writer || !reader.ExtractCurrentEntry(writer.get())) { + LOG(ERROR) << "Cannot extract file " << Redact(entry->path) + << " from ZIP"; + if (!options.continue_on_error) + return false; } } - return true; + + return reader.ok(); } bool ZipWithFilterCallback(const base::FilePath& src_dir, const base::FilePath& dest_file, - const FilterCallback& filter_cb) { + FilterCallback filter) { DCHECK(base::DirectoryExists(src_dir)); - ZipParams params(src_dir, dest_file); - params.set_filter_callback(filter_cb); - return Zip(params); + return Zip({.src_dir = src_dir, + .dest_file = dest_file, + .filter_callback = std::move(filter)}); } -bool Zip(const base::FilePath& src_dir, const base::FilePath& dest_file, +bool Zip(const base::FilePath& src_dir, + const base::FilePath& dest_file, bool include_hidden_files) { - if (include_hidden_files) { - return ZipWithFilterCallback(src_dir, dest_file, - base::BindRepeating(&ExcludeNoFilesFilter)); - } else { - return ZipWithFilterCallback( - src_dir, dest_file, base::BindRepeating(&ExcludeHiddenFilesFilter)); - } + return Zip({.src_dir = src_dir, + .dest_file = dest_file, + .include_hidden_files = include_hidden_files}); } -#if defined(OS_POSIX) +#if defined(OS_POSIX) || defined(OS_FUCHSIA) bool ZipFiles(const base::FilePath& src_dir, - const std::vector<base::FilePath>& src_relative_paths, + Paths src_relative_paths, int dest_fd) { DCHECK(base::DirectoryExists(src_dir)); - ZipParams params(src_dir, dest_fd); - params.set_files_to_zip(src_relative_paths); - return Zip(params); + return Zip({.src_dir = src_dir, + .dest_fd = dest_fd, + .src_files = src_relative_paths}); } -#endif // defined(OS_POSIX) +#endif // defined(OS_POSIX) || defined(OS_FUCHSIA) } // namespace zip |