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 |