1*86ee64e7SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*86ee64e7SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*86ee64e7SAndroid Build Coastguard Worker // found in the LICENSE file.
4*86ee64e7SAndroid Build Coastguard Worker
5*86ee64e7SAndroid Build Coastguard Worker #include "third_party/zlib/google/zip.h"
6*86ee64e7SAndroid Build Coastguard Worker
7*86ee64e7SAndroid Build Coastguard Worker #include <string>
8*86ee64e7SAndroid Build Coastguard Worker #include <vector>
9*86ee64e7SAndroid Build Coastguard Worker
10*86ee64e7SAndroid Build Coastguard Worker #include "base/files/file.h"
11*86ee64e7SAndroid Build Coastguard Worker #include "base/files/file_enumerator.h"
12*86ee64e7SAndroid Build Coastguard Worker #include "base/files/file_util.h"
13*86ee64e7SAndroid Build Coastguard Worker #include "base/functional/bind.h"
14*86ee64e7SAndroid Build Coastguard Worker #include "base/logging.h"
15*86ee64e7SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
16*86ee64e7SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
17*86ee64e7SAndroid Build Coastguard Worker #include "build/build_config.h"
18*86ee64e7SAndroid Build Coastguard Worker #include "third_party/zlib/google/redact.h"
19*86ee64e7SAndroid Build Coastguard Worker #include "third_party/zlib/google/zip_internal.h"
20*86ee64e7SAndroid Build Coastguard Worker #include "third_party/zlib/google/zip_reader.h"
21*86ee64e7SAndroid Build Coastguard Worker #include "third_party/zlib/google/zip_writer.h"
22*86ee64e7SAndroid Build Coastguard Worker
23*86ee64e7SAndroid Build Coastguard Worker namespace zip {
24*86ee64e7SAndroid Build Coastguard Worker namespace {
25*86ee64e7SAndroid Build Coastguard Worker
IsHiddenFile(const base::FilePath & file_path)26*86ee64e7SAndroid Build Coastguard Worker bool IsHiddenFile(const base::FilePath& file_path) {
27*86ee64e7SAndroid Build Coastguard Worker return file_path.BaseName().value()[0] == '.';
28*86ee64e7SAndroid Build Coastguard Worker }
29*86ee64e7SAndroid Build Coastguard Worker
30*86ee64e7SAndroid Build Coastguard Worker // Creates a directory at |extract_dir|/|entry_path|, including any parents.
CreateDirectory(const base::FilePath & extract_dir,const base::FilePath & entry_path)31*86ee64e7SAndroid Build Coastguard Worker bool CreateDirectory(const base::FilePath& extract_dir,
32*86ee64e7SAndroid Build Coastguard Worker const base::FilePath& entry_path) {
33*86ee64e7SAndroid Build Coastguard Worker const base::FilePath dir = extract_dir.Append(entry_path);
34*86ee64e7SAndroid Build Coastguard Worker const bool ok = base::CreateDirectory(dir);
35*86ee64e7SAndroid Build Coastguard Worker PLOG_IF(ERROR, !ok) << "Cannot create directory " << Redact(dir);
36*86ee64e7SAndroid Build Coastguard Worker return ok;
37*86ee64e7SAndroid Build Coastguard Worker }
38*86ee64e7SAndroid Build Coastguard Worker
39*86ee64e7SAndroid Build Coastguard Worker // Creates a WriterDelegate that can write a file at |extract_dir|/|entry_path|.
CreateFilePathWriterDelegate(const base::FilePath & extract_dir,const base::FilePath & entry_path)40*86ee64e7SAndroid Build Coastguard Worker std::unique_ptr<WriterDelegate> CreateFilePathWriterDelegate(
41*86ee64e7SAndroid Build Coastguard Worker const base::FilePath& extract_dir,
42*86ee64e7SAndroid Build Coastguard Worker const base::FilePath& entry_path) {
43*86ee64e7SAndroid Build Coastguard Worker return std::make_unique<FilePathWriterDelegate>(
44*86ee64e7SAndroid Build Coastguard Worker extract_dir.Append(entry_path));
45*86ee64e7SAndroid Build Coastguard Worker }
46*86ee64e7SAndroid Build Coastguard Worker
47*86ee64e7SAndroid Build Coastguard Worker class DirectFileAccessor : public FileAccessor {
48*86ee64e7SAndroid Build Coastguard Worker public:
DirectFileAccessor(base::FilePath src_dir)49*86ee64e7SAndroid Build Coastguard Worker explicit DirectFileAccessor(base::FilePath src_dir)
50*86ee64e7SAndroid Build Coastguard Worker : src_dir_(std::move(src_dir)) {}
51*86ee64e7SAndroid Build Coastguard Worker
52*86ee64e7SAndroid Build Coastguard Worker ~DirectFileAccessor() override = default;
53*86ee64e7SAndroid Build Coastguard Worker
Open(const Paths paths,std::vector<base::File> * const files)54*86ee64e7SAndroid Build Coastguard Worker bool Open(const Paths paths, std::vector<base::File>* const files) override {
55*86ee64e7SAndroid Build Coastguard Worker DCHECK(files);
56*86ee64e7SAndroid Build Coastguard Worker files->reserve(files->size() + paths.size());
57*86ee64e7SAndroid Build Coastguard Worker
58*86ee64e7SAndroid Build Coastguard Worker for (const base::FilePath& path : paths) {
59*86ee64e7SAndroid Build Coastguard Worker DCHECK(!path.IsAbsolute());
60*86ee64e7SAndroid Build Coastguard Worker const base::FilePath absolute_path = src_dir_.Append(path);
61*86ee64e7SAndroid Build Coastguard Worker if (base::DirectoryExists(absolute_path)) {
62*86ee64e7SAndroid Build Coastguard Worker files->emplace_back();
63*86ee64e7SAndroid Build Coastguard Worker LOG(ERROR) << "Cannot open " << Redact(path) << ": It is a directory";
64*86ee64e7SAndroid Build Coastguard Worker } else {
65*86ee64e7SAndroid Build Coastguard Worker const base::File& file = files->emplace_back(
66*86ee64e7SAndroid Build Coastguard Worker absolute_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
67*86ee64e7SAndroid Build Coastguard Worker LOG_IF(ERROR, !file.IsValid())
68*86ee64e7SAndroid Build Coastguard Worker << "Cannot open " << Redact(path) << ": "
69*86ee64e7SAndroid Build Coastguard Worker << base::File::ErrorToString(file.error_details());
70*86ee64e7SAndroid Build Coastguard Worker }
71*86ee64e7SAndroid Build Coastguard Worker }
72*86ee64e7SAndroid Build Coastguard Worker
73*86ee64e7SAndroid Build Coastguard Worker return true;
74*86ee64e7SAndroid Build Coastguard Worker }
75*86ee64e7SAndroid Build Coastguard Worker
List(const base::FilePath & path,std::vector<base::FilePath> * const files,std::vector<base::FilePath> * const subdirs)76*86ee64e7SAndroid Build Coastguard Worker bool List(const base::FilePath& path,
77*86ee64e7SAndroid Build Coastguard Worker std::vector<base::FilePath>* const files,
78*86ee64e7SAndroid Build Coastguard Worker std::vector<base::FilePath>* const subdirs) override {
79*86ee64e7SAndroid Build Coastguard Worker DCHECK(!path.IsAbsolute());
80*86ee64e7SAndroid Build Coastguard Worker DCHECK(files);
81*86ee64e7SAndroid Build Coastguard Worker DCHECK(subdirs);
82*86ee64e7SAndroid Build Coastguard Worker
83*86ee64e7SAndroid Build Coastguard Worker base::FileEnumerator file_enumerator(
84*86ee64e7SAndroid Build Coastguard Worker src_dir_.Append(path), false /* recursive */,
85*86ee64e7SAndroid Build Coastguard Worker base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
86*86ee64e7SAndroid Build Coastguard Worker
87*86ee64e7SAndroid Build Coastguard Worker while (!file_enumerator.Next().empty()) {
88*86ee64e7SAndroid Build Coastguard Worker const base::FileEnumerator::FileInfo info = file_enumerator.GetInfo();
89*86ee64e7SAndroid Build Coastguard Worker (info.IsDirectory() ? subdirs : files)
90*86ee64e7SAndroid Build Coastguard Worker ->push_back(path.Append(info.GetName()));
91*86ee64e7SAndroid Build Coastguard Worker }
92*86ee64e7SAndroid Build Coastguard Worker
93*86ee64e7SAndroid Build Coastguard Worker return true;
94*86ee64e7SAndroid Build Coastguard Worker }
95*86ee64e7SAndroid Build Coastguard Worker
GetInfo(const base::FilePath & path,Info * const info)96*86ee64e7SAndroid Build Coastguard Worker bool GetInfo(const base::FilePath& path, Info* const info) override {
97*86ee64e7SAndroid Build Coastguard Worker DCHECK(!path.IsAbsolute());
98*86ee64e7SAndroid Build Coastguard Worker DCHECK(info);
99*86ee64e7SAndroid Build Coastguard Worker
100*86ee64e7SAndroid Build Coastguard Worker base::File::Info file_info;
101*86ee64e7SAndroid Build Coastguard Worker if (!base::GetFileInfo(src_dir_.Append(path), &file_info)) {
102*86ee64e7SAndroid Build Coastguard Worker PLOG(ERROR) << "Cannot get info of " << Redact(path);
103*86ee64e7SAndroid Build Coastguard Worker return false;
104*86ee64e7SAndroid Build Coastguard Worker }
105*86ee64e7SAndroid Build Coastguard Worker
106*86ee64e7SAndroid Build Coastguard Worker info->is_directory = file_info.is_directory;
107*86ee64e7SAndroid Build Coastguard Worker info->last_modified = file_info.last_modified;
108*86ee64e7SAndroid Build Coastguard Worker
109*86ee64e7SAndroid Build Coastguard Worker return true;
110*86ee64e7SAndroid Build Coastguard Worker }
111*86ee64e7SAndroid Build Coastguard Worker
112*86ee64e7SAndroid Build Coastguard Worker private:
113*86ee64e7SAndroid Build Coastguard Worker const base::FilePath src_dir_;
114*86ee64e7SAndroid Build Coastguard Worker };
115*86ee64e7SAndroid Build Coastguard Worker
116*86ee64e7SAndroid Build Coastguard Worker } // namespace
117*86ee64e7SAndroid Build Coastguard Worker
operator <<(std::ostream & out,const Progress & progress)118*86ee64e7SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& out, const Progress& progress) {
119*86ee64e7SAndroid Build Coastguard Worker return out << progress.bytes << " bytes, " << progress.files << " files, "
120*86ee64e7SAndroid Build Coastguard Worker << progress.directories << " dirs, " << progress.errors
121*86ee64e7SAndroid Build Coastguard Worker << " errors";
122*86ee64e7SAndroid Build Coastguard Worker }
123*86ee64e7SAndroid Build Coastguard Worker
Zip(const ZipParams & params)124*86ee64e7SAndroid Build Coastguard Worker bool Zip(const ZipParams& params) {
125*86ee64e7SAndroid Build Coastguard Worker DirectFileAccessor default_accessor(params.src_dir);
126*86ee64e7SAndroid Build Coastguard Worker FileAccessor* const file_accessor = params.file_accessor ?: &default_accessor;
127*86ee64e7SAndroid Build Coastguard Worker
128*86ee64e7SAndroid Build Coastguard Worker std::unique_ptr<internal::ZipWriter> zip_writer;
129*86ee64e7SAndroid Build Coastguard Worker
130*86ee64e7SAndroid Build Coastguard Worker #if defined(OS_POSIX) || defined(OS_FUCHSIA)
131*86ee64e7SAndroid Build Coastguard Worker if (params.dest_fd != base::kInvalidPlatformFile) {
132*86ee64e7SAndroid Build Coastguard Worker DCHECK(params.dest_file.empty());
133*86ee64e7SAndroid Build Coastguard Worker zip_writer =
134*86ee64e7SAndroid Build Coastguard Worker internal::ZipWriter::CreateWithFd(params.dest_fd, file_accessor);
135*86ee64e7SAndroid Build Coastguard Worker if (!zip_writer)
136*86ee64e7SAndroid Build Coastguard Worker return false;
137*86ee64e7SAndroid Build Coastguard Worker }
138*86ee64e7SAndroid Build Coastguard Worker #endif
139*86ee64e7SAndroid Build Coastguard Worker
140*86ee64e7SAndroid Build Coastguard Worker if (!zip_writer) {
141*86ee64e7SAndroid Build Coastguard Worker zip_writer = internal::ZipWriter::Create(params.dest_file, file_accessor);
142*86ee64e7SAndroid Build Coastguard Worker if (!zip_writer)
143*86ee64e7SAndroid Build Coastguard Worker return false;
144*86ee64e7SAndroid Build Coastguard Worker }
145*86ee64e7SAndroid Build Coastguard Worker
146*86ee64e7SAndroid Build Coastguard Worker zip_writer->SetProgressCallback(params.progress_callback,
147*86ee64e7SAndroid Build Coastguard Worker params.progress_period);
148*86ee64e7SAndroid Build Coastguard Worker zip_writer->SetRecursive(params.recursive);
149*86ee64e7SAndroid Build Coastguard Worker zip_writer->ContinueOnError(params.continue_on_error);
150*86ee64e7SAndroid Build Coastguard Worker
151*86ee64e7SAndroid Build Coastguard Worker if (!params.include_hidden_files || params.filter_callback)
152*86ee64e7SAndroid Build Coastguard Worker zip_writer->SetFilterCallback(base::BindRepeating(
153*86ee64e7SAndroid Build Coastguard Worker [](const ZipParams* const params, const base::FilePath& path) -> bool {
154*86ee64e7SAndroid Build Coastguard Worker return (params->include_hidden_files || !IsHiddenFile(path)) &&
155*86ee64e7SAndroid Build Coastguard Worker (!params->filter_callback ||
156*86ee64e7SAndroid Build Coastguard Worker params->filter_callback.Run(params->src_dir.Append(path)));
157*86ee64e7SAndroid Build Coastguard Worker },
158*86ee64e7SAndroid Build Coastguard Worker ¶ms));
159*86ee64e7SAndroid Build Coastguard Worker
160*86ee64e7SAndroid Build Coastguard Worker if (params.src_files.empty()) {
161*86ee64e7SAndroid Build Coastguard Worker // No source items are specified. Zip the entire source directory.
162*86ee64e7SAndroid Build Coastguard Worker zip_writer->SetRecursive(true);
163*86ee64e7SAndroid Build Coastguard Worker if (!zip_writer->AddDirectoryContents(base::FilePath()))
164*86ee64e7SAndroid Build Coastguard Worker return false;
165*86ee64e7SAndroid Build Coastguard Worker } else {
166*86ee64e7SAndroid Build Coastguard Worker // Only zip the specified source items.
167*86ee64e7SAndroid Build Coastguard Worker if (!zip_writer->AddMixedEntries(params.src_files))
168*86ee64e7SAndroid Build Coastguard Worker return false;
169*86ee64e7SAndroid Build Coastguard Worker }
170*86ee64e7SAndroid Build Coastguard Worker
171*86ee64e7SAndroid Build Coastguard Worker return zip_writer->Close();
172*86ee64e7SAndroid Build Coastguard Worker }
173*86ee64e7SAndroid Build Coastguard Worker
Unzip(const base::FilePath & src_file,const base::FilePath & dest_dir,UnzipOptions options)174*86ee64e7SAndroid Build Coastguard Worker bool Unzip(const base::FilePath& src_file,
175*86ee64e7SAndroid Build Coastguard Worker const base::FilePath& dest_dir,
176*86ee64e7SAndroid Build Coastguard Worker UnzipOptions options) {
177*86ee64e7SAndroid Build Coastguard Worker base::File file(src_file, base::File::FLAG_OPEN | base::File::FLAG_READ);
178*86ee64e7SAndroid Build Coastguard Worker if (!file.IsValid()) {
179*86ee64e7SAndroid Build Coastguard Worker PLOG(ERROR) << "Cannot open " << Redact(src_file) << ": "
180*86ee64e7SAndroid Build Coastguard Worker << base::File::ErrorToString(file.error_details());
181*86ee64e7SAndroid Build Coastguard Worker return false;
182*86ee64e7SAndroid Build Coastguard Worker }
183*86ee64e7SAndroid Build Coastguard Worker
184*86ee64e7SAndroid Build Coastguard Worker DLOG_IF(WARNING, !base::IsDirectoryEmpty(dest_dir))
185*86ee64e7SAndroid Build Coastguard Worker << "ZIP extraction directory is not empty: " << dest_dir;
186*86ee64e7SAndroid Build Coastguard Worker
187*86ee64e7SAndroid Build Coastguard Worker return Unzip(file.GetPlatformFile(),
188*86ee64e7SAndroid Build Coastguard Worker base::BindRepeating(&CreateFilePathWriterDelegate, dest_dir),
189*86ee64e7SAndroid Build Coastguard Worker base::BindRepeating(&CreateDirectory, dest_dir),
190*86ee64e7SAndroid Build Coastguard Worker std::move(options));
191*86ee64e7SAndroid Build Coastguard Worker }
192*86ee64e7SAndroid Build Coastguard Worker
Unzip(const base::PlatformFile & src_file,WriterFactory writer_factory,DirectoryCreator directory_creator,UnzipOptions options)193*86ee64e7SAndroid Build Coastguard Worker bool Unzip(const base::PlatformFile& src_file,
194*86ee64e7SAndroid Build Coastguard Worker WriterFactory writer_factory,
195*86ee64e7SAndroid Build Coastguard Worker DirectoryCreator directory_creator,
196*86ee64e7SAndroid Build Coastguard Worker UnzipOptions options) {
197*86ee64e7SAndroid Build Coastguard Worker ZipReader reader;
198*86ee64e7SAndroid Build Coastguard Worker reader.SetEncoding(std::move(options.encoding));
199*86ee64e7SAndroid Build Coastguard Worker reader.SetPassword(std::move(options.password));
200*86ee64e7SAndroid Build Coastguard Worker
201*86ee64e7SAndroid Build Coastguard Worker if (!reader.OpenFromPlatformFile(src_file)) {
202*86ee64e7SAndroid Build Coastguard Worker LOG(ERROR) << "Cannot open ZIP from file handle " << src_file;
203*86ee64e7SAndroid Build Coastguard Worker return false;
204*86ee64e7SAndroid Build Coastguard Worker }
205*86ee64e7SAndroid Build Coastguard Worker
206*86ee64e7SAndroid Build Coastguard Worker while (const ZipReader::Entry* const entry = reader.Next()) {
207*86ee64e7SAndroid Build Coastguard Worker if (entry->is_unsafe) {
208*86ee64e7SAndroid Build Coastguard Worker LOG(ERROR) << "Found unsafe entry " << Redact(entry->path) << " in ZIP";
209*86ee64e7SAndroid Build Coastguard Worker if (!options.continue_on_error)
210*86ee64e7SAndroid Build Coastguard Worker return false;
211*86ee64e7SAndroid Build Coastguard Worker continue;
212*86ee64e7SAndroid Build Coastguard Worker }
213*86ee64e7SAndroid Build Coastguard Worker
214*86ee64e7SAndroid Build Coastguard Worker if (options.filter && !options.filter.Run(entry->path)) {
215*86ee64e7SAndroid Build Coastguard Worker VLOG(1) << "Skipped ZIP entry " << Redact(entry->path);
216*86ee64e7SAndroid Build Coastguard Worker continue;
217*86ee64e7SAndroid Build Coastguard Worker }
218*86ee64e7SAndroid Build Coastguard Worker
219*86ee64e7SAndroid Build Coastguard Worker if (entry->is_directory) {
220*86ee64e7SAndroid Build Coastguard Worker // It's a directory.
221*86ee64e7SAndroid Build Coastguard Worker if (!directory_creator.Run(entry->path)) {
222*86ee64e7SAndroid Build Coastguard Worker LOG(ERROR) << "Cannot create directory " << Redact(entry->path);
223*86ee64e7SAndroid Build Coastguard Worker if (!options.continue_on_error)
224*86ee64e7SAndroid Build Coastguard Worker return false;
225*86ee64e7SAndroid Build Coastguard Worker }
226*86ee64e7SAndroid Build Coastguard Worker
227*86ee64e7SAndroid Build Coastguard Worker continue;
228*86ee64e7SAndroid Build Coastguard Worker }
229*86ee64e7SAndroid Build Coastguard Worker
230*86ee64e7SAndroid Build Coastguard Worker // It's a file.
231*86ee64e7SAndroid Build Coastguard Worker std::unique_ptr<WriterDelegate> writer = writer_factory.Run(entry->path);
232*86ee64e7SAndroid Build Coastguard Worker if (!writer ||
233*86ee64e7SAndroid Build Coastguard Worker (options.progress ? !reader.ExtractCurrentEntryWithListener(
234*86ee64e7SAndroid Build Coastguard Worker writer.get(), options.progress)
235*86ee64e7SAndroid Build Coastguard Worker : !reader.ExtractCurrentEntry(writer.get()))) {
236*86ee64e7SAndroid Build Coastguard Worker LOG(ERROR) << "Cannot extract file " << Redact(entry->path)
237*86ee64e7SAndroid Build Coastguard Worker << " from ZIP";
238*86ee64e7SAndroid Build Coastguard Worker if (!options.continue_on_error)
239*86ee64e7SAndroid Build Coastguard Worker return false;
240*86ee64e7SAndroid Build Coastguard Worker }
241*86ee64e7SAndroid Build Coastguard Worker }
242*86ee64e7SAndroid Build Coastguard Worker
243*86ee64e7SAndroid Build Coastguard Worker return reader.ok();
244*86ee64e7SAndroid Build Coastguard Worker }
245*86ee64e7SAndroid Build Coastguard Worker
ZipWithFilterCallback(const base::FilePath & src_dir,const base::FilePath & dest_file,FilterCallback filter)246*86ee64e7SAndroid Build Coastguard Worker bool ZipWithFilterCallback(const base::FilePath& src_dir,
247*86ee64e7SAndroid Build Coastguard Worker const base::FilePath& dest_file,
248*86ee64e7SAndroid Build Coastguard Worker FilterCallback filter) {
249*86ee64e7SAndroid Build Coastguard Worker DCHECK(base::DirectoryExists(src_dir));
250*86ee64e7SAndroid Build Coastguard Worker return Zip({.src_dir = src_dir,
251*86ee64e7SAndroid Build Coastguard Worker .dest_file = dest_file,
252*86ee64e7SAndroid Build Coastguard Worker .filter_callback = std::move(filter)});
253*86ee64e7SAndroid Build Coastguard Worker }
254*86ee64e7SAndroid Build Coastguard Worker
Zip(const base::FilePath & src_dir,const base::FilePath & dest_file,bool include_hidden_files)255*86ee64e7SAndroid Build Coastguard Worker bool Zip(const base::FilePath& src_dir,
256*86ee64e7SAndroid Build Coastguard Worker const base::FilePath& dest_file,
257*86ee64e7SAndroid Build Coastguard Worker bool include_hidden_files) {
258*86ee64e7SAndroid Build Coastguard Worker return Zip({.src_dir = src_dir,
259*86ee64e7SAndroid Build Coastguard Worker .dest_file = dest_file,
260*86ee64e7SAndroid Build Coastguard Worker .include_hidden_files = include_hidden_files});
261*86ee64e7SAndroid Build Coastguard Worker }
262*86ee64e7SAndroid Build Coastguard Worker
263*86ee64e7SAndroid Build Coastguard Worker #if defined(OS_POSIX) || defined(OS_FUCHSIA)
ZipFiles(const base::FilePath & src_dir,Paths src_relative_paths,int dest_fd)264*86ee64e7SAndroid Build Coastguard Worker bool ZipFiles(const base::FilePath& src_dir,
265*86ee64e7SAndroid Build Coastguard Worker Paths src_relative_paths,
266*86ee64e7SAndroid Build Coastguard Worker int dest_fd) {
267*86ee64e7SAndroid Build Coastguard Worker DCHECK(base::DirectoryExists(src_dir));
268*86ee64e7SAndroid Build Coastguard Worker return Zip({.src_dir = src_dir,
269*86ee64e7SAndroid Build Coastguard Worker .dest_fd = dest_fd,
270*86ee64e7SAndroid Build Coastguard Worker .src_files = src_relative_paths});
271*86ee64e7SAndroid Build Coastguard Worker }
272*86ee64e7SAndroid Build Coastguard Worker #endif // defined(OS_POSIX) || defined(OS_FUCHSIA)
273*86ee64e7SAndroid Build Coastguard Worker
274*86ee64e7SAndroid Build Coastguard Worker } // namespace zip
275