1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2008 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "zip_archive.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <fcntl.h>
20*795d594fSAndroid Build Coastguard Worker #include <stdio.h>
21*795d594fSAndroid Build Coastguard Worker #include <sys/stat.h>
22*795d594fSAndroid Build Coastguard Worker #include <sys/types.h>
23*795d594fSAndroid Build Coastguard Worker #include <unistd.h>
24*795d594fSAndroid Build Coastguard Worker #include <vector>
25*795d594fSAndroid Build Coastguard Worker
26*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
27*795d594fSAndroid Build Coastguard Worker #include "ziparchive/zip_archive.h"
28*795d594fSAndroid Build Coastguard Worker
29*795d594fSAndroid Build Coastguard Worker #include "base/mman.h"
30*795d594fSAndroid Build Coastguard Worker #include "bit_utils.h"
31*795d594fSAndroid Build Coastguard Worker #include "unix_file/fd_file.h"
32*795d594fSAndroid Build Coastguard Worker
33*795d594fSAndroid Build Coastguard Worker namespace art {
34*795d594fSAndroid Build Coastguard Worker
35*795d594fSAndroid Build Coastguard Worker // Log file contents and mmap info when mapping entries directly.
36*795d594fSAndroid Build Coastguard Worker static constexpr const bool kDebugZipMapDirectly = false;
37*795d594fSAndroid Build Coastguard Worker
38*795d594fSAndroid Build Coastguard Worker using android::base::StringPrintf;
39*795d594fSAndroid Build Coastguard Worker
GetUncompressedLength()40*795d594fSAndroid Build Coastguard Worker uint32_t ZipEntry::GetUncompressedLength() {
41*795d594fSAndroid Build Coastguard Worker return zip_entry_->uncompressed_length;
42*795d594fSAndroid Build Coastguard Worker }
43*795d594fSAndroid Build Coastguard Worker
GetCrc32()44*795d594fSAndroid Build Coastguard Worker uint32_t ZipEntry::GetCrc32() {
45*795d594fSAndroid Build Coastguard Worker return zip_entry_->crc32;
46*795d594fSAndroid Build Coastguard Worker }
47*795d594fSAndroid Build Coastguard Worker
IsUncompressed()48*795d594fSAndroid Build Coastguard Worker bool ZipEntry::IsUncompressed() {
49*795d594fSAndroid Build Coastguard Worker return zip_entry_->method == kCompressStored;
50*795d594fSAndroid Build Coastguard Worker }
51*795d594fSAndroid Build Coastguard Worker
IsAlignedTo(size_t alignment) const52*795d594fSAndroid Build Coastguard Worker bool ZipEntry::IsAlignedTo(size_t alignment) const {
53*795d594fSAndroid Build Coastguard Worker DCHECK(IsPowerOfTwo(alignment)) << alignment;
54*795d594fSAndroid Build Coastguard Worker return IsAlignedParam(zip_entry_->offset, static_cast<int>(alignment));
55*795d594fSAndroid Build Coastguard Worker }
56*795d594fSAndroid Build Coastguard Worker
~ZipEntry()57*795d594fSAndroid Build Coastguard Worker ZipEntry::~ZipEntry() {
58*795d594fSAndroid Build Coastguard Worker delete zip_entry_;
59*795d594fSAndroid Build Coastguard Worker }
60*795d594fSAndroid Build Coastguard Worker
ExtractToFile(File & file,std::string * error_msg)61*795d594fSAndroid Build Coastguard Worker bool ZipEntry::ExtractToFile(File& file, std::string* error_msg) {
62*795d594fSAndroid Build Coastguard Worker const int32_t error = ExtractEntryToFile(handle_, zip_entry_, file.Fd());
63*795d594fSAndroid Build Coastguard Worker if (error != 0) {
64*795d594fSAndroid Build Coastguard Worker *error_msg = std::string(ErrorCodeString(error));
65*795d594fSAndroid Build Coastguard Worker return false;
66*795d594fSAndroid Build Coastguard Worker }
67*795d594fSAndroid Build Coastguard Worker
68*795d594fSAndroid Build Coastguard Worker return true;
69*795d594fSAndroid Build Coastguard Worker }
70*795d594fSAndroid Build Coastguard Worker
ExtractToMemMap(const char * zip_filename,const char * entry_filename,std::string * error_msg)71*795d594fSAndroid Build Coastguard Worker MemMap ZipEntry::ExtractToMemMap(const char* zip_filename,
72*795d594fSAndroid Build Coastguard Worker const char* entry_filename,
73*795d594fSAndroid Build Coastguard Worker std::string* error_msg) {
74*795d594fSAndroid Build Coastguard Worker std::string name(entry_filename);
75*795d594fSAndroid Build Coastguard Worker name += " extracted in memory from ";
76*795d594fSAndroid Build Coastguard Worker name += zip_filename;
77*795d594fSAndroid Build Coastguard Worker MemMap map = MemMap::MapAnonymous(name.c_str(),
78*795d594fSAndroid Build Coastguard Worker GetUncompressedLength(),
79*795d594fSAndroid Build Coastguard Worker PROT_READ | PROT_WRITE,
80*795d594fSAndroid Build Coastguard Worker /*low_4gb=*/ false,
81*795d594fSAndroid Build Coastguard Worker error_msg);
82*795d594fSAndroid Build Coastguard Worker if (!map.IsValid()) {
83*795d594fSAndroid Build Coastguard Worker DCHECK(!error_msg->empty());
84*795d594fSAndroid Build Coastguard Worker return MemMap::Invalid();
85*795d594fSAndroid Build Coastguard Worker }
86*795d594fSAndroid Build Coastguard Worker
87*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(map.Size(), GetUncompressedLength());
88*795d594fSAndroid Build Coastguard Worker if (!ExtractToMemory(map.Begin(), error_msg)) {
89*795d594fSAndroid Build Coastguard Worker return MemMap::Invalid();
90*795d594fSAndroid Build Coastguard Worker }
91*795d594fSAndroid Build Coastguard Worker
92*795d594fSAndroid Build Coastguard Worker return map;
93*795d594fSAndroid Build Coastguard Worker }
94*795d594fSAndroid Build Coastguard Worker
ExtractToMemory(uint8_t * buffer,std::string * error_msg)95*795d594fSAndroid Build Coastguard Worker bool ZipEntry::ExtractToMemory(/*out*/uint8_t* buffer, /*out*/std::string* error_msg) {
96*795d594fSAndroid Build Coastguard Worker const int32_t error = ::ExtractToMemory(handle_, zip_entry_, buffer, GetUncompressedLength());
97*795d594fSAndroid Build Coastguard Worker if (error != 0) {
98*795d594fSAndroid Build Coastguard Worker *error_msg = std::string(ErrorCodeString(error));
99*795d594fSAndroid Build Coastguard Worker return false;
100*795d594fSAndroid Build Coastguard Worker }
101*795d594fSAndroid Build Coastguard Worker return true;
102*795d594fSAndroid Build Coastguard Worker }
103*795d594fSAndroid Build Coastguard Worker
MapDirectlyFromFile(const char * zip_filename,std::string * error_msg)104*795d594fSAndroid Build Coastguard Worker MemMap ZipEntry::MapDirectlyFromFile(const char* zip_filename, std::string* error_msg) {
105*795d594fSAndroid Build Coastguard Worker const int zip_fd = GetFileDescriptor(handle_);
106*795d594fSAndroid Build Coastguard Worker const char* entry_filename = entry_name_.c_str();
107*795d594fSAndroid Build Coastguard Worker
108*795d594fSAndroid Build Coastguard Worker // Should not happen since we don't have a memory ZipArchive constructor.
109*795d594fSAndroid Build Coastguard Worker // However the underlying ZipArchive isn't required to have an FD,
110*795d594fSAndroid Build Coastguard Worker // so check to be sure.
111*795d594fSAndroid Build Coastguard Worker CHECK_GE(zip_fd, 0) <<
112*795d594fSAndroid Build Coastguard Worker StringPrintf("Cannot map '%s' (in zip '%s') directly because the zip archive "
113*795d594fSAndroid Build Coastguard Worker "is not file backed.",
114*795d594fSAndroid Build Coastguard Worker entry_filename,
115*795d594fSAndroid Build Coastguard Worker zip_filename);
116*795d594fSAndroid Build Coastguard Worker
117*795d594fSAndroid Build Coastguard Worker if (!IsUncompressed()) {
118*795d594fSAndroid Build Coastguard Worker *error_msg = StringPrintf("Cannot map '%s' (in zip '%s') directly because it is compressed.",
119*795d594fSAndroid Build Coastguard Worker entry_filename,
120*795d594fSAndroid Build Coastguard Worker zip_filename);
121*795d594fSAndroid Build Coastguard Worker return MemMap::Invalid();
122*795d594fSAndroid Build Coastguard Worker } else if (zip_entry_->uncompressed_length != zip_entry_->compressed_length) {
123*795d594fSAndroid Build Coastguard Worker *error_msg = StringPrintf("Cannot map '%s' (in zip '%s') directly because "
124*795d594fSAndroid Build Coastguard Worker "entry has bad size (%u != %u).",
125*795d594fSAndroid Build Coastguard Worker entry_filename,
126*795d594fSAndroid Build Coastguard Worker zip_filename,
127*795d594fSAndroid Build Coastguard Worker zip_entry_->uncompressed_length,
128*795d594fSAndroid Build Coastguard Worker zip_entry_->compressed_length);
129*795d594fSAndroid Build Coastguard Worker return MemMap::Invalid();
130*795d594fSAndroid Build Coastguard Worker }
131*795d594fSAndroid Build Coastguard Worker
132*795d594fSAndroid Build Coastguard Worker std::string name(entry_filename);
133*795d594fSAndroid Build Coastguard Worker name += " mapped directly in memory from ";
134*795d594fSAndroid Build Coastguard Worker name += zip_filename;
135*795d594fSAndroid Build Coastguard Worker
136*795d594fSAndroid Build Coastguard Worker const off_t offset = zip_entry_->offset;
137*795d594fSAndroid Build Coastguard Worker
138*795d594fSAndroid Build Coastguard Worker if (kDebugZipMapDirectly) {
139*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "zip_archive: " << "make mmap of " << name << " @ offset = " << offset;
140*795d594fSAndroid Build Coastguard Worker }
141*795d594fSAndroid Build Coastguard Worker
142*795d594fSAndroid Build Coastguard Worker MemMap map =
143*795d594fSAndroid Build Coastguard Worker MemMap::MapFile(GetUncompressedLength(), // Byte count
144*795d594fSAndroid Build Coastguard Worker PROT_READ | PROT_WRITE,
145*795d594fSAndroid Build Coastguard Worker MAP_PRIVATE,
146*795d594fSAndroid Build Coastguard Worker zip_fd,
147*795d594fSAndroid Build Coastguard Worker offset,
148*795d594fSAndroid Build Coastguard Worker /*low_4gb=*/ false,
149*795d594fSAndroid Build Coastguard Worker name.c_str(),
150*795d594fSAndroid Build Coastguard Worker error_msg);
151*795d594fSAndroid Build Coastguard Worker
152*795d594fSAndroid Build Coastguard Worker if (!map.IsValid()) {
153*795d594fSAndroid Build Coastguard Worker DCHECK(!error_msg->empty());
154*795d594fSAndroid Build Coastguard Worker }
155*795d594fSAndroid Build Coastguard Worker
156*795d594fSAndroid Build Coastguard Worker if (kDebugZipMapDirectly) {
157*795d594fSAndroid Build Coastguard Worker // Dump contents of file, same format as using this shell command:
158*795d594fSAndroid Build Coastguard Worker // $> od -j <offset> -t x1 <zip_filename>
159*795d594fSAndroid Build Coastguard Worker static constexpr const int kMaxDumpChars = 15;
160*795d594fSAndroid Build Coastguard Worker lseek(zip_fd, 0, SEEK_SET);
161*795d594fSAndroid Build Coastguard Worker
162*795d594fSAndroid Build Coastguard Worker int count = offset + kMaxDumpChars;
163*795d594fSAndroid Build Coastguard Worker
164*795d594fSAndroid Build Coastguard Worker std::string tmp;
165*795d594fSAndroid Build Coastguard Worker char buf;
166*795d594fSAndroid Build Coastguard Worker
167*795d594fSAndroid Build Coastguard Worker // Dump file contents.
168*795d594fSAndroid Build Coastguard Worker int i = 0;
169*795d594fSAndroid Build Coastguard Worker while (read(zip_fd, &buf, 1) > 0 && i < count) {
170*795d594fSAndroid Build Coastguard Worker tmp += StringPrintf("%3d ", (unsigned int)buf);
171*795d594fSAndroid Build Coastguard Worker ++i;
172*795d594fSAndroid Build Coastguard Worker }
173*795d594fSAndroid Build Coastguard Worker
174*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "map_fd raw bytes starting at 0";
175*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "" << tmp;
176*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "---------------------------";
177*795d594fSAndroid Build Coastguard Worker
178*795d594fSAndroid Build Coastguard Worker // Dump map contents.
179*795d594fSAndroid Build Coastguard Worker if (map.IsValid()) {
180*795d594fSAndroid Build Coastguard Worker tmp = "";
181*795d594fSAndroid Build Coastguard Worker
182*795d594fSAndroid Build Coastguard Worker count = kMaxDumpChars;
183*795d594fSAndroid Build Coastguard Worker
184*795d594fSAndroid Build Coastguard Worker uint8_t* begin = map.Begin();
185*795d594fSAndroid Build Coastguard Worker for (i = 0; i < count; ++i) {
186*795d594fSAndroid Build Coastguard Worker tmp += StringPrintf("%3d ", (unsigned int)begin[i]);
187*795d594fSAndroid Build Coastguard Worker }
188*795d594fSAndroid Build Coastguard Worker
189*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "map address " << StringPrintf("%p", begin);
190*795d594fSAndroid Build Coastguard Worker LOG(INFO) << "map first " << kMaxDumpChars << " chars:";
191*795d594fSAndroid Build Coastguard Worker LOG(INFO) << tmp;
192*795d594fSAndroid Build Coastguard Worker }
193*795d594fSAndroid Build Coastguard Worker }
194*795d594fSAndroid Build Coastguard Worker
195*795d594fSAndroid Build Coastguard Worker return map;
196*795d594fSAndroid Build Coastguard Worker }
197*795d594fSAndroid Build Coastguard Worker
MapDirectlyOrExtract(const char * zip_filename,const char * entry_filename,std::string * error_msg,size_t alignment)198*795d594fSAndroid Build Coastguard Worker MemMap ZipEntry::MapDirectlyOrExtract(const char* zip_filename,
199*795d594fSAndroid Build Coastguard Worker const char* entry_filename,
200*795d594fSAndroid Build Coastguard Worker std::string* error_msg,
201*795d594fSAndroid Build Coastguard Worker size_t alignment) {
202*795d594fSAndroid Build Coastguard Worker if (IsUncompressed() && IsAlignedTo(alignment) && GetFileDescriptor(handle_) >= 0) {
203*795d594fSAndroid Build Coastguard Worker std::string local_error_msg;
204*795d594fSAndroid Build Coastguard Worker MemMap ret = MapDirectlyFromFile(zip_filename, &local_error_msg);
205*795d594fSAndroid Build Coastguard Worker if (ret.IsValid()) {
206*795d594fSAndroid Build Coastguard Worker return ret;
207*795d594fSAndroid Build Coastguard Worker }
208*795d594fSAndroid Build Coastguard Worker // Fall back to extraction for the failure case.
209*795d594fSAndroid Build Coastguard Worker }
210*795d594fSAndroid Build Coastguard Worker return ExtractToMemMap(zip_filename, entry_filename, error_msg);
211*795d594fSAndroid Build Coastguard Worker }
212*795d594fSAndroid Build Coastguard Worker
SetCloseOnExec(int fd)213*795d594fSAndroid Build Coastguard Worker static void SetCloseOnExec(int fd) {
214*795d594fSAndroid Build Coastguard Worker #ifdef _WIN32
215*795d594fSAndroid Build Coastguard Worker // Exec is not supported on Windows.
216*795d594fSAndroid Build Coastguard Worker UNUSED(fd);
217*795d594fSAndroid Build Coastguard Worker PLOG(ERROR) << "SetCloseOnExec is not supported on Windows.";
218*795d594fSAndroid Build Coastguard Worker #else
219*795d594fSAndroid Build Coastguard Worker // This dance is more portable than Linux's O_CLOEXEC open(2) flag.
220*795d594fSAndroid Build Coastguard Worker int flags = fcntl(fd, F_GETFD);
221*795d594fSAndroid Build Coastguard Worker if (flags == -1) {
222*795d594fSAndroid Build Coastguard Worker PLOG(WARNING) << "fcntl(" << fd << ", F_GETFD) failed";
223*795d594fSAndroid Build Coastguard Worker return;
224*795d594fSAndroid Build Coastguard Worker }
225*795d594fSAndroid Build Coastguard Worker int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
226*795d594fSAndroid Build Coastguard Worker if (rc == -1) {
227*795d594fSAndroid Build Coastguard Worker PLOG(WARNING) << "fcntl(" << fd << ", F_SETFD, " << flags << ") failed";
228*795d594fSAndroid Build Coastguard Worker return;
229*795d594fSAndroid Build Coastguard Worker }
230*795d594fSAndroid Build Coastguard Worker #endif
231*795d594fSAndroid Build Coastguard Worker }
232*795d594fSAndroid Build Coastguard Worker
Open(const char * filename,std::string * error_msg)233*795d594fSAndroid Build Coastguard Worker ZipArchive* ZipArchive::Open(const char* filename, std::string* error_msg) {
234*795d594fSAndroid Build Coastguard Worker DCHECK(filename != nullptr);
235*795d594fSAndroid Build Coastguard Worker
236*795d594fSAndroid Build Coastguard Worker ZipArchiveHandle handle;
237*795d594fSAndroid Build Coastguard Worker const int32_t error = OpenArchive(filename, &handle);
238*795d594fSAndroid Build Coastguard Worker if (error != 0) {
239*795d594fSAndroid Build Coastguard Worker *error_msg = std::string(ErrorCodeString(error));
240*795d594fSAndroid Build Coastguard Worker CloseArchive(handle);
241*795d594fSAndroid Build Coastguard Worker return nullptr;
242*795d594fSAndroid Build Coastguard Worker }
243*795d594fSAndroid Build Coastguard Worker
244*795d594fSAndroid Build Coastguard Worker SetCloseOnExec(GetFileDescriptor(handle));
245*795d594fSAndroid Build Coastguard Worker return new ZipArchive(handle);
246*795d594fSAndroid Build Coastguard Worker }
247*795d594fSAndroid Build Coastguard Worker
OpenFromFd(int fd,const char * filename,std::string * error_msg)248*795d594fSAndroid Build Coastguard Worker ZipArchive* ZipArchive::OpenFromFd(int fd, const char* filename, std::string* error_msg) {
249*795d594fSAndroid Build Coastguard Worker return OpenFromFdInternal(fd, /*assume_ownership=*/true, filename, error_msg);
250*795d594fSAndroid Build Coastguard Worker }
251*795d594fSAndroid Build Coastguard Worker
OpenFromOwnedFd(int fd,const char * filename,std::string * error_msg)252*795d594fSAndroid Build Coastguard Worker ZipArchive* ZipArchive::OpenFromOwnedFd(int fd, const char* filename, std::string* error_msg) {
253*795d594fSAndroid Build Coastguard Worker return OpenFromFdInternal(fd, /*assume_ownership=*/false, filename, error_msg);
254*795d594fSAndroid Build Coastguard Worker }
255*795d594fSAndroid Build Coastguard Worker
OpenFromMemory(const uint8_t * data,size_t size,const char * filename,std::string * error_msg)256*795d594fSAndroid Build Coastguard Worker ZipArchive* ZipArchive::OpenFromMemory(const uint8_t* data,
257*795d594fSAndroid Build Coastguard Worker size_t size,
258*795d594fSAndroid Build Coastguard Worker const char* filename,
259*795d594fSAndroid Build Coastguard Worker std::string* error_msg) {
260*795d594fSAndroid Build Coastguard Worker DCHECK(filename != nullptr);
261*795d594fSAndroid Build Coastguard Worker DCHECK(data != nullptr);
262*795d594fSAndroid Build Coastguard Worker
263*795d594fSAndroid Build Coastguard Worker ZipArchiveHandle handle;
264*795d594fSAndroid Build Coastguard Worker const int32_t error = OpenArchiveFromMemory(data, size, filename, &handle);
265*795d594fSAndroid Build Coastguard Worker if (error != 0) {
266*795d594fSAndroid Build Coastguard Worker *error_msg = std::string(ErrorCodeString(error));
267*795d594fSAndroid Build Coastguard Worker CloseArchive(handle);
268*795d594fSAndroid Build Coastguard Worker return nullptr;
269*795d594fSAndroid Build Coastguard Worker }
270*795d594fSAndroid Build Coastguard Worker
271*795d594fSAndroid Build Coastguard Worker return new ZipArchive(handle);
272*795d594fSAndroid Build Coastguard Worker }
273*795d594fSAndroid Build Coastguard Worker
OpenFromFdInternal(int fd,bool assume_ownership,const char * filename,std::string * error_msg)274*795d594fSAndroid Build Coastguard Worker ZipArchive* ZipArchive::OpenFromFdInternal(int fd,
275*795d594fSAndroid Build Coastguard Worker bool assume_ownership,
276*795d594fSAndroid Build Coastguard Worker const char* filename,
277*795d594fSAndroid Build Coastguard Worker std::string* error_msg) {
278*795d594fSAndroid Build Coastguard Worker DCHECK(filename != nullptr);
279*795d594fSAndroid Build Coastguard Worker DCHECK_GT(fd, 0);
280*795d594fSAndroid Build Coastguard Worker
281*795d594fSAndroid Build Coastguard Worker ZipArchiveHandle handle;
282*795d594fSAndroid Build Coastguard Worker const int32_t error = OpenArchiveFd(fd, filename, &handle, assume_ownership);
283*795d594fSAndroid Build Coastguard Worker if (error != 0) {
284*795d594fSAndroid Build Coastguard Worker *error_msg = std::string(ErrorCodeString(error));
285*795d594fSAndroid Build Coastguard Worker CloseArchive(handle);
286*795d594fSAndroid Build Coastguard Worker return nullptr;
287*795d594fSAndroid Build Coastguard Worker }
288*795d594fSAndroid Build Coastguard Worker
289*795d594fSAndroid Build Coastguard Worker SetCloseOnExec(GetFileDescriptor(handle));
290*795d594fSAndroid Build Coastguard Worker return new ZipArchive(handle);
291*795d594fSAndroid Build Coastguard Worker }
292*795d594fSAndroid Build Coastguard Worker
Find(const char * name,std::string * error_msg) const293*795d594fSAndroid Build Coastguard Worker ZipEntry* ZipArchive::Find(const char* name, std::string* error_msg) const {
294*795d594fSAndroid Build Coastguard Worker DCHECK(name != nullptr);
295*795d594fSAndroid Build Coastguard Worker
296*795d594fSAndroid Build Coastguard Worker // Resist the urge to delete the space. <: is a bigraph sequence.
297*795d594fSAndroid Build Coastguard Worker std::unique_ptr< ::ZipEntry> zip_entry(new ::ZipEntry);
298*795d594fSAndroid Build Coastguard Worker const int32_t error = FindEntry(handle_, name, zip_entry.get());
299*795d594fSAndroid Build Coastguard Worker if (error != 0) {
300*795d594fSAndroid Build Coastguard Worker *error_msg = std::string(ErrorCodeString(error));
301*795d594fSAndroid Build Coastguard Worker return nullptr;
302*795d594fSAndroid Build Coastguard Worker }
303*795d594fSAndroid Build Coastguard Worker
304*795d594fSAndroid Build Coastguard Worker return new ZipEntry(handle_, zip_entry.release(), name);
305*795d594fSAndroid Build Coastguard Worker }
306*795d594fSAndroid Build Coastguard Worker
~ZipArchive()307*795d594fSAndroid Build Coastguard Worker ZipArchive::~ZipArchive() {
308*795d594fSAndroid Build Coastguard Worker CloseArchive(handle_);
309*795d594fSAndroid Build Coastguard Worker }
310*795d594fSAndroid Build Coastguard Worker
311*795d594fSAndroid Build Coastguard Worker } // namespace art
312