diff options
author | Narayan Kamath | 2013-12-11 08:51:51 -0600 |
---|---|---|
committer | Narayan Kamath | 2013-12-11 09:17:06 -0600 |
commit | eaf988532b9e603b1599b7750bfa923fbb39d297 (patch) | |
tree | b6043dc218a8e3f71bafd58da02361c5c2414038 /libziparchive/zip_archive.cc | |
parent | a183f45f7aaee721a9c1cde14cdd47e47a1592e4 (diff) | |
download | platform-system-core-eaf988532b9e603b1599b7750bfa923fbb39d297.tar.gz platform-system-core-eaf988532b9e603b1599b7750bfa923fbb39d297.tar.xz platform-system-core-eaf988532b9e603b1599b7750bfa923fbb39d297.zip |
Use FileMap from libcutil instead of rolling our own.
Adds windows support as a side effect.
Change-Id: I912c1f980f284d01d4f3936291999646ddf6250a
Diffstat (limited to 'libziparchive/zip_archive.cc')
-rw-r--r-- | libziparchive/zip_archive.cc | 110 |
1 files changed, 38 insertions, 72 deletions
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc index 43312b4be..4143facae 100644 --- a/libziparchive/zip_archive.cc +++ b/libziparchive/zip_archive.cc | |||
@@ -28,8 +28,8 @@ | |||
28 | #include <fcntl.h> | 28 | #include <fcntl.h> |
29 | #include <stdlib.h> | 29 | #include <stdlib.h> |
30 | #include <string.h> | 30 | #include <string.h> |
31 | #include <sys/mman.h> | ||
32 | #include <unistd.h> | 31 | #include <unistd.h> |
32 | #include <utils/FileMap.h> | ||
33 | 33 | ||
34 | #include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd | 34 | #include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd |
35 | 35 | ||
@@ -97,6 +97,7 @@ static const char* kErrorMessages[] = { | |||
97 | "Inconsistent information", | 97 | "Inconsistent information", |
98 | "Invalid entry name", | 98 | "Invalid entry name", |
99 | "I/O Error", | 99 | "I/O Error", |
100 | "File mapping failed" | ||
100 | }; | 101 | }; |
101 | 102 | ||
102 | static const int32_t kErrorMessageUpperBound = 0; | 103 | static const int32_t kErrorMessageUpperBound = 0; |
@@ -140,22 +141,12 @@ static const int32_t kInvalidEntryName = -10; | |||
140 | // An I/O related system call (read, lseek, ftruncate, map) failed. | 141 | // An I/O related system call (read, lseek, ftruncate, map) failed. |
141 | static const int32_t kIoError = -11; | 142 | static const int32_t kIoError = -11; |
142 | 143 | ||
143 | static const int32_t kErrorMessageLowerBound = -12; | 144 | // We were not able to mmap the central directory or entry contents. |
145 | static const int32_t kMmapFailed = -12; | ||
144 | 146 | ||
147 | static const int32_t kErrorMessageLowerBound = -13; | ||
145 | 148 | ||
146 | #ifdef PAGE_SHIFT | 149 | static const char kTempMappingFileName[] = "zip: ExtractFileToFile"; |
147 | #define SYSTEM_PAGE_SIZE (1 << PAGE_SHIFT) | ||
148 | #else | ||
149 | #define SYSTEM_PAGE_SIZE 4096 | ||
150 | #endif | ||
151 | |||
152 | struct MemMapping { | ||
153 | uint8_t* addr; // Start of data | ||
154 | size_t length; // Length of data | ||
155 | |||
156 | uint8_t* base_address; // page-aligned base address | ||
157 | size_t base_length; // length of mapping | ||
158 | }; | ||
159 | 150 | ||
160 | /* | 151 | /* |
161 | * A Read-only Zip archive. | 152 | * A Read-only Zip archive. |
@@ -182,7 +173,7 @@ struct ZipArchive { | |||
182 | 173 | ||
183 | /* mapped central directory area */ | 174 | /* mapped central directory area */ |
184 | off64_t directory_offset; | 175 | off64_t directory_offset; |
185 | MemMapping directory_map; | 176 | android::FileMap* directory_map; |
186 | 177 | ||
187 | /* number of entries in the Zip archive */ | 178 | /* number of entries in the Zip archive */ |
188 | uint16_t num_entries; | 179 | uint16_t num_entries; |
@@ -198,43 +189,17 @@ struct ZipArchive { | |||
198 | }; | 189 | }; |
199 | 190 | ||
200 | // Returns 0 on success and negative values on failure. | 191 | // Returns 0 on success and negative values on failure. |
201 | static int32_t MapFileSegment(const int fd, const off64_t start, const size_t length, | 192 | static android::FileMap* MapFileSegment(const int fd, const off64_t start, |
202 | const int prot, const int flags, MemMapping *mapping) { | 193 | const size_t length, const bool read_only, |
203 | /* adjust to be page-aligned */ | 194 | const char* debug_file_name) { |
204 | const int adjust = start % SYSTEM_PAGE_SIZE; | 195 | android::FileMap* file_map = new android::FileMap; |
205 | const off64_t actual_start = start - adjust; | 196 | const bool success = file_map->create(debug_file_name, fd, start, length, read_only); |
206 | const off64_t actual_length = length + adjust; | 197 | if (!success) { |
207 | 198 | file_map->release(); | |
208 | void* map_addr = mmap(NULL, actual_length, prot, flags, fd, actual_start); | 199 | return NULL; |
209 | if (map_addr == MAP_FAILED) { | ||
210 | ALOGW("mmap(%llx, R, FILE|SHARED, %d, %llx) failed: %s", | ||
211 | actual_length, fd, actual_start, strerror(errno)); | ||
212 | return kIoError; | ||
213 | } | 200 | } |
214 | 201 | ||
215 | mapping->base_address = (uint8_t*) map_addr; | 202 | return file_map; |
216 | mapping->base_length = actual_length; | ||
217 | mapping->addr = (uint8_t*) map_addr + adjust; | ||
218 | mapping->length = length; | ||
219 | |||
220 | ALOGV("mmap seg (st=%d ln=%d): b=%p bl=%d ad=%p ln=%d", | ||
221 | start, length, mapping->base_address, mapping->base_length, | ||
222 | mapping->addr, mapping->length); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static void ReleaseMappedSegment(MemMapping* map) { | ||
228 | if (map->base_address == 0 || map->base_length == 0) { | ||
229 | return; | ||
230 | } | ||
231 | |||
232 | if (munmap(map->base_address, map->base_length) < 0) { | ||
233 | ALOGW("munmap(%p, %d) failed: %s", | ||
234 | map->base_address, map->base_length, strerror(errno)); | ||
235 | } else { | ||
236 | ALOGV("munmap(%p, %d) succeeded", map->base_address, map->base_length); | ||
237 | } | ||
238 | } | 203 | } |
239 | 204 | ||
240 | static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) { | 205 | static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) { |
@@ -430,13 +395,14 @@ static int32_t MapCentralDirectory0(int fd, const char* debug_file_name, | |||
430 | * It all looks good. Create a mapping for the CD, and set the fields | 395 | * It all looks good. Create a mapping for the CD, and set the fields |
431 | * in archive. | 396 | * in archive. |
432 | */ | 397 | */ |
433 | const int32_t result = MapFileSegment(fd, dir_offset, dir_size, | 398 | android::FileMap* map = MapFileSegment(fd, dir_offset, dir_size, |
434 | PROT_READ, MAP_FILE | MAP_SHARED, | 399 | true /* read only */, debug_file_name); |
435 | &(archive->directory_map)); | 400 | if (map == NULL) { |
436 | if (result) { | 401 | archive->directory_map = NULL; |
437 | return result; | 402 | return kMmapFailed; |
438 | } | 403 | } |
439 | 404 | ||
405 | archive->directory_map = map; | ||
440 | archive->num_entries = num_entries; | 406 | archive->num_entries = num_entries; |
441 | archive->directory_offset = dir_offset; | 407 | archive->directory_offset = dir_offset; |
442 | 408 | ||
@@ -506,8 +472,8 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name, | |||
506 | */ | 472 | */ |
507 | static int32_t ParseZipArchive(ZipArchive* archive) { | 473 | static int32_t ParseZipArchive(ZipArchive* archive) { |
508 | int32_t result = -1; | 474 | int32_t result = -1; |
509 | const uint8_t* cd_ptr = (const uint8_t*) archive->directory_map.addr; | 475 | const uint8_t* cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr(); |
510 | size_t cd_length = archive->directory_map.length; | 476 | size_t cd_length = archive->directory_map->getDataLength(); |
511 | uint16_t num_entries = archive->num_entries; | 477 | uint16_t num_entries = archive->num_entries; |
512 | 478 | ||
513 | /* | 479 | /* |
@@ -621,7 +587,9 @@ void CloseArchive(ZipArchiveHandle handle) { | |||
621 | close(archive->fd); | 587 | close(archive->fd); |
622 | } | 588 | } |
623 | 589 | ||
624 | ReleaseMappedSegment(&archive->directory_map); | 590 | if (archive->directory_map != NULL) { |
591 | archive->directory_map->release(); | ||
592 | } | ||
625 | free(archive->hash_table); | 593 | free(archive->hash_table); |
626 | 594 | ||
627 | /* ensure nobody tries to use the ZipArchive after it's closed */ | 595 | /* ensure nobody tries to use the ZipArchive after it's closed */ |
@@ -668,7 +636,7 @@ static inline ssize_t ReadAtOffset(int fd, uint8_t* buf, size_t len, | |||
668 | // is Windows. Only recent versions of windows support unix like forks, | 636 | // is Windows. Only recent versions of windows support unix like forks, |
669 | // and even there the semantics are quite different. | 637 | // and even there the semantics are quite different. |
670 | if (lseek64(fd, off, SEEK_SET) != off) { | 638 | if (lseek64(fd, off, SEEK_SET) != off) { |
671 | ALOGW("Zip: failed seek to offset %lld", name_offset); | 639 | ALOGW("Zip: failed seek to offset %lld", off); |
672 | return kIoError; | 640 | return kIoError; |
673 | } | 641 | } |
674 | 642 | ||
@@ -691,8 +659,8 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent, | |||
691 | // the name that's in the hash table is a pointer to a location within | 659 | // the name that's in the hash table is a pointer to a location within |
692 | // this mapped region. | 660 | // this mapped region. |
693 | const unsigned char* base_ptr = (const unsigned char*) | 661 | const unsigned char* base_ptr = (const unsigned char*) |
694 | archive->directory_map.addr; | 662 | archive->directory_map->getDataPtr(); |
695 | if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.length) { | 663 | if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) { |
696 | ALOGW("Zip: Invalid entry pointer"); | 664 | ALOGW("Zip: Invalid entry pointer"); |
697 | return kInvalidOffset; | 665 | return kInvalidOffset; |
698 | } | 666 | } |
@@ -1045,18 +1013,16 @@ int32_t ExtractEntryToFile(ZipArchiveHandle handle, | |||
1045 | return kIoError; | 1013 | return kIoError; |
1046 | } | 1014 | } |
1047 | 1015 | ||
1048 | MemMapping mapping; | 1016 | android::FileMap* map = MapFileSegment(fd, 0, declared_length, |
1049 | int32_t error = MapFileSegment(fd, 0, declared_length, | 1017 | false, kTempMappingFileName); |
1050 | PROT_READ | PROT_WRITE, | 1018 | if (map == NULL) { |
1051 | MAP_FILE | MAP_SHARED, | 1019 | return kMmapFailed; |
1052 | &mapping); | ||
1053 | if (error) { | ||
1054 | return error; | ||
1055 | } | 1020 | } |
1056 | 1021 | ||
1057 | error = ExtractToMemory(handle, entry, mapping.addr, | 1022 | const int32_t error = ExtractToMemory(handle, entry, |
1058 | mapping.length); | 1023 | reinterpret_cast<uint8_t*>(map->getDataPtr()), |
1059 | ReleaseMappedSegment(&mapping); | 1024 | map->getDataLength()); |
1025 | map->release(); | ||
1060 | return error; | 1026 | return error; |
1061 | } | 1027 | } |
1062 | 1028 | ||