summaryrefslogtreecommitdiff
path: root/google/zip.cc
diff options
context:
space:
mode:
Diffstat (limited to 'google/zip.cc')
-rw-r--r--google/zip.cc318
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 = &params.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)));
+ },
+ &params));
+
+ 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