diff options
author | Michaël Zasso <targos@protonmail.com> | 2021-07-14 11:30:07 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2021-07-20 15:24:51 +0200 |
commit | 6cdd310275bb0f8056aa0ae6d95614e9ca5b70c7 (patch) | |
tree | 9ed37b19cd668894854b7f469010f7621e63ef81 /deps/v8/third_party | |
parent | c0f10006c82d2d9896a552de98ed146f9542720d (diff) | |
download | node-new-6cdd310275bb0f8056aa0ae6d95614e9ca5b70c7.tar.gz |
deps: update V8 to 9.2.230.21
PR-URL: https://github.com/nodejs/node/pull/38990
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Diffstat (limited to 'deps/v8/third_party')
22 files changed, 597 insertions, 303 deletions
diff --git a/deps/v8/third_party/google_benchmark/BUILD.gn b/deps/v8/third_party/google_benchmark/BUILD.gn new file mode 100644 index 0000000000..e746cc421a --- /dev/null +++ b/deps/v8/third_party/google_benchmark/BUILD.gn @@ -0,0 +1,75 @@ +# Copyright 2020 The V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/gclient_args.gni") +import("../../gni/v8.gni") + +if (v8_enable_google_benchmark) { + config("benchmark_config") { + include_dirs = [ "src/include" ] + } + + source_set("google_benchmark") { + testonly = true + + public = [ "src/include/benchmark/benchmark.h" ] + + sources = [ + "src/src/arraysize.h", + "src/src/benchmark.cc", + "src/src/benchmark_api_internal.cc", + "src/src/benchmark_api_internal.h", + "src/src/benchmark_name.cc", + "src/src/benchmark_register.cc", + "src/src/benchmark_register.h", + "src/src/benchmark_runner.cc", + "src/src/benchmark_runner.h", + "src/src/check.h", + "src/src/colorprint.cc", + "src/src/colorprint.h", + "src/src/commandlineflags.cc", + "src/src/commandlineflags.h", + "src/src/complexity.cc", + "src/src/complexity.h", + "src/src/console_reporter.cc", + "src/src/counter.cc", + "src/src/counter.h", + "src/src/csv_reporter.cc", + "src/src/internal_macros.h", + "src/src/json_reporter.cc", + "src/src/log.h", + "src/src/mutex.h", + "src/src/perf_counters.cc", + "src/src/perf_counters.h", + "src/src/re.h", + "src/src/reporter.cc", + "src/src/sleep.cc", + "src/src/sleep.h", + "src/src/statistics.cc", + "src/src/statistics.h", + "src/src/string_util.cc", + "src/src/string_util.h", + "src/src/sysinfo.cc", + "src/src/thread_manager.h", + "src/src/thread_timer.h", + "src/src/timers.cc", + "src/src/timers.h", + ] + + all_dependent_configs = [ ":benchmark_config" ] + + defines = [ + # Tell google_benchmark to always use standard regular expressions. + "HAVE_GNU_POSIX_REGEX=0", + "HAVE_POSIX_REGEX=0", + "HAVE_STD_REGEX=1", + ] + } + + source_set("benchmark_main") { + testonly = true + sources = [ "src/src/benchmark_main.cc" ] + public_deps = [ ":google_benchmark" ] + } +} diff --git a/deps/v8/third_party/google_benchmark/OWNERS b/deps/v8/third_party/google_benchmark/OWNERS new file mode 100644 index 0000000000..d934f47fe1 --- /dev/null +++ b/deps/v8/third_party/google_benchmark/OWNERS @@ -0,0 +1,3 @@ +file:../../INFRA_OWNERS + +mlippautz@chromium.org diff --git a/deps/v8/third_party/google_benchmark/README.v8 b/deps/v8/third_party/google_benchmark/README.v8 new file mode 100644 index 0000000000..fe2ac187ac --- /dev/null +++ b/deps/v8/third_party/google_benchmark/README.v8 @@ -0,0 +1,21 @@ +Name: Google Benchmark +Short Name: benchmark +URL: https://github.com/google/benchmark +Version: unknown +License: Apache 2.0 +License File: NOT_SHIPPED +Security Critical: no + +Description: +A microbenchmark support library. + +To include this library in the V8 checkout, add the following clause to +your .gclient configuration. + + "custom_vars": { + "checkout_google_benchmark": True, + } + + +Local Additions: +* gn file for building in V8 diff --git a/deps/v8/third_party/googletest/BUILD.gn b/deps/v8/third_party/googletest/BUILD.gn index cfa9205547..4d393efd95 100644 --- a/deps/v8/third_party/googletest/BUILD.gn +++ b/deps/v8/third_party/googletest/BUILD.gn @@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("../../gni/v8.gni") + config("gtest_config") { visibility = [ ":*" ] # gmock also shares this config. @@ -49,8 +51,6 @@ config("gmock_config") { source_set("gtest") { testonly = true sources = [ - # TODO(crbug.com/829773): Remove this after transitioning off <tr1/tuple>. - "custom/gmock/internal/custom/gmock-port.h", "src/googletest/include/gtest/gtest-death-test.h", "src/googletest/include/gtest/gtest-matchers.h", "src/googletest/include/gtest/gtest-message.h", @@ -64,12 +64,9 @@ source_set("gtest") { "src/googletest/include/gtest/internal/gtest-death-test-internal.h", "src/googletest/include/gtest/internal/gtest-filepath.h", "src/googletest/include/gtest/internal/gtest-internal.h", - "src/googletest/include/gtest/internal/gtest-linked_ptr.h", - "src/googletest/include/gtest/internal/gtest-param-util-generated.h", "src/googletest/include/gtest/internal/gtest-param-util.h", "src/googletest/include/gtest/internal/gtest-port.h", "src/googletest/include/gtest/internal/gtest-string.h", - "src/googletest/include/gtest/internal/gtest-tuple.h", "src/googletest/include/gtest/internal/gtest-type-util.h", #"src/googletest/src/gtest-all.cc", # Not needed by our build. @@ -92,6 +89,15 @@ source_set("gtest") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] + # V8-only workaround for http://crbug.com/chromium/1191946. Ensures that + # googletest is compiled with the same visibility such as the rest of V8, see + # https://source.chromium.org/chromium/chromium/src/+/master:v8/gni/v8.gni + if ((is_posix || is_fuchsia) && + (v8_enable_backtrace || v8_monolithic || v8_expose_symbols)) { + configs -= [ "//build/config/gcc:symbol_visibility_hidden" ] + configs += [ "//build/config/gcc:symbol_visibility_default" ] + } + deps = [] if (is_fuchsia) { @@ -118,22 +124,16 @@ source_set("gmock") { "src/googlemock/include/gmock/gmock-actions.h", "src/googlemock/include/gmock/gmock-cardinalities.h", "src/googlemock/include/gmock/gmock-function-mocker.h", - "src/googlemock/include/gmock/gmock-generated-actions.h", - "src/googlemock/include/gmock/gmock-generated-nice-strict.h", "src/googlemock/include/gmock/gmock-matchers.h", "src/googlemock/include/gmock/gmock-more-actions.h", "src/googlemock/include/gmock/gmock-more-matchers.h", "src/googlemock/include/gmock/gmock-nice-strict.h", "src/googlemock/include/gmock/gmock-spec-builders.h", "src/googlemock/include/gmock/gmock.h", - "src/googlemock/include/gmock/internal/gmock-generated-internal-utils.h", "src/googlemock/include/gmock/internal/gmock-internal-utils.h", "src/googlemock/include/gmock/internal/gmock-port.h", "src/googlemock/include/gmock/internal/gmock-pp.h", - # gmock helpers. - "custom/gmock/internal/custom/gmock-port.h", - #"src/googlemock/src/gmock-all.cc", # Not needed by our build. "src/googlemock/src/gmock-cardinalities.cc", "src/googlemock/src/gmock-internal-utils.cc", @@ -142,10 +142,21 @@ source_set("gmock") { "src/googlemock/src/gmock.cc", ] + # V8-only workaround for http://crbug.com/chromium/1191946. Ensures that + # googletest is compiled with the same visibility such as the rest of V8, see + # https://source.chromium.org/chromium/chromium/src/+/master:v8/gni/v8.gni + if ((is_posix || is_fuchsia) && + (v8_enable_backtrace || v8_monolithic || v8_expose_symbols)) { + configs -= [ "//build/config/gcc:symbol_visibility_hidden" ] + configs += [ "//build/config/gcc:symbol_visibility_default" ] + } + public_configs = [ ":gmock_config", ":gtest_config", ] + + deps = [ ":gtest" ] } # Do NOT depend on this directly. Use //testing/gmock:gmock_main instead. @@ -153,5 +164,8 @@ source_set("gmock") { static_library("gmock_main") { testonly = true sources = [ "src/googlemock/src/gmock_main.cc" ] - deps = [ ":gmock" ] + deps = [ + ":gmock", + ":gtest", + ] } diff --git a/deps/v8/third_party/googletest/src/googletest/include/gtest/gtest_prod.h b/deps/v8/third_party/googletest/src/googletest/include/gtest/gtest_prod.h index e651671ebd..38b9d85a51 100644 --- a/deps/v8/third_party/googletest/src/googletest/include/gtest/gtest_prod.h +++ b/deps/v8/third_party/googletest/src/googletest/include/gtest/gtest_prod.h @@ -31,8 +31,8 @@ // Google C++ Testing and Mocking Framework definitions useful in production code. // GOOGLETEST_CM0003 DO NOT DELETE -#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_ // When you need to test the private or protected members of a class, // use the FRIEND_TEST macro to declare your tests as friends of the @@ -58,4 +58,4 @@ #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test -#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_ diff --git a/deps/v8/third_party/inspector_protocol/BUILD.gn b/deps/v8/third_party/inspector_protocol/BUILD.gn index 880b651c09..94b7fe2677 100644 --- a/deps/v8/third_party/inspector_protocol/BUILD.gn +++ b/deps/v8/third_party/inspector_protocol/BUILD.gn @@ -5,7 +5,10 @@ import("../../gni/v8.gni") config("crdtp_config") { - visibility = [ "../../src/inspector:*", ":*" ] + visibility = [ + ":*", + "../../src/inspector:*", + ] configs = [ "../../:internal_config" ] include_dirs = [ "../../include" ] } @@ -46,6 +49,7 @@ v8_source_set("crdtp_platform") { "crdtp/json_platform_v8.cc", ] public_deps = [ "../..:v8_libbase" ] + deps = [ "../../:v8_internal_headers" ] configs = [ ":crdtp_config" ] } diff --git a/deps/v8/third_party/inspector_protocol/README.v8 b/deps/v8/third_party/inspector_protocol/README.v8 index 97bc1c3414..cc5e083c6a 100644 --- a/deps/v8/third_party/inspector_protocol/README.v8 +++ b/deps/v8/third_party/inspector_protocol/README.v8 @@ -2,7 +2,7 @@ Name: inspector protocol Short Name: inspector_protocol URL: https://chromium.googlesource.com/deps/inspector_protocol/ Version: 0 -Revision: 94298cef795ec994106bdaff002c41182911b767 +Revision: 35e8d2d89cb017d72cf905362672de77c978e1e6 License: BSD License File: LICENSE Security Critical: no diff --git a/deps/v8/third_party/inspector_protocol/crdtp/serializable.cc b/deps/v8/third_party/inspector_protocol/crdtp/serializable.cc index 20de53ecc0..7a21ffd35f 100644 --- a/deps/v8/third_party/inspector_protocol/crdtp/serializable.cc +++ b/deps/v8/third_party/inspector_protocol/crdtp/serializable.cc @@ -4,6 +4,8 @@ #include "serializable.h" +#include <utility> + namespace v8_crdtp { // ============================================================================= // Serializable - An object to be emitted as a sequence of bytes. @@ -18,7 +20,8 @@ std::vector<uint8_t> Serializable::Serialize() const { namespace { class PreSerialized : public Serializable { public: - explicit PreSerialized(std::vector<uint8_t> bytes) : bytes_(bytes) {} + explicit PreSerialized(std::vector<uint8_t> bytes) + : bytes_(std::move(bytes)) {} void AppendSerialized(std::vector<uint8_t>* out) const override { out->insert(out->end(), bytes_.begin(), bytes_.end()); diff --git a/deps/v8/third_party/inspector_protocol/crdtp/status.cc b/deps/v8/third_party/inspector_protocol/crdtp/status.cc index 4a8e03d389..7181df97d1 100644 --- a/deps/v8/third_party/inspector_protocol/crdtp/status.cc +++ b/deps/v8/third_party/inspector_protocol/crdtp/status.cc @@ -113,6 +113,8 @@ std::string Status::Message() const { return "BINDINGS: string8 value expected"; case Error::BINDINGS_BINARY_VALUE_EXPECTED: return "BINDINGS: binary value expected"; + case Error::BINDINGS_DICTIONARY_VALUE_EXPECTED: + return "BINDINGS: dictionary value expected"; } // Some compilers can't figure out that we can't get here. return "INVALID ERROR CODE"; diff --git a/deps/v8/third_party/inspector_protocol/crdtp/status.h b/deps/v8/third_party/inspector_protocol/crdtp/status.h index 45e0a57acf..1039156942 100644 --- a/deps/v8/third_party/inspector_protocol/crdtp/status.h +++ b/deps/v8/third_party/inspector_protocol/crdtp/status.h @@ -77,6 +77,7 @@ enum class Error { BINDINGS_STRING_VALUE_EXPECTED = 0x34, BINDINGS_STRING8_VALUE_EXPECTED = 0x35, BINDINGS_BINARY_VALUE_EXPECTED = 0x36, + BINDINGS_DICTIONARY_VALUE_EXPECTED = 0x37, }; // A status value with position that can be copied. The default status diff --git a/deps/v8/third_party/inspector_protocol/lib/ValueConversions_cpp.template b/deps/v8/third_party/inspector_protocol/lib/ValueConversions_cpp.template index 36c8dcc356..a16b522c38 100644 --- a/deps/v8/third_party/inspector_protocol/lib/ValueConversions_cpp.template +++ b/deps/v8/third_party/inspector_protocol/lib/ValueConversions_cpp.template @@ -96,6 +96,10 @@ bool ProtocolTypeTraits<std::unique_ptr<DictionaryValue>>::Deserialize( std::unique_ptr<Value> res; if (!ProtocolTypeTraits<std::unique_ptr<Value>>::Deserialize(state, &res)) return false; + if (res->type() != Value::TypeObject) { + state->RegisterError(Error::BINDINGS_DICTIONARY_VALUE_EXPECTED); + return false; + } *value = DictionaryValue::cast(std::move(res)); return true; } diff --git a/deps/v8/third_party/inspector_protocol/lib/base_string_adapter_cc.template b/deps/v8/third_party/inspector_protocol/lib/base_string_adapter_cc.template index e503f5c23e..10488f2243 100644 --- a/deps/v8/third_party/inspector_protocol/lib/base_string_adapter_cc.template +++ b/deps/v8/third_party/inspector_protocol/lib/base_string_adapter_cc.template @@ -11,7 +11,6 @@ #include "base/base64.h" #include "base/json/json_reader.h" #include "base/memory/ptr_util.h" -#include "base/strings/string16.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" @@ -141,7 +140,7 @@ std::unique_ptr<base::Value> toBaseValue(Value* value, int depth) { // static String StringUtil::fromUTF16LE(const uint16_t* data, size_t length) { std::string utf8; - base::UTF16ToUTF8(reinterpret_cast<const base::char16*>(data), length, &utf8); + base::UTF16ToUTF8(reinterpret_cast<const char16_t*>(data), length, &utf8); return utf8; } @@ -246,4 +245,4 @@ void ProtocolTypeTraits<Binary>::Serialize(const Binary& value, std::vector<uint value.AppendSerialized(bytes); } -} // namespace {{config.crdtp.namespace}}
\ No newline at end of file +} // namespace {{config.crdtp.namespace}} diff --git a/deps/v8/third_party/inspector_protocol/pdl.py b/deps/v8/third_party/inspector_protocol/pdl.py index d7733634e5..9a9fec9898 100644 --- a/deps/v8/third_party/inspector_protocol/pdl.py +++ b/deps/v8/third_party/inspector_protocol/pdl.py @@ -27,6 +27,9 @@ def assignType(item, type, is_array=False, map_binary_to_string=False): type = 'string' if map_binary_to_string and type == 'binary': type = 'string' + if 'description' in item: + item['description'] = (item['description'] + + ' (Encoded as a base64 string when passed over JSON)') if type in primitiveTypes: item['type'] = type else: diff --git a/deps/v8/third_party/jsoncpp/BUILD.gn b/deps/v8/third_party/jsoncpp/BUILD.gn index 411d2d62e7..6324be019c 100644 --- a/deps/v8/third_party/jsoncpp/BUILD.gn +++ b/deps/v8/third_party/jsoncpp/BUILD.gn @@ -21,9 +21,7 @@ source_set("jsoncpp") { sources = [ "generated/version.h", "source/include/json/assertions.h", - "source/include/json/autolink.h", "source/include/json/config.h", - "source/include/json/features.h", "source/include/json/forwards.h", "source/include/json/json.h", "source/include/json/reader.h", diff --git a/deps/v8/third_party/zlib/OWNERS b/deps/v8/third_party/zlib/OWNERS index 632b3f9f43..0bfa9fb9dd 100644 --- a/deps/v8/third_party/zlib/OWNERS +++ b/deps/v8/third_party/zlib/OWNERS @@ -2,4 +2,5 @@ agl@chromium.org cavalcantii@chromium.org cblume@chromium.org mtklein@google.com +noel@chromium.org scroggo@google.com diff --git a/deps/v8/third_party/zlib/google/OWNERS b/deps/v8/third_party/zlib/google/OWNERS index 868af3cc66..411670ca13 100644 --- a/deps/v8/third_party/zlib/google/OWNERS +++ b/deps/v8/third_party/zlib/google/OWNERS @@ -1,3 +1,5 @@ +fdegros@chromium.org +noel@chromium.org satorux@chromium.org # compression_utils* diff --git a/deps/v8/third_party/zlib/google/zip.cc b/deps/v8/third_party/zlib/google/zip.cc index 907e5da72e..20cdd57bdf 100644 --- a/deps/v8/third_party/zlib/google/zip.cc +++ b/deps/v8/third_party/zlib/google/zip.cc @@ -4,7 +4,7 @@ #include "third_party/zlib/google/zip.h" -#include <list> +#include <queue> #include <string> #include <vector> @@ -50,12 +50,12 @@ std::unique_ptr<WriterDelegate> CreateFilePathWriterDelegate( class DirectFileAccessor : public FileAccessor { public: - explicit DirectFileAccessor(base::FilePath src_dir) : src_dir_(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)) { @@ -63,6 +63,7 @@ class DirectFileAccessor : public FileAccessor { } files.push_back(std::move(file)); } + return files; } @@ -73,103 +74,91 @@ class DirectFileAccessor : public FileAccessor { std::vector<DirectoryContentEntry> ListDirectoryContent( const base::FilePath& dir) override { std::vector<DirectoryContentEntry> files; + base::FileEnumerator file_enumerator( dir, false /* recursive */, base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); - for (base::FilePath path = file_enumerator.Next(); !path.value().empty(); + for (base::FilePath path = file_enumerator.Next(); !path.empty(); path = file_enumerator.Next()) { - files.push_back(DirectoryContentEntry(path, base::DirectoryExists(path))); + const bool is_directory = base::DirectoryExists(path); + files.push_back({std::move(path), is_directory}); } + return files; } base::Time GetLastModifiedTime(const base::FilePath& path) override { base::File::Info file_info; if (!base::GetFileInfo(path, &file_info)) { - LOG(ERROR) << "Failed to retrieve file modification time for " - << path.value(); + LOG(ERROR) << "Cannot get modification time for '" << path << "'"; } return file_info.last_modified; } - - private: - base::FilePath src_dir_; - - DISALLOW_COPY_AND_ASSIGN(DirectFileAccessor); }; } // 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"; +} 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; - } + DirectFileAccessor default_accessor; + FileAccessor* const file_accessor = params.file_accessor ?: &default_accessor; + + Paths files_to_add = params.src_files; - 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); + std::vector<base::FilePath> all_files; + if (files_to_add.empty()) { + // Perform a Breadth First Search (BFS) of the source tree. Note that the + // BFS order might not be optimal when storing files in a ZIP (either for + // the storing side, or for the program that will extract this ZIP). + for (std::queue<base::FilePath> q({params.src_dir}); !q.empty(); q.pop()) { + for (FileAccessor::DirectoryContentEntry& entry : + file_accessor->ListDirectoryContent(q.front())) { + // Skip hidden and filtered files. + if ((!params.include_hidden_files && IsHiddenFile(entry.path)) || + (params.filter_callback && !params.filter_callback.Run(entry.path))) + continue; + + // Store relative path. + all_files.emplace_back(); + const bool success = + params.src_dir.AppendRelativePath(entry.path, &all_files.back()); 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()); + if (entry.is_directory) + q.push(std::move(entry.path)); } } + + files_to_add = all_files; } std::unique_ptr<internal::ZipWriter> zip_writer; + #if defined(OS_POSIX) - if (params.dest_fd() != base::kInvalidPlatformFile) { - DCHECK(params.dest_file().empty()); + 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()); + params.dest_fd, params.src_dir, 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, params.src_dir, + file_accessor); if (!zip_writer) return false; } - return zip_writer->WriteEntries(*files_to_add); + + zip_writer->SetProgressCallback(params.progress_callback, + params.progress_period); + + return zip_writer->WriteEntries(files_to_add); } bool Unzip(const base::FilePath& src_file, const base::FilePath& dest_dir) { @@ -179,7 +168,7 @@ bool Unzip(const base::FilePath& src_file, const base::FilePath& dest_dir) { bool UnzipWithFilterCallback(const base::FilePath& src_file, const base::FilePath& dest_dir, - const FilterCallback& filter_cb, + FilterCallback filter_cb, bool log_skipped_files) { base::File file(src_file, base::File::FLAG_OPEN | base::File::FLAG_READ); if (!file.IsValid()) { @@ -189,14 +178,14 @@ bool UnzipWithFilterCallback(const base::FilePath& src_file, return UnzipWithFilterAndWriters( file.GetPlatformFile(), base::BindRepeating(&CreateFilePathWriterDelegate, dest_dir), - base::BindRepeating(&CreateDirectory, dest_dir), filter_cb, + base::BindRepeating(&CreateDirectory, dest_dir), std::move(filter_cb), log_skipped_files); } bool UnzipWithFilterAndWriters(const base::PlatformFile& src_file, - const WriterFactory& writer_factory, - const DirectoryCreator& directory_creator, - const FilterCallback& filter_cb, + WriterFactory writer_factory, + DirectoryCreator directory_creator, + FilterCallback filter_cb, bool log_skipped_files) { ZipReader reader; if (!reader.OpenFromPlatformFile(src_file)) { @@ -239,14 +228,15 @@ bool UnzipWithFilterAndWriters(const base::PlatformFile& src_file, bool ZipWithFilterCallback(const base::FilePath& src_dir, const base::FilePath& dest_file, - const FilterCallback& filter_cb) { + FilterCallback filter_cb) { 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_cb)}); } -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, @@ -259,12 +249,12 @@ bool Zip(const base::FilePath& src_dir, const base::FilePath& dest_file, #if defined(OS_POSIX) 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) diff --git a/deps/v8/third_party/zlib/google/zip.h b/deps/v8/third_party/zlib/google/zip.h index 4f64a8aca8..ecd7ba02b4 100644 --- a/deps/v8/third_party/zlib/google/zip.h +++ b/deps/v8/third_party/zlib/google/zip.h @@ -5,9 +5,13 @@ #ifndef THIRD_PARTY_ZLIB_GOOGLE_ZIP_H_ #define THIRD_PARTY_ZLIB_GOOGLE_ZIP_H_ +#include <cstdint> +#include <ostream> +#include <utility> #include <vector> #include "base/callback.h" +#include "base/containers/span.h" #include "base/files/file_path.h" #include "base/files/platform_file.h" #include "base/time/time.h" @@ -31,8 +35,6 @@ class FileAccessor { virtual ~FileAccessor() = default; struct DirectoryContentEntry { - DirectoryContentEntry(const base::FilePath& path, bool is_directory) - : path(path), is_directory(is_directory) {} base::FilePath path; bool is_directory = false; }; @@ -48,72 +50,75 @@ class FileAccessor { virtual base::Time GetLastModifiedTime(const base::FilePath& path) = 0; }; -class ZipParams { - public: - ZipParams(const base::FilePath& src_dir, const base::FilePath& dest_file); -#if defined(OS_POSIX) - // Does not take ownership of |dest_fd|. - ZipParams(const base::FilePath& src_dir, int dest_fd); +// Progress of a ZIP creation operation. +struct Progress { + // Total number of bytes read from files getting zipped so far. + std::int64_t bytes = 0; - int dest_fd() const { return dest_fd_; } -#endif + // Number of file entries added to the ZIP so far. + // A file entry is added after its bytes have been processed. + int files = 0; + + // Number of directory entries added to the ZIP so far. + // A directory entry is added before items in it. + int directories = 0; +}; + +// Prints Progress to output stream. +std::ostream& operator<<(std::ostream& out, const Progress& progress); + +// Callback reporting the progress of a ZIP creation operation. +// +// This callback returns a boolean indicating whether the ZIP creation operation +// should continue. If it returns false once, then the ZIP creation operation is +// immediately cancelled and the callback won't be called again. +using ProgressCallback = base::RepeatingCallback<bool(const Progress&)>; + +using FilterCallback = base::RepeatingCallback<bool(const base::FilePath&)>; + +using Paths = base::span<const base::FilePath>; + +// ZIP creation parameters and options. +struct ZipParams { + // Source directory. + base::FilePath src_dir; + + // Destination file path. + // Either dest_file or dest_fd should be set, but not both. + base::FilePath dest_file; - const base::FilePath& src_dir() const { return src_dir_; } - - const base::FilePath& dest_file() const { return dest_file_; } - - // Restricts the files actually zipped to the paths listed in - // |src_relative_paths|. They must be relative to the |src_dir| passed in the - // constructor and will be used as the file names in the created zip file. All - // source paths must be under |src_dir| in the file system hierarchy. - void set_files_to_zip(const std::vector<base::FilePath>& src_relative_paths) { - src_files_ = src_relative_paths; - } - const std::vector<base::FilePath>& files_to_zip() const { return src_files_; } - - using FilterCallback = base::RepeatingCallback<bool(const base::FilePath&)>; - void set_filter_callback(FilterCallback filter_callback) { - filter_callback_ = filter_callback; - } - const FilterCallback& filter_callback() const { return filter_callback_; } - - void set_include_hidden_files(bool include_hidden_files) { - include_hidden_files_ = include_hidden_files; - } - bool include_hidden_files() const { return include_hidden_files_; } - - // Sets a custom file accessor for file operations. Default is to directly - // access the files (with fopen and the rest). - // Useful in cases where running in a sandbox process and file access has to - // go through IPC, for example. - void set_file_accessor(std::unique_ptr<FileAccessor> file_accessor) { - file_accessor_ = std::move(file_accessor); - } - FileAccessor* file_accessor() const { return file_accessor_.get(); } - - private: - base::FilePath src_dir_; - - base::FilePath dest_file_; #if defined(OS_POSIX) - int dest_fd_ = base::kInvalidPlatformFile; + // Destination file passed a file descriptor. + // Either dest_file or dest_fd should be set, but not both. + int dest_fd = base::kInvalidPlatformFile; #endif - // The relative paths to the files that should be included in the zip file. If - // this is empty, all files in |src_dir_| are included. - std::vector<base::FilePath> src_files_; + // The relative paths to the files that should be included in the ZIP file. If + // this is empty, all files in |src_dir| are included. + // + // These paths must be relative to |src_dir| and will be used as the file + // names in the created zip file. All files must be under |src_dir| in the + // file system hierarchy. + Paths src_files; // Filter used to exclude files from the ZIP file. Only effective when - // |src_files_| is empty. - FilterCallback filter_callback_; + // |src_files| is empty. + FilterCallback filter_callback; + + // Optional progress reporting callback. + ProgressCallback progress_callback; + + // Progress reporting period. The final callback is always called when the ZIP + // creation operation completes. + base::TimeDelta progress_period; // Whether hidden files should be included in the ZIP file. Only effective - // when |src_files_| is empty. - bool include_hidden_files_ = true; + // when |src_files| is empty. + bool include_hidden_files = true; - // Abstraction around file system access used to read files. An implementation - // that accesses files directly is provided by default. - std::unique_ptr<FileAccessor> file_accessor_; + // Abstraction around file system access used to read files. If left null, an + // implementation that accesses files directly is used. + FileAccessor* file_accessor = nullptr; // Not owned }; // Zip files specified into a ZIP archives. The source files and ZIP destination @@ -125,15 +130,15 @@ bool Zip(const ZipParams& params); // of src_dir will be at the root level of the created zip. For each file in // src_dir, include it only if the callback |filter_cb| returns true. Otherwise // omit it. -using FilterCallback = base::RepeatingCallback<bool(const base::FilePath&)>; bool ZipWithFilterCallback(const base::FilePath& src_dir, const base::FilePath& dest_file, - const FilterCallback& filter_cb); + FilterCallback filter_cb); // Convenience method for callers who don't need to set up the filter callback. // If |include_hidden_files| is true, files starting with "." are included. // Otherwise they are omitted. -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 defined(OS_POSIX) @@ -143,7 +148,7 @@ bool Zip(const base::FilePath& src_dir, const base::FilePath& dest_file, // file names in the created zip file. All source paths must be under |src_dir| // in the file system hierarchy. bool ZipFiles(const base::FilePath& src_dir, - const std::vector<base::FilePath>& src_relative_paths, + Paths src_relative_paths, int dest_fd); #endif // defined(OS_POSIX) @@ -152,10 +157,9 @@ bool ZipFiles(const base::FilePath& src_dir, // returns true. Otherwise omit it. // If |log_skipped_files| is true, files skipped during extraction are printed // to debug log. -using FilterCallback = base::RepeatingCallback<bool(const base::FilePath&)>; bool UnzipWithFilterCallback(const base::FilePath& zip_file, const base::FilePath& dest_dir, - const FilterCallback& filter_cb, + FilterCallback filter_cb, bool log_skipped_files); // Unzip the contents of zip_file, using the writers provided by writer_factory. @@ -168,9 +172,9 @@ typedef base::RepeatingCallback<std::unique_ptr<WriterDelegate>( WriterFactory; typedef base::RepeatingCallback<bool(const base::FilePath&)> DirectoryCreator; bool UnzipWithFilterAndWriters(const base::PlatformFile& zip_file, - const WriterFactory& writer_factory, - const DirectoryCreator& directory_creator, - const FilterCallback& filter_cb, + WriterFactory writer_factory, + DirectoryCreator directory_creator, + FilterCallback filter_cb, bool log_skipped_files); // Unzip the contents of zip_file into dest_dir. diff --git a/deps/v8/third_party/zlib/google/zip_reader_unittest.cc b/deps/v8/third_party/zlib/google/zip_reader_unittest.cc index bba4365298..44134f886e 100644 --- a/deps/v8/third_party/zlib/google/zip_reader_unittest.cc +++ b/deps/v8/third_party/zlib/google/zip_reader_unittest.cc @@ -20,6 +20,7 @@ #include "base/path_service.h" #include "base/run_loop.h" #include "base/stl_util.h" +#include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/test/task_environment.h" @@ -510,12 +511,12 @@ TEST_F(ZipReaderTest, ExtractCurrentEntryToString) { if (i > 0) { // Exact byte read limit: must pass. EXPECT_TRUE(reader.ExtractCurrentEntryToString(i, &contents)); - EXPECT_EQ(base::StringPiece("0123456", i).as_string(), contents); + EXPECT_EQ(std::string(base::StringPiece("0123456", i)), contents); } // More than necessary byte read limit: must pass. EXPECT_TRUE(reader.ExtractCurrentEntryToString(16, &contents)); - EXPECT_EQ(base::StringPiece("0123456", i).as_string(), contents); + EXPECT_EQ(std::string(base::StringPiece("0123456", i)), contents); } reader.Close(); } diff --git a/deps/v8/third_party/zlib/google/zip_unittest.cc b/deps/v8/third_party/zlib/google/zip_unittest.cc index 10f2ef7a97..cf914d9f06 100644 --- a/deps/v8/third_party/zlib/google/zip_unittest.cc +++ b/deps/v8/third_party/zlib/google/zip_unittest.cc @@ -21,6 +21,7 @@ #include "base/path_service.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/test/bind.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -78,13 +79,10 @@ class VirtualFileSystem : public zip::FileAccessor { DCHECK(success); files_[bar2_txt_path] = std::move(file); - file_tree_[test_dir] = std::vector<DirectoryContentEntry>{ - DirectoryContentEntry(foo_txt_path, /*is_dir=*/false), - DirectoryContentEntry(bar_dir, /*is_dir=*/true)}; - file_tree_[bar_dir] = std::vector<DirectoryContentEntry>{ - DirectoryContentEntry(bar1_txt_path, /*is_dir=*/false), - DirectoryContentEntry(bar2_txt_path, /*is_dir=*/false)}; + file_tree_[test_dir] = {{foo_txt_path, false}, {bar_dir, true}}; + file_tree_[bar_dir] = {{bar1_txt_path, false}, {bar2_txt_path, false}}; } + ~VirtualFileSystem() override = default; private: @@ -108,7 +106,7 @@ class VirtualFileSystem : public zip::FileAccessor { auto iter = file_tree_.find(dir); if (iter == file_tree_.end()) { NOTREACHED(); - return std::vector<DirectoryContentEntry>(); + return {}; } return iter->second; } @@ -131,10 +129,7 @@ constexpr char VirtualFileSystem::kBar2Content[]; // Make the test a PlatformTest to setup autorelease pools properly on Mac. class ZipTest : public PlatformTest { protected: - enum ValidYearType { - VALID_YEAR, - INVALID_YEAR - }; + enum ValidYearType { VALID_YEAR, INVALID_YEAR }; virtual void SetUp() { PlatformTest::SetUp(); @@ -161,20 +156,17 @@ class ZipTest : public PlatformTest { base::FilePath(FILE_PATH_LITERAL("foo/bar/.hidden"))); } - virtual void TearDown() { - PlatformTest::TearDown(); - } + virtual void TearDown() { PlatformTest::TearDown(); } bool GetTestDataDirectory(base::FilePath* path) { bool success = base::PathService::Get(base::DIR_SOURCE_ROOT, path); EXPECT_TRUE(success); if (!success) return false; - *path = path->AppendASCII("third_party"); - *path = path->AppendASCII("zlib"); - *path = path->AppendASCII("google"); - *path = path->AppendASCII("test"); - *path = path->AppendASCII("data"); + for (const base::StringPiece s : + {"third_party", "zlib", "google", "test", "data"}) { + *path = path->AppendASCII(s); + } return true; } @@ -193,7 +185,8 @@ class ZipTest : public PlatformTest { ASSERT_TRUE(GetTestDataDirectory(&original_dir)); original_dir = original_dir.AppendASCII("test"); - base::FileEnumerator files(test_dir_, true, + base::FileEnumerator files( + test_dir_, true, base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); base::FilePath unzipped_entry_path = files.Next(); size_t count = 0; @@ -211,15 +204,19 @@ class ZipTest : public PlatformTest { bool append_relative_path_success = test_dir_.AppendRelativePath(unzipped_entry_path, &relative_path); if (!append_relative_path_success) { - LOG(ERROR) << "Append relative path failed, params: " - << test_dir_.value() << " and " - << unzipped_entry_path.value(); + LOG(ERROR) << "Append relative path failed, params: " << test_dir_ + << " and " << unzipped_entry_path; } base::FilePath original_path = original_dir.Append(relative_path); - LOG(ERROR) << "Comparing original " << original_path.value() - << " and unzipped file " << unzipped_entry_path.value() - << " result: " - << base::ContentsEqual(original_path, unzipped_entry_path); + const bool equal = + base::ContentsEqual(original_path, unzipped_entry_path); + if (equal) { + LOG(INFO) << "Original and unzipped file '" << relative_path + << "' are equal"; + } else { + LOG(ERROR) << "Original and unzipped file '" << relative_path + << "' are different"; + } // EXPECT_TRUE(base::ContentsEqual(original_path, unzipped_entry_path)) // << "Contents differ between original " << original_path.value() // << " and unzipped file " << unzipped_entry_path.value(); @@ -487,8 +484,8 @@ TEST_F(ZipTest, ZipFiles) { base::File zip_file(zip_name, base::File::FLAG_CREATE | base::File::FLAG_WRITE); ASSERT_TRUE(zip_file.IsValid()); - EXPECT_TRUE(zip::ZipFiles(src_dir, zip_file_list_, - zip_file.GetPlatformFile())); + EXPECT_TRUE( + zip::ZipFiles(src_dir, zip_file_list_, zip_file.GetPlatformFile())); zip_file.Close(); zip::ZipReader reader; @@ -524,8 +521,8 @@ TEST_F(ZipTest, UnzipFilesWithIncorrectSize) { for (int i = 0; i < 8; i++) { SCOPED_TRACE(base::StringPrintf("Processing %d.txt", i)); - base::FilePath file_path = temp_dir.AppendASCII( - base::StringPrintf("%d.txt", i)); + base::FilePath file_path = + temp_dir.AppendASCII(base::StringPrintf("%d.txt", i)); int64_t file_size = -1; EXPECT_TRUE(base::GetFileSize(file_path, &file_size)); EXPECT_EQ(static_cast<int64_t>(i), file_size); @@ -535,8 +532,11 @@ TEST_F(ZipTest, UnzipFilesWithIncorrectSize) { TEST_F(ZipTest, ZipWithFileAccessor) { base::FilePath zip_file; ASSERT_TRUE(base::CreateTemporaryFile(&zip_file)); - zip::ZipParams params(base::FilePath(FILE_PATH_LITERAL("/test")), zip_file); - params.set_file_accessor(std::make_unique<VirtualFileSystem>()); + VirtualFileSystem file_accessor; + const zip::ZipParams params{ + .src_dir = base::FilePath(FILE_PATH_LITERAL("/test")), + .dest_file = zip_file, + .file_accessor = &file_accessor}; ASSERT_TRUE(zip::Zip(params)); base::ScopedTempDir scoped_temp_dir; @@ -557,4 +557,125 @@ TEST_F(ZipTest, ZipWithFileAccessor) { EXPECT_EQ(VirtualFileSystem::kBar2Content, file_content); } +// Tests progress reporting while zipping files. +TEST_F(ZipTest, ZipProgress) { + base::FilePath src_dir; + ASSERT_TRUE(GetTestDataDirectory(&src_dir)); + src_dir = src_dir.AppendASCII("test"); + + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + base::FilePath zip_file = temp_dir.GetPath().AppendASCII("out.zip"); + + int progress_count = 0; + zip::Progress last_progress; + + zip::ProgressCallback progress_callback = + base::BindLambdaForTesting([&](const zip::Progress& progress) { + progress_count++; + LOG(INFO) << "Progress #" << progress_count << ": " << progress; + + // Progress should only go forwards. + EXPECT_GE(progress.bytes, last_progress.bytes); + EXPECT_GE(progress.files, last_progress.files); + EXPECT_GE(progress.directories, last_progress.directories); + + last_progress = progress; + return true; + }); + + EXPECT_TRUE(zip::Zip({.src_dir = src_dir, + .dest_file = zip_file, + .progress_callback = std::move(progress_callback)})); + + EXPECT_EQ(progress_count, 14); + EXPECT_EQ(last_progress.bytes, 13546); + EXPECT_EQ(last_progress.files, 5); + EXPECT_EQ(last_progress.directories, 2); + + TestUnzipFile(zip_file, true); +} + +// Tests throttling of progress reporting while zipping files. +TEST_F(ZipTest, ZipProgressPeriod) { + base::FilePath src_dir; + ASSERT_TRUE(GetTestDataDirectory(&src_dir)); + src_dir = src_dir.AppendASCII("test"); + + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + base::FilePath zip_file = temp_dir.GetPath().AppendASCII("out.zip"); + + int progress_count = 0; + zip::Progress last_progress; + + zip::ProgressCallback progress_callback = + base::BindLambdaForTesting([&](const zip::Progress& progress) { + progress_count++; + LOG(INFO) << "Progress #" << progress_count << ": " << progress; + + // Progress should only go forwards. + EXPECT_GE(progress.bytes, last_progress.bytes); + EXPECT_GE(progress.files, last_progress.files); + EXPECT_GE(progress.directories, last_progress.directories); + + last_progress = progress; + return true; + }); + + EXPECT_TRUE(zip::Zip({.src_dir = src_dir, + .dest_file = zip_file, + .progress_callback = std::move(progress_callback), + .progress_period = base::TimeDelta::FromHours(1)})); + + // We expect only 2 progress reports: the first one, and the last one. + EXPECT_EQ(progress_count, 2); + EXPECT_EQ(last_progress.bytes, 13546); + EXPECT_EQ(last_progress.files, 5); + EXPECT_EQ(last_progress.directories, 2); + + TestUnzipFile(zip_file, true); +} + +// Tests cancellation while zipping files. +TEST_F(ZipTest, ZipCancel) { + base::FilePath src_dir; + ASSERT_TRUE(GetTestDataDirectory(&src_dir)); + src_dir = src_dir.AppendASCII("test"); + + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + base::FilePath zip_file = temp_dir.GetPath().AppendASCII("out.zip"); + + // First: establish the number of possible interruption points. + int progress_count = 0; + + EXPECT_TRUE(zip::Zip({.src_dir = src_dir, + .dest_file = zip_file, + .progress_callback = base::BindLambdaForTesting( + [&progress_count](const zip::Progress&) { + progress_count++; + return true; + })})); + + EXPECT_EQ(progress_count, 14); + + // Second: exercise each and every interruption point. + for (int i = progress_count; i > 0; i--) { + int j = 0; + EXPECT_FALSE(zip::Zip({.src_dir = src_dir, + .dest_file = zip_file, + .progress_callback = base::BindLambdaForTesting( + [i, &j](const zip::Progress&) { + j++; + // Callback shouldn't be called again after + // having returned false once. + EXPECT_LE(j, i); + return j < i; + })})); + + EXPECT_EQ(j, i); + } +} + } // namespace diff --git a/deps/v8/third_party/zlib/google/zip_writer.cc b/deps/v8/third_party/zlib/google/zip_writer.cc index 6f38d42b6b..de1930e803 100644 --- a/deps/v8/third_party/zlib/google/zip_writer.cc +++ b/deps/v8/third_party/zlib/google/zip_writer.cc @@ -12,35 +12,51 @@ namespace zip { namespace internal { -namespace { +bool ZipWriter::ShouldContinue() { + if (!progress_callback_) + return true; -// Numbers of pending entries that trigger writting them to the ZIP file. -constexpr size_t kMaxPendingEntriesCount = 50; + const base::TimeTicks now = base::TimeTicks::Now(); + if (next_progress_report_time_ > now) + return true; -bool AddFileContentToZip(zipFile zip_file, - base::File file, - const base::FilePath& file_path) { - int num_bytes; + next_progress_report_time_ = now + progress_period_; + if (progress_callback_.Run(progress_)) + return true; + + LOG(ERROR) << "Cancelling ZIP creation"; + return false; +} + +bool ZipWriter::AddFileContent(const base::FilePath& path, base::File file) { char buf[zip::internal::kZipBufSize]; - do { - num_bytes = file.ReadAtCurrentPos(buf, zip::internal::kZipBufSize); - - if (num_bytes > 0) { - if (zipWriteInFileInZip(zip_file, buf, num_bytes) != ZIP_OK) { - DLOG(ERROR) << "Could not write data to zip for path " - << file_path.value(); - return false; - } + + while (ShouldContinue()) { + const int num_bytes = + file.ReadAtCurrentPos(buf, zip::internal::kZipBufSize); + + if (num_bytes < 0) { + DPLOG(ERROR) << "Cannot read file '" << path << "'"; + return false; } - } while (num_bytes > 0); - return true; + if (num_bytes == 0) + return true; + + if (zipWriteInFileInZip(zip_file_, buf, num_bytes) != ZIP_OK) { + DLOG(ERROR) << "Cannot write data from file '" << path << "' to ZIP"; + return false; + } + + progress_.bytes += num_bytes; + } + + return false; } -bool OpenNewFileEntry(zipFile zip_file, - const base::FilePath& path, - bool is_directory, - base::Time last_modified) { +bool ZipWriter::OpenNewFileEntry(const base::FilePath& path, + bool is_directory, + base::Time last_modified) { std::string str_path = path.AsUTF8Unsafe(); #if defined(OS_WIN) base::ReplaceSubstringsAfterOffset(&str_path, 0u, "\\", "/"); @@ -48,41 +64,33 @@ bool OpenNewFileEntry(zipFile zip_file, if (is_directory) str_path += "/"; - return zip::internal::ZipOpenNewFileInZip(zip_file, str_path, last_modified); + return zip::internal::ZipOpenNewFileInZip(zip_file_, str_path, last_modified); } -bool CloseNewFileEntry(zipFile zip_file) { - return zipCloseFileInZip(zip_file) == ZIP_OK; +bool ZipWriter::CloseNewFileEntry() { + return zipCloseFileInZip(zip_file_) == ZIP_OK; } -bool AddFileEntryToZip(zipFile zip_file, - const base::FilePath& path, - base::File file) { +bool ZipWriter::AddFileEntry(const base::FilePath& path, base::File file) { base::File::Info file_info; if (!file.GetInfo(&file_info)) return false; - if (!OpenNewFileEntry(zip_file, path, /*is_directory=*/false, - file_info.last_modified)) - return false; - - bool success = AddFileContentToZip(zip_file, std::move(file), path); - if (!CloseNewFileEntry(zip_file)) + if (!OpenNewFileEntry(path, /*is_directory=*/false, file_info.last_modified)) return false; - return success; + const bool success = AddFileContent(path, std::move(file)); + progress_.files++; + return CloseNewFileEntry() && success; } -bool AddDirectoryEntryToZip(zipFile zip_file, - const base::FilePath& path, - base::Time last_modified) { - return OpenNewFileEntry(zip_file, path, /*is_directory=*/true, - last_modified) && - CloseNewFileEntry(zip_file); +bool ZipWriter::AddDirectoryEntry(const base::FilePath& path, + base::Time last_modified) { + progress_.directories++; + return OpenNewFileEntry(path, /*is_directory=*/true, last_modified) && + CloseNewFileEntry() && ShouldContinue(); } -} // namespace - #if defined(OS_POSIX) // static std::unique_ptr<ZipWriter> ZipWriter::CreateWithFd( @@ -92,10 +100,12 @@ std::unique_ptr<ZipWriter> ZipWriter::CreateWithFd( DCHECK(zip_file_fd != base::kInvalidPlatformFile); zipFile zip_file = internal::OpenFdForZipping(zip_file_fd, APPEND_STATUS_CREATE); + if (!zip_file) { - DLOG(ERROR) << "Couldn't create ZIP file for FD " << zip_file_fd; + DLOG(ERROR) << "Cannot create ZIP file for FD " << zip_file_fd; return nullptr; } + return std::unique_ptr<ZipWriter>( new ZipWriter(zip_file, root_dir, file_accessor)); } @@ -109,10 +119,12 @@ std::unique_ptr<ZipWriter> ZipWriter::Create( DCHECK(!zip_file_path.empty()); zipFile zip_file = internal::OpenForZipping(zip_file_path.AsUTF8Unsafe(), APPEND_STATUS_CREATE); + if (!zip_file) { - DLOG(ERROR) << "Couldn't create ZIP file at path " << zip_file_path; + DLOG(ERROR) << "Cannot create ZIP file '" << zip_file_path << "'"; return nullptr; } + return std::unique_ptr<ZipWriter>( new ZipWriter(zip_file, root_dir, file_accessor)); } @@ -123,80 +135,83 @@ ZipWriter::ZipWriter(zipFile zip_file, : zip_file_(zip_file), root_dir_(root_dir), file_accessor_(file_accessor) {} ZipWriter::~ZipWriter() { - DCHECK(pending_entries_.empty()); + if (zip_file_) + zipClose(zip_file_, nullptr); } -bool ZipWriter::WriteEntries(const std::vector<base::FilePath>& paths) { +bool ZipWriter::WriteEntries(Paths paths) { return AddEntries(paths) && Close(); } -bool ZipWriter::AddEntries(const std::vector<base::FilePath>& paths) { - DCHECK(zip_file_); - pending_entries_.insert(pending_entries_.end(), paths.begin(), paths.end()); - return FlushEntriesIfNeeded(/*force=*/false); -} - bool ZipWriter::Close() { - bool success = FlushEntriesIfNeeded(/*force=*/true) && - zipClose(zip_file_, nullptr) == ZIP_OK; + const bool success = zipClose(zip_file_, nullptr) == ZIP_OK; zip_file_ = nullptr; + + // Call the progress callback one last time with the final progress status. + if (progress_callback_ && !progress_callback_.Run(progress_)) { + LOG(ERROR) << "Cancelling ZIP creation at the end"; + return false; + } + return success; } -bool ZipWriter::FlushEntriesIfNeeded(bool force) { - if (pending_entries_.size() < kMaxPendingEntriesCount && !force) - return true; - - while (pending_entries_.size() >= kMaxPendingEntriesCount || - (force && !pending_entries_.empty())) { - size_t entry_count = - std::min(pending_entries_.size(), kMaxPendingEntriesCount); - std::vector<base::FilePath> relative_paths; - std::vector<base::FilePath> absolute_paths; - relative_paths.insert(relative_paths.begin(), pending_entries_.begin(), - pending_entries_.begin() + entry_count); - for (auto iter = pending_entries_.begin(); - iter != pending_entries_.begin() + entry_count; ++iter) { - // The FileAccessor requires absolute paths. - absolute_paths.push_back(root_dir_.Append(*iter)); +bool ZipWriter::AddEntries(Paths paths) { + // Constructed outside the loop in order to reuse its internal buffer. + std::vector<base::FilePath> absolute_paths; + + while (!paths.empty()) { + // Work with chunks of 50 paths at most. + const size_t n = std::min<size_t>(paths.size(), 50); + const Paths relative_paths = paths.subspan(0, n); + paths = paths.subspan(n, paths.size() - n); + + // FileAccessor requires absolute paths. + absolute_paths.clear(); + absolute_paths.reserve(n); + for (const base::FilePath& relative_path : relative_paths) { + absolute_paths.push_back(root_dir_.Append(relative_path)); } - pending_entries_.erase(pending_entries_.begin(), - pending_entries_.begin() + entry_count); + + DCHECK_EQ(relative_paths.size(), n); + DCHECK_EQ(absolute_paths.size(), n); // We don't know which paths are files and which ones are directories, and - // we want to avoid making a call to file_accessor_ for each entry. Open the - // files instead, invalid files are returned for directories. + // we want to avoid making a call to file_accessor_ for each entry. Try to + // open all of the paths as files. We'll get invalid file descriptors for + // directories. std::vector<base::File> files = file_accessor_->OpenFilesForReading(absolute_paths); - DCHECK_EQ(files.size(), relative_paths.size()); - for (size_t i = 0; i < files.size(); i++) { + DCHECK_EQ(files.size(), n); + + for (size_t i = 0; i < n; i++) { const base::FilePath& relative_path = relative_paths[i]; const base::FilePath& absolute_path = absolute_paths[i]; - base::File file = std::move(files[i]); + base::File& file = files[i]; + if (file.IsValid()) { - if (!AddFileEntryToZip(zip_file_, relative_path, std::move(file))) { - LOG(ERROR) << "Failed to write file " << relative_path.value() - << " to ZIP file."; + if (!AddFileEntry(relative_path, std::move(file))) { + LOG(ERROR) << "Cannot add file '" << relative_path << "' to ZIP"; return false; } } else { - // Missing file or directory case. - base::Time last_modified = + // Either directory or missing file. + const base::Time last_modified = file_accessor_->GetLastModifiedTime(absolute_path); if (last_modified.is_null()) { - LOG(ERROR) << "Failed to write entry " << relative_path.value() - << " to ZIP file."; + LOG(ERROR) << "Missing file or directory '" << relative_path << "'"; return false; } + DCHECK(file_accessor_->DirectoryExists(absolute_path)); - if (!AddDirectoryEntryToZip(zip_file_, relative_path, last_modified)) { - LOG(ERROR) << "Failed to write directory " << relative_path.value() - << " to ZIP file."; + if (!AddDirectoryEntry(relative_path, last_modified)) { + LOG(ERROR) << "Cannot add directory '" << relative_path << "' to ZIP"; return false; } } } } + return true; } diff --git a/deps/v8/third_party/zlib/google/zip_writer.h b/deps/v8/third_party/zlib/google/zip_writer.h index bd2a727b94..489984f843 100644 --- a/deps/v8/third_party/zlib/google/zip_writer.h +++ b/deps/v8/third_party/zlib/google/zip_writer.h @@ -9,6 +9,7 @@ #include <vector> #include "base/files/file_path.h" +#include "base/time/time.h" #include "build/build_config.h" #include "third_party/zlib/google/zip.h" @@ -31,7 +32,7 @@ namespace internal { class ZipWriter { public: // Creates a writer that will write a ZIP file to |zip_file_fd|/|zip_file| -// and which entries (specifies with AddEntries) are relative to |root_dir|. +// and which entries (specified with WriteEntries) are relative to |root_dir|. // All file reads are performed using |file_accessor|. #if defined(OS_POSIX) static std::unique_ptr<ZipWriter> CreateWithFd(int zip_file_fd, @@ -43,36 +44,56 @@ class ZipWriter { FileAccessor* file_accessor); ~ZipWriter(); - // Writes the files at |paths| to the ZIP file and closes this Zip file. - // Note that the the FilePaths must be relative to |root_dir| specified in the + // Sets the optional progress callback. The callback is called once for each + // time |period|. The final callback is always called when the ZIP operation + // completes. + void SetProgressCallback(ProgressCallback callback, base::TimeDelta period) { + progress_callback_ = std::move(callback); + progress_period_ = std::move(period); + } + + // Writes the files at |paths| to the ZIP file and closes this ZIP file. + // The file paths must be relative to |root_dir| specified in the // Create method. // Returns true if all entries were written successfuly. - bool WriteEntries(const std::vector<base::FilePath>& paths); + bool WriteEntries(Paths paths); private: + // Takes ownership of |zip_file|. ZipWriter(zipFile zip_file, const base::FilePath& root_dir, FileAccessor* file_accessor); - // Writes the pending entries to the ZIP file if there are at least - // |kMaxPendingEntriesCount| of them. If |force| is true, all pending entries - // are written regardless of how many there are. - // Returns false if writing an entry fails, true if no entry was written or - // there was no error writing entries. - bool FlushEntriesIfNeeded(bool force); + // Regularly called during processing to check whether zipping should continue + // or should be cancelled. + bool ShouldContinue(); // Adds the files at |paths| to the ZIP file. These FilePaths must be relative // to |root_dir| specified in the Create method. - bool AddEntries(const std::vector<base::FilePath>& paths); + bool AddEntries(Paths paths); + + // Adds file content to currently open file entry. + bool AddFileContent(const base::FilePath& path, base::File file); + + // Adds a file entry (including file contents). + bool AddFileEntry(const base::FilePath& path, base::File file); + + // Adds a directory entry. + bool AddDirectoryEntry(const base::FilePath& path, base::Time last_modified); + + // Opens a file or directory entry. + bool OpenNewFileEntry(const base::FilePath& path, + bool is_directory, + base::Time last_modified); + + // Closes the currently open entry. + bool CloseNewFileEntry(); // Closes the ZIP file. // Returns true if successful, false otherwise (typically if an entry failed // to be written). bool Close(); - // The entries that have been added but not yet written to the ZIP file. - std::vector<base::FilePath> pending_entries_; - // The actual zip file. zipFile zip_file_; @@ -82,10 +103,22 @@ class ZipWriter { // Abstraction over file access methods used to read files. FileAccessor* file_accessor_; + // Progress stats. + Progress progress_; + + // Optional progress callback. + ProgressCallback progress_callback_; + + // Optional progress reporting period. + base::TimeDelta progress_period_; + + // Next time to report progress. + base::TimeTicks next_progress_report_time_ = base::TimeTicks::Now(); + DISALLOW_COPY_AND_ASSIGN(ZipWriter); }; } // namespace internal } // namespace zip -#endif // THIRD_PARTY_ZLIB_GOOGLE_ZIP_WRITER_H_
\ No newline at end of file +#endif // THIRD_PARTY_ZLIB_GOOGLE_ZIP_WRITER_H_ |