/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/zlib/google/zip.cc
391 строка
12 KB
Node.js GitHub Bot
deps: update zlib to 1.3.1-63d7e16
02 дек 2025, 04:05
Не верифицирован
02 дек 2025, 04:05
644fb88
Код
Авторство
О чём код?
// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "third_party/zlib/google/zip.h" #include <cstdint> #include <string> #include <vector> #include "base/files/file.h" #include "base/files/file_enumerator.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/containers/flat_set.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" namespace zip { namespace { #if defined(OS_POSIX) // The maximum allowed size of a symbolic link in bytes. constexpr uint64_t kMaxSymlinkFileSize = 8192; #endif bool IsHiddenFile(const base::FilePath& file_path) { return file_path.BaseName().value()[0] == '.'; } // Creates a directory at |extract_dir|/|entry_path|, including any parents. bool CreateDirectory(const base::FilePath& extract_dir, const base::FilePath& 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; } #if defined(OS_POSIX) // Creates a symbolic link at |extract_dir|/|target| to |link|. Fails if |link| // points outside of |extract_dir|. bool CreateSymbolicLink(const base::FilePath& extract_dir, const base::FilePath& target, const base::FilePath& link) { const base::FilePath full_link_path = extract_dir.Append(link); if (target.IsAbsolute()) { LOG(ERROR) << "Won't create link with an absolute target " << Redact(target); return false; } std::optional<base::FilePath> absolute_target = base::MakeAbsoluteFilePathNoResolveSymbolicLinks( full_link_path.DirName().Append(target)); if (!absolute_target) { LOG(ERROR) << "Failed to make an absolute path to " << Redact(target); return false; } if (!extract_dir.IsParent(*absolute_target)) { LOG(ERROR) << "Won't create link with target outside extract dir " << Redact(target); return false; } return base::CreateSymbolicLink(target, full_link_path); } #endif // defined(OS_POSIX) // Creates a WriterDelegate that can write a file at |extract_dir|/|entry_path|. std::unique_ptr<WriterDelegate> CreateFilePathWriterDelegate( const base::FilePath& extract_dir, const base::FilePath& entry_path) { return std::make_unique<FilePathWriterDelegate>( extract_dir.Append(entry_path)); } class DirectFileAccessor : public FileAccessor { public: explicit DirectFileAccessor(base::FilePath src_dir) : src_dir_(std::move(src_dir)) {} ~DirectFileAccessor() override = default; 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()); } } return true; } 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( src_dir_.Append(path), false /* recursive */, base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); while (!file_enumerator.Next().empty()) { const base::FileEnumerator::FileInfo info = file_enumerator.GetInfo(); (info.IsDirectory() ? subdirs : files) ->push_back(path.Append(info.GetName())); } return true; } bool GetInfo(const base::FilePath& path, Info* const info) override { DCHECK(!path.IsAbsolute()); DCHECK(info); base::File::Info file_info; if (!base::GetFileInfo(src_dir_.Append(path), &file_info)) { PLOG(ERROR) << "Cannot get info of " << Redact(path); return false; } info->is_directory = file_info.is_directory; info->last_modified = file_info.last_modified; return true; } private: const base::FilePath src_dir_; }; // |symlink_creator| may be null in which case symbolic link entries are // considered errors. bool UnzipImpl( const base::PlatformFile& src_file, WriterFactory writer_factory, DirectoryCreator directory_creator, UnzipOptions options, base::RepeatingCallback<bool(const base::FilePath&, const base::FilePath&)> symlink_creator) { ZipReader reader; reader.SetEncoding(std::move(options.encoding)); reader.SetPassword(std::move(options.password)); if (!reader.OpenFromPlatformFile(src_file)) { LOG(ERROR) << "Cannot open ZIP from file handle " << src_file; return false; } base::flat_set<base::FilePath> symlinks; 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; } if (options.filter && !options.filter.Run(entry->path)) { VLOG(1) << "Skipped ZIP entry " << Redact(entry->path); continue; } base::FilePath path = entry->path; bool is_in_symlinked_dir = false; while (path.DirName() != path) { path = path.DirName(); if (symlinks.contains(path)) { is_in_symlinked_dir = true; break; } } if (is_in_symlinked_dir) { LOG(ERROR) << "Found entry " << Redact(entry->path) << " in symlinked directory " << Redact(path); if (!options.continue_on_error) { return false; } continue; } 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; } } continue; } #if defined(OS_POSIX) if (entry->is_symbolic_link) { if (!symlink_creator) { LOG(ERROR) << "Skipping symbolic link " << Redact(entry->path); if (!options.continue_on_error) { return false; } continue; } std::string target; if (!reader.ExtractCurrentEntryToString(kMaxSymlinkFileSize, &target)) { LOG(ERROR) << "Failed to read link target " << Redact(entry->path); if (!options.continue_on_error) { return false; } continue; } if (!symlink_creator.Run(base::FilePath(target), entry->path)) { LOG(ERROR) << "Failed to create symbolic link " << Redact(entry->path); if (!options.continue_on_error) { return false; } continue; } symlinks.insert(entry->path); continue; } #endif // defined(OS_POSIX) // It's a file. std::unique_ptr<WriterDelegate> writer = writer_factory.Run(entry->path); if (!writer || (options.progress ? !reader.ExtractCurrentEntryWithListener( writer.get(), options.progress) : !reader.ExtractCurrentEntry(writer.get()))) { LOG(ERROR) << "Cannot extract file " << Redact(entry->path) << " from ZIP"; if (!options.continue_on_error) { return false; } } } return reader.ok(); } } // namespace 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) { 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) || 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, file_accessor); if (!zip_writer) { return false; } } 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 Unzip(const base::FilePath& src_file, const base::FilePath& dest_dir, UnzipOptions options, UnzipSymlinkOption symlink_option) { base::File file(src_file, base::File::FLAG_OPEN | base::File::FLAG_READ); if (!file.IsValid()) { PLOG(ERROR) << "Cannot open " << Redact(src_file) << ": " << base::File::ErrorToString(file.error_details()); return false; } DLOG_IF(WARNING, !base::IsDirectoryEmpty(dest_dir)) << "ZIP extraction directory is not empty: " << dest_dir; base::RepeatingCallback<bool(const base::FilePath&, const base::FilePath&)> symlink_creator; #if defined(OS_POSIX) if (symlink_option == UnzipSymlinkOption::PRESERVE) { symlink_creator = base::BindRepeating(&CreateSymbolicLink, dest_dir); } #endif // defined(OS_POSIX) return UnzipImpl(file.GetPlatformFile(), base::BindRepeating(&CreateFilePathWriterDelegate, dest_dir), base::BindRepeating(&CreateDirectory, dest_dir), std::move(options), symlink_creator); } bool Unzip(const base::PlatformFile& src_file, WriterFactory writer_factory, DirectoryCreator directory_creator, UnzipOptions options) { return UnzipImpl(src_file, writer_factory, directory_creator, std::move(options), /*symlink_creator=*/{}); } bool ZipWithFilterCallback(const base::FilePath& src_dir, const base::FilePath& dest_file, FilterCallback filter) { DCHECK(base::DirectoryExists(src_dir)); 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 include_hidden_files) { return Zip({.src_dir = src_dir, .dest_file = dest_file, .include_hidden_files = include_hidden_files}); } #if defined(OS_POSIX) || defined(OS_FUCHSIA) bool ZipFiles(const base::FilePath& src_dir, Paths src_relative_paths, int dest_fd) { DCHECK(base::DirectoryExists(src_dir)); return Zip({.src_dir = src_dir, .dest_fd = dest_fd, .src_files = src_relative_paths}); } #endif // defined(OS_POSIX) || defined(OS_FUCHSIA) } // namespace zip