| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "crazy_linker_zip.h" | 5 #include "crazy_linker_zip.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <sys/mman.h> | 8 #include <sys/mman.h> |
| 9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
| 10 #include <unistd.h> | 10 #include <unistd.h> |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 const int kOffsetOfCentralDirLengthInEndOfCentralDirectory = | 27 const int kOffsetOfCentralDirLengthInEndOfCentralDirectory = |
| 28 kOffsetNumOfEntriesInEndOfCentralDirectory + 2 + 2; | 28 kOffsetNumOfEntriesInEndOfCentralDirectory + 2 + 2; |
| 29 const int kOffsetOfStartOfCentralDirInEndOfCentralDirectory = | 29 const int kOffsetOfStartOfCentralDirInEndOfCentralDirectory = |
| 30 kOffsetOfCentralDirLengthInEndOfCentralDirectory + 4; | 30 kOffsetOfCentralDirLengthInEndOfCentralDirectory + 4; |
| 31 | 31 |
| 32 // http://www.pkware.com/documents/casestudies/APPNOTE.TXT Section 4.3.12 | 32 // http://www.pkware.com/documents/casestudies/APPNOTE.TXT Section 4.3.12 |
| 33 // This marker appears at the start of the central directory | 33 // This marker appears at the start of the central directory |
| 34 const uint32_t kCentralDirHeaderMarker = 0x2014b50; | 34 const uint32_t kCentralDirHeaderMarker = 0x2014b50; |
| 35 | 35 |
| 36 // Offsets of fields in Central Directory Header. | 36 // Offsets of fields in Central Directory Header. |
| 37 const int kOffsetCompressedSizeInCentralDirectory = 4 + 2 + 2 + 2 + 2 + 2 + 2 +
4; |
| 38 const int kOffsetUncompressedSizeInCentralDirectory = |
| 39 kOffsetCompressedSizeInCentralDirectory + 4; |
| 37 const int kOffsetFilenameLengthInCentralDirectory = | 40 const int kOffsetFilenameLengthInCentralDirectory = |
| 38 4 + 2 + 2 + 2 + 2 + 2 + 2 + 4 + 4 + 4; | 41 kOffsetUncompressedSizeInCentralDirectory + 4; |
| 39 const int kOffsetExtraFieldLengthInCentralDirectory = | 42 const int kOffsetExtraFieldLengthInCentralDirectory = |
| 40 kOffsetFilenameLengthInCentralDirectory + 2; | 43 kOffsetFilenameLengthInCentralDirectory + 2; |
| 41 const int kOffsetCommentLengthInCentralDirectory = | 44 const int kOffsetCommentLengthInCentralDirectory = |
| 42 kOffsetExtraFieldLengthInCentralDirectory + 2; | 45 kOffsetExtraFieldLengthInCentralDirectory + 2; |
| 43 const int kOffsetLocalHeaderOffsetInCentralDirectory = | 46 const int kOffsetLocalHeaderOffsetInCentralDirectory = |
| 44 kOffsetCommentLengthInCentralDirectory + 2 + 2 + 2 + 4; | 47 kOffsetCommentLengthInCentralDirectory + 2 + 2 + 2 + 4; |
| 45 const int kOffsetFilenameInCentralDirectory = | 48 const int kOffsetFilenameInCentralDirectory = |
| 46 kOffsetLocalHeaderOffsetInCentralDirectory + 4; | 49 kOffsetLocalHeaderOffsetInCentralDirectory + 4; |
| 47 | 50 |
| 48 // http://www.pkware.com/documents/casestudies/APPNOTE.TXT Section 4.3.7 | 51 // http://www.pkware.com/documents/casestudies/APPNOTE.TXT Section 4.3.7 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 (static_cast<uint32_t>(mem_bytes[offset + 2]) << 16) | | 93 (static_cast<uint32_t>(mem_bytes[offset + 2]) << 16) | |
| 91 (static_cast<uint32_t>(mem_bytes[offset + 3]) << 24); | 94 (static_cast<uint32_t>(mem_bytes[offset + 3]) << 24); |
| 92 } | 95 } |
| 93 | 96 |
| 94 } // unnamed namespace | 97 } // unnamed namespace |
| 95 | 98 |
| 96 namespace crazy { | 99 namespace crazy { |
| 97 | 100 |
| 98 const uint32_t kMaxZipFileLength = 1U << 31; // 2GB | 101 const uint32_t kMaxZipFileLength = 1U << 31; // 2GB |
| 99 | 102 |
| 100 int FindStartOffsetOfFileInZipFile(const char* zip_file, const char* filename) { | 103 |
| 104 OffsetSize FindStartOffsetAndLengthOfFileInZipFile(const char* zip_file, |
| 105 const char* filename) { |
| 106 OffsetSize result(CRAZY_OFFSET_FAILED, -1); |
| 101 // Open the file | 107 // Open the file |
| 102 FileDescriptor fd; | 108 FileDescriptor fd; |
| 103 if (!fd.OpenReadOnly(zip_file)) { | 109 if (!fd.OpenReadOnly(zip_file)) { |
| 104 LOG_ERRNO("%s: open failed trying to open zip file %s\n", | 110 LOG_ERRNO("%s: open failed trying to open zip file %s\n", |
| 105 __FUNCTION__, zip_file); | 111 __FUNCTION__, zip_file); |
| 106 return CRAZY_OFFSET_FAILED; | 112 return result; |
| 107 } | 113 } |
| 108 | 114 |
| 109 // Find the length of the file. | 115 // Find the length of the file. |
| 110 struct stat stat_buf; | 116 struct stat stat_buf; |
| 111 if (stat(zip_file, &stat_buf) == -1) { | 117 if (stat(zip_file, &stat_buf) == -1) { |
| 112 LOG_ERRNO("%s: stat failed trying to stat zip file %s\n", | 118 LOG_ERRNO("%s: stat failed trying to stat zip file %s\n", |
| 113 __FUNCTION__, zip_file); | 119 __FUNCTION__, zip_file); |
| 114 return CRAZY_OFFSET_FAILED; | 120 return result; |
| 115 } | 121 } |
| 116 | 122 |
| 117 if (stat_buf.st_size > kMaxZipFileLength) { | 123 if (stat_buf.st_size > kMaxZipFileLength) { |
| 118 LOG("%s: The size %ld of %s is too large to map\n", | 124 LOG("%s: The size %ld of %s is too large to map\n", |
| 119 __FUNCTION__, stat_buf.st_size, zip_file); | 125 __FUNCTION__, stat_buf.st_size, zip_file); |
| 120 return CRAZY_OFFSET_FAILED; | 126 return result; |
| 121 } | 127 } |
| 122 | 128 |
| 123 // Map the file into memory. | 129 // Map the file into memory. |
| 124 void* mem = fd.Map(NULL, stat_buf.st_size, PROT_READ, MAP_PRIVATE, 0); | 130 void* mem = fd.Map(NULL, stat_buf.st_size, PROT_READ, MAP_PRIVATE, 0); |
| 125 if (mem == MAP_FAILED) { | 131 if (mem == MAP_FAILED) { |
| 126 LOG_ERRNO("%s: mmap failed trying to mmap zip file %s\n", | 132 LOG_ERRNO("%s: mmap failed trying to mmap zip file %s\n", |
| 127 __FUNCTION__, zip_file); | 133 __FUNCTION__, zip_file); |
| 128 return CRAZY_OFFSET_FAILED; | 134 return result; |
| 129 } | 135 } |
| 130 ScopedMMap scoped_mmap(mem, stat_buf.st_size); | 136 ScopedMMap scoped_mmap(mem, stat_buf.st_size); |
| 131 | 137 |
| 132 // Scan backwards from the end of the file searching for the end of | 138 // Scan backwards from the end of the file searching for the end of |
| 133 // central directory marker. | 139 // central directory marker. |
| 134 uint8_t* mem_bytes = static_cast<uint8_t*>(mem); | 140 uint8_t* mem_bytes = static_cast<uint8_t*>(mem); |
| 135 int off; | 141 int off; |
| 136 for (off = stat_buf.st_size - sizeof(kEndOfCentralDirectoryMarker); | 142 for (off = stat_buf.st_size - sizeof(kEndOfCentralDirectoryMarker); |
| 137 off >= 0; --off) { | 143 off >= 0; --off) { |
| 138 if (ReadUInt32(mem_bytes, off) == kEndOfCentralDirectoryMarker) { | 144 if (ReadUInt32(mem_bytes, off) == kEndOfCentralDirectoryMarker) { |
| 139 break; | 145 break; |
| 140 } | 146 } |
| 141 } | 147 } |
| 142 if (off == -1) { | 148 if (off == -1) { |
| 143 LOG("%s: Failed to find end of central directory in %s\n", | 149 LOG("%s: Failed to find end of central directory in %s\n", |
| 144 __FUNCTION__, zip_file); | 150 __FUNCTION__, zip_file); |
| 145 return CRAZY_OFFSET_FAILED; | 151 return result; |
| 146 } | 152 } |
| 147 | 153 |
| 148 // We have located the end of central directory record, now locate | 154 // We have located the end of central directory record, now locate |
| 149 // the central directory by reading the end of central directory record. | 155 // the central directory by reading the end of central directory record. |
| 150 | 156 |
| 151 uint32_t length_of_central_dir = ReadUInt32( | 157 uint32_t length_of_central_dir = ReadUInt32( |
| 152 mem_bytes, off + kOffsetOfCentralDirLengthInEndOfCentralDirectory); | 158 mem_bytes, off + kOffsetOfCentralDirLengthInEndOfCentralDirectory); |
| 153 uint32_t start_of_central_dir = ReadUInt32( | 159 uint32_t start_of_central_dir = ReadUInt32( |
| 154 mem_bytes, off + kOffsetOfStartOfCentralDirInEndOfCentralDirectory); | 160 mem_bytes, off + kOffsetOfStartOfCentralDirInEndOfCentralDirectory); |
| 155 | 161 |
| 156 if (start_of_central_dir > off) { | 162 if (start_of_central_dir > off) { |
| 157 LOG("%s: Found out of range offset %u for start of directory in %s\n", | 163 LOG("%s: Found out of range offset %u for start of directory in %s\n", |
| 158 __FUNCTION__, start_of_central_dir, zip_file); | 164 __FUNCTION__, start_of_central_dir, zip_file); |
| 159 return CRAZY_OFFSET_FAILED; | 165 return result; |
| 160 } | 166 } |
| 161 | 167 |
| 162 uint32_t end_of_central_dir = start_of_central_dir + length_of_central_dir; | 168 uint32_t end_of_central_dir = start_of_central_dir + length_of_central_dir; |
| 163 if (end_of_central_dir > off) { | 169 if (end_of_central_dir > off) { |
| 164 LOG("%s: Found out of range offset %u for end of directory in %s\n", | 170 LOG("%s: Found out of range offset %u for end of directory in %s\n", |
| 165 __FUNCTION__, end_of_central_dir, zip_file); | 171 __FUNCTION__, end_of_central_dir, zip_file); |
| 166 return CRAZY_OFFSET_FAILED; | 172 return result; |
| 167 } | 173 } |
| 168 | 174 |
| 169 uint32_t num_entries = ReadUInt16( | 175 uint32_t num_entries = ReadUInt16( |
| 170 mem_bytes, off + kOffsetNumOfEntriesInEndOfCentralDirectory); | 176 mem_bytes, off + kOffsetNumOfEntriesInEndOfCentralDirectory); |
| 171 | 177 |
| 172 // Read the headers in the central directory and locate the file. | 178 // Read the headers in the central directory and locate the file. |
| 173 off = start_of_central_dir; | 179 off = start_of_central_dir; |
| 174 const int target_len = strlen(filename); | 180 const int target_len = strlen(filename); |
| 175 int n = 0; | 181 int n = 0; |
| 176 for (; n < num_entries && off < end_of_central_dir; ++n) { | 182 for (; n < num_entries && off < end_of_central_dir; ++n) { |
| 177 uint32_t marker = ReadUInt32(mem_bytes, off); | 183 uint32_t marker = ReadUInt32(mem_bytes, off); |
| 178 if (marker != kCentralDirHeaderMarker) { | 184 if (marker != kCentralDirHeaderMarker) { |
| 179 LOG("%s: Failed to find central directory header marker in %s. " | 185 LOG("%s: Failed to find central directory header marker in %s. " |
| 180 "Found 0x%x but expected 0x%x\n", __FUNCTION__, | 186 "Found 0x%x but expected 0x%x\n", __FUNCTION__, |
| 181 zip_file, marker, kCentralDirHeaderMarker); | 187 zip_file, marker, kCentralDirHeaderMarker); |
| 182 return CRAZY_OFFSET_FAILED; | 188 return result; |
| 183 } | 189 } |
| 190 uint32_t compressed_size = |
| 191 ReadUInt32(mem_bytes, off + kOffsetCompressedSizeInCentralDirectory); |
| 192 uint32_t uncompressed_size = |
| 193 ReadUInt32(mem_bytes, off + kOffsetUncompressedSizeInCentralDirectory); |
| 184 uint32_t file_name_length = | 194 uint32_t file_name_length = |
| 185 ReadUInt16(mem_bytes, off + kOffsetFilenameLengthInCentralDirectory); | 195 ReadUInt16(mem_bytes, off + kOffsetFilenameLengthInCentralDirectory); |
| 186 uint32_t extra_field_length = | 196 uint32_t extra_field_length = |
| 187 ReadUInt16(mem_bytes, off + kOffsetExtraFieldLengthInCentralDirectory); | 197 ReadUInt16(mem_bytes, off + kOffsetExtraFieldLengthInCentralDirectory); |
| 188 uint32_t comment_field_length = | 198 uint32_t comment_field_length = |
| 189 ReadUInt16(mem_bytes, off + kOffsetCommentLengthInCentralDirectory); | 199 ReadUInt16(mem_bytes, off + kOffsetCommentLengthInCentralDirectory); |
| 190 uint32_t header_length = kOffsetFilenameInCentralDirectory + | 200 uint32_t header_length = kOffsetFilenameInCentralDirectory + |
| 191 file_name_length + extra_field_length + comment_field_length; | 201 file_name_length + extra_field_length + comment_field_length; |
| 192 | 202 |
| 193 uint32_t local_header_offset = | 203 uint32_t local_header_offset = |
| 194 ReadUInt32(mem_bytes, off + kOffsetLocalHeaderOffsetInCentralDirectory); | 204 ReadUInt32(mem_bytes, off + kOffsetLocalHeaderOffsetInCentralDirectory); |
| 195 | 205 |
| 196 uint8_t* filename_bytes = | 206 uint8_t* filename_bytes = |
| 197 mem_bytes + off + kOffsetFilenameInCentralDirectory; | 207 mem_bytes + off + kOffsetFilenameInCentralDirectory; |
| 198 | 208 |
| 199 if (file_name_length == target_len && | 209 if (file_name_length == target_len && |
| 200 memcmp(filename_bytes, filename, target_len) == 0) { | 210 memcmp(filename_bytes, filename, target_len) == 0) { |
| 201 // Filename matches. Read the local header and compute the offset. | 211 // Filename matches. Read the local header and compute the offset. |
| 202 uint32_t marker = ReadUInt32(mem_bytes, local_header_offset); | 212 uint32_t marker = ReadUInt32(mem_bytes, local_header_offset); |
| 203 if (marker != kLocalHeaderMarker) { | 213 if (marker != kLocalHeaderMarker) { |
| 204 LOG("%s: Failed to find local file header marker in %s. " | 214 LOG("%s: Failed to find local file header marker in %s. " |
| 205 "Found 0x%x but expected 0x%x\n", __FUNCTION__, | 215 "Found 0x%x but expected 0x%x\n", __FUNCTION__, |
| 206 zip_file, marker, kLocalHeaderMarker); | 216 zip_file, marker, kLocalHeaderMarker); |
| 207 return CRAZY_OFFSET_FAILED; | 217 return result; |
| 208 } | 218 } |
| 209 | 219 |
| 210 uint32_t compression_method = | 220 uint32_t compression_method = |
| 211 ReadUInt16( | 221 ReadUInt16( |
| 212 mem_bytes, | 222 mem_bytes, |
| 213 local_header_offset + kOffsetCompressionMethodInLocalHeader); | 223 local_header_offset + kOffsetCompressionMethodInLocalHeader); |
| 214 if (compression_method != kCompressionMethodStored) { | 224 if (compression_method != kCompressionMethodStored) { |
| 215 LOG("%s: %s is compressed within %s. " | 225 LOG("%s: %s is compressed within %s. " |
| 216 "Found compression method %u but expected %u\n", __FUNCTION__, | 226 "Found compression method %u but expected %u\n", __FUNCTION__, |
| 217 filename, zip_file, compression_method, kCompressionMethodStored); | 227 filename, zip_file, compression_method, kCompressionMethodStored); |
| 218 return CRAZY_OFFSET_FAILED; | 228 return result; |
| 229 } |
| 230 |
| 231 if (uncompressed_size != compressed_size) { |
| 232 LOG("%s: Uncompressed size (%d) differs from compressed size (%d).\n", |
| 233 __FUNCTION__, filename, uncompressed_size, compressed_size); |
| 234 return result; |
| 219 } | 235 } |
| 220 | 236 |
| 221 uint32_t file_name_length = | 237 uint32_t file_name_length = |
| 222 ReadUInt16( | 238 ReadUInt16( |
| 223 mem_bytes, | 239 mem_bytes, |
| 224 local_header_offset + kOffsetFilenameLengthInLocalHeader); | 240 local_header_offset + kOffsetFilenameLengthInLocalHeader); |
| 225 uint32_t extra_field_length = | 241 uint32_t extra_field_length = |
| 226 ReadUInt16( | 242 ReadUInt16( |
| 227 mem_bytes, | 243 mem_bytes, |
| 228 local_header_offset + kOffsetExtraFieldLengthInLocalHeader); | 244 local_header_offset + kOffsetExtraFieldLengthInLocalHeader); |
| 229 uint32_t header_length = | 245 uint32_t header_length = |
| 230 kOffsetFilenameInLocalHeader + file_name_length + extra_field_length; | 246 kOffsetFilenameInLocalHeader + file_name_length + extra_field_length; |
| 231 | 247 |
| 232 return local_header_offset + header_length; | 248 result.offset = local_header_offset + header_length; |
| 249 result.size = compressed_size; |
| 250 return result; |
| 233 } | 251 } |
| 234 | 252 |
| 235 off += header_length; | 253 off += header_length; |
| 236 } | 254 } |
| 237 | 255 |
| 238 if (n < num_entries) { | 256 if (n < num_entries) { |
| 239 LOG("%s: Did not find all the expected entries in the central directory. " | 257 LOG("%s: Did not find all the expected entries in the central directory. " |
| 240 "Found %d but expected %d\n", __FUNCTION__, n, num_entries); | 258 "Found %d but expected %d\n", __FUNCTION__, n, num_entries); |
| 241 } | 259 } |
| 242 | 260 |
| 243 if (off < end_of_central_dir) { | 261 if (off < end_of_central_dir) { |
| 244 LOG("%s: There are %d extra bytes at the end of the central directory.\n", | 262 LOG("%s: There are %d extra bytes at the end of the central directory.\n", |
| 245 __FUNCTION__, end_of_central_dir - off); | 263 __FUNCTION__, end_of_central_dir - off); |
| 246 } | 264 } |
| 247 | 265 |
| 248 LOG("%s: Did not find %s in %s\n", __FUNCTION__, filename, zip_file); | 266 LOG("%s: Did not find %s in %s\n", __FUNCTION__, filename, zip_file); |
| 249 return CRAZY_OFFSET_FAILED; | 267 return result; |
| 268 } |
| 269 |
| 270 |
| 271 int FindStartOffsetOfFileInZipFile(const char* zip_file, const char* filename) { |
| 272 return FindStartOffsetAndLengthOfFileInZipFile(zip_file, filename).offset; |
| 250 } | 273 } |
| 251 | 274 |
| 252 } // crazy namespace | 275 } // crazy namespace |
| OLD | NEW |