blob: eea17499704545da7b9f3c39e90cb0f3d823f7a9 [file] [log] [blame]
The Android Open Source Project88b60792009-03-03 19:28:42 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Andy McFadden95ed76b2009-09-29 10:55:32 -070016
The Android Open Source Project88b60792009-03-03 19:28:42 -080017/*
18 * Zip alignment tool
19 */
Mathias Agopian3344b2e2009-06-05 14:55:48 -070020#include "ZipFile.h"
The Android Open Source Project88b60792009-03-03 19:28:42 -080021
The Android Open Source Project88b60792009-03-03 19:28:42 -080022#include <stdio.h>
Mark Salyzyn404fd5b2016-10-17 10:20:33 -070023#include <stdlib.h>
24#include <unistd.h>
The Android Open Source Project88b60792009-03-03 19:28:42 -080025
26using namespace android;
27
28/*
29 * Show program usage.
30 */
31void usage(void)
32{
33 fprintf(stderr, "Zip alignment utility\n");
Andy McFadden95ed76b2009-09-29 10:55:32 -070034 fprintf(stderr, "Copyright (C) 2009 The Android Open Source Project\n\n");
The Android Open Source Project88b60792009-03-03 19:28:42 -080035 fprintf(stderr,
Dmitriy Ivanov13e59652014-07-23 15:27:21 -070036 "Usage: zipalign [-f] [-p] [-v] [-z] <align> infile.zip outfile.zip\n"
Alex Klyubin01d6b592016-04-29 12:32:17 -070037 " zipalign -c [-p] [-v] <align> infile.zip\n\n" );
Andy McFadden95ed76b2009-09-29 10:55:32 -070038 fprintf(stderr,
39 " <align>: alignment in bytes, e.g. '4' provides 32-bit alignment\n");
40 fprintf(stderr, " -c: check alignment only (does not modify file)\n");
41 fprintf(stderr, " -f: overwrite existing outfile.zip\n");
Alex Klyubin01d6b592016-04-29 12:32:17 -070042 fprintf(stderr, " -p: memory page alignment for stored shared object files\n");
Andy McFadden95ed76b2009-09-29 10:55:32 -070043 fprintf(stderr, " -v: verbose output\n");
Raph Levien093d04c2014-07-07 16:00:29 -070044 fprintf(stderr, " -z: recompress using Zopfli\n");
The Android Open Source Project88b60792009-03-03 19:28:42 -080045}
46
Dmitriy Ivanov13e59652014-07-23 15:27:21 -070047static int getAlignment(bool pageAlignSharedLibs, int defaultAlignment,
48 ZipEntry* pEntry) {
49
Narayan Kamathe0b8d192015-02-26 17:57:55 +000050 static const int kPageAlignment = 4096;
51
Dmitriy Ivanov13e59652014-07-23 15:27:21 -070052 if (!pageAlignSharedLibs) {
53 return defaultAlignment;
54 }
55
56 const char* ext = strrchr(pEntry->getFileName(), '.');
57 if (ext && strcmp(ext, ".so") == 0) {
58 return kPageAlignment;
59 }
60
61 return defaultAlignment;
62}
63
The Android Open Source Project88b60792009-03-03 19:28:42 -080064/*
65 * Copy all entries from "pZin" to "pZout", aligning as needed.
66 */
Dmitriy Ivanov13e59652014-07-23 15:27:21 -070067static int copyAndAlign(ZipFile* pZin, ZipFile* pZout, int alignment, bool zopfli,
Dan Willemsenb589ae42015-10-29 21:26:18 +000068 bool pageAlignSharedLibs)
The Android Open Source Project88b60792009-03-03 19:28:42 -080069{
70 int numEntries = pZin->getNumEntries();
71 ZipEntry* pEntry;
72 int bias = 0;
73 status_t status;
74
75 for (int i = 0; i < numEntries; i++) {
76 ZipEntry* pNewEntry;
77 int padding = 0;
78
79 pEntry = pZin->getEntryByIndex(i);
80 if (pEntry == NULL) {
81 fprintf(stderr, "ERROR: unable to retrieve entry %d\n", i);
82 return 1;
83 }
84
85 if (pEntry->isCompressed()) {
86 /* copy the entry without padding */
87 //printf("--- %s: orig at %ld len=%ld (compressed)\n",
88 // pEntry->getFileName(), (long) pEntry->getFileOffset(),
89 // (long) pEntry->getUncompressedLen());
90
Raph Levien093d04c2014-07-07 16:00:29 -070091 if (zopfli) {
Dan Willemsenb589ae42015-10-29 21:26:18 +000092 status = pZout->addRecompress(pZin, pEntry, &pNewEntry);
Raph Levien093d04c2014-07-07 16:00:29 -070093 bias += pNewEntry->getCompressedLen() - pEntry->getCompressedLen();
94 } else {
Dan Willemsenb589ae42015-10-29 21:26:18 +000095 status = pZout->add(pZin, pEntry, padding, &pNewEntry);
Raph Levien093d04c2014-07-07 16:00:29 -070096 }
The Android Open Source Project88b60792009-03-03 19:28:42 -080097 } else {
Dmitriy Ivanov13e59652014-07-23 15:27:21 -070098 const int alignTo = getAlignment(pageAlignSharedLibs, alignment, pEntry);
99
The Android Open Source Project88b60792009-03-03 19:28:42 -0800100 /*
101 * Copy the entry, adjusting as required. We assume that the
102 * file position in the new file will be equal to the file
103 * position in the original.
104 */
Chih-Hung Hsieh0c0d9282018-08-10 15:14:26 -0700105 off_t newOffset = pEntry->getFileOffset() + bias;
Dmitriy Ivanov13e59652014-07-23 15:27:21 -0700106 padding = (alignTo - (newOffset % alignTo)) % alignTo;
The Android Open Source Project88b60792009-03-03 19:28:42 -0800107
108 //printf("--- %s: orig at %ld(+%d) len=%ld, adding pad=%d\n",
109 // pEntry->getFileName(), (long) pEntry->getFileOffset(),
110 // bias, (long) pEntry->getUncompressedLen(), padding);
Dan Willemsenb589ae42015-10-29 21:26:18 +0000111 status = pZout->add(pZin, pEntry, padding, &pNewEntry);
The Android Open Source Project88b60792009-03-03 19:28:42 -0800112 }
113
Elliott Hughesad7d5622018-10-08 11:19:28 -0700114 if (status != OK)
The Android Open Source Project88b60792009-03-03 19:28:42 -0800115 return 1;
116 bias += padding;
117 //printf(" added '%s' at %ld (pad=%d)\n",
118 // pNewEntry->getFileName(), (long) pNewEntry->getFileOffset(),
119 // padding);
120 }
121
122 return 0;
123}
124
125/*
126 * Process a file. We open the input and output files, failing if the
127 * output file exists and "force" wasn't specified.
128 */
129static int process(const char* inFileName, const char* outFileName,
Dan Willemsenb589ae42015-10-29 21:26:18 +0000130 int alignment, bool force, bool zopfli, bool pageAlignSharedLibs)
The Android Open Source Project88b60792009-03-03 19:28:42 -0800131{
132 ZipFile zin, zout;
133
134 //printf("PROCESS: align=%d in='%s' out='%s' force=%d\n",
135 // alignment, inFileName, outFileName, force);
136
137 /* this mode isn't supported -- do a trivial check */
138 if (strcmp(inFileName, outFileName) == 0) {
139 fprintf(stderr, "Input and output can't be same file\n");
140 return 1;
141 }
142
143 /* don't overwrite existing unless given permission */
144 if (!force && access(outFileName, F_OK) == 0) {
145 fprintf(stderr, "Output file '%s' exists\n", outFileName);
146 return 1;
147 }
148
Elliott Hughesad7d5622018-10-08 11:19:28 -0700149 if (zin.open(inFileName, ZipFile::kOpenReadOnly) != OK) {
The Android Open Source Project88b60792009-03-03 19:28:42 -0800150 fprintf(stderr, "Unable to open '%s' as zip archive\n", inFileName);
151 return 1;
152 }
153 if (zout.open(outFileName,
154 ZipFile::kOpenReadWrite|ZipFile::kOpenCreate|ZipFile::kOpenTruncate)
Elliott Hughesad7d5622018-10-08 11:19:28 -0700155 != OK)
The Android Open Source Project88b60792009-03-03 19:28:42 -0800156 {
Jingwen Owen Ou30321392012-08-17 16:21:11 -0700157 fprintf(stderr, "Unable to open '%s' as zip archive\n", outFileName);
The Android Open Source Project88b60792009-03-03 19:28:42 -0800158 return 1;
159 }
160
Dan Willemsenb589ae42015-10-29 21:26:18 +0000161 int result = copyAndAlign(&zin, &zout, alignment, zopfli, pageAlignSharedLibs);
The Android Open Source Project88b60792009-03-03 19:28:42 -0800162 if (result != 0) {
163 printf("zipalign: failed rewriting '%s' to '%s'\n",
164 inFileName, outFileName);
165 }
166 return result;
167}
168
169/*
170 * Verify the alignment of a zip archive.
171 */
Dmitriy Ivanov13e59652014-07-23 15:27:21 -0700172static int verify(const char* fileName, int alignment, bool verbose,
173 bool pageAlignSharedLibs)
The Android Open Source Project88b60792009-03-03 19:28:42 -0800174{
175 ZipFile zipFile;
176 bool foundBad = false;
177
178 if (verbose)
179 printf("Verifying alignment of %s (%d)...\n", fileName, alignment);
180
Elliott Hughesad7d5622018-10-08 11:19:28 -0700181 if (zipFile.open(fileName, ZipFile::kOpenReadOnly) != OK) {
The Android Open Source Project88b60792009-03-03 19:28:42 -0800182 fprintf(stderr, "Unable to open '%s' for verification\n", fileName);
183 return 1;
184 }
185
186 int numEntries = zipFile.getNumEntries();
187 ZipEntry* pEntry;
188
189 for (int i = 0; i < numEntries; i++) {
190 pEntry = zipFile.getEntryByIndex(i);
191 if (pEntry->isCompressed()) {
192 if (verbose) {
Chih-Hung Hsieh0c0d9282018-08-10 15:14:26 -0700193 printf("%8jd %s (OK - compressed)\n",
194 (intmax_t) pEntry->getFileOffset(), pEntry->getFileName());
The Android Open Source Project88b60792009-03-03 19:28:42 -0800195 }
196 } else {
Chih-Hung Hsieh0c0d9282018-08-10 15:14:26 -0700197 off_t offset = pEntry->getFileOffset();
Dmitriy Ivanov13e59652014-07-23 15:27:21 -0700198 const int alignTo = getAlignment(pageAlignSharedLibs, alignment, pEntry);
199 if ((offset % alignTo) != 0) {
The Android Open Source Project88b60792009-03-03 19:28:42 -0800200 if (verbose) {
Chih-Hung Hsieh9b2bf2d2018-08-11 11:33:43 -0700201 printf("%8jd %s (BAD - %jd)\n",
Chih-Hung Hsieh0c0d9282018-08-10 15:14:26 -0700202 (intmax_t) offset, pEntry->getFileName(),
Chih-Hung Hsieh9b2bf2d2018-08-11 11:33:43 -0700203 (intmax_t) (offset % alignTo));
The Android Open Source Project88b60792009-03-03 19:28:42 -0800204 }
205 foundBad = true;
206 } else {
207 if (verbose) {
Chih-Hung Hsieh0c0d9282018-08-10 15:14:26 -0700208 printf("%8jd %s (OK)\n",
209 (intmax_t) offset, pEntry->getFileName());
The Android Open Source Project88b60792009-03-03 19:28:42 -0800210 }
211 }
212 }
213 }
214
215 if (verbose)
216 printf("Verification %s\n", foundBad ? "FAILED" : "succesful");
217
218 return foundBad ? 1 : 0;
219}
220
221/*
222 * Parse args.
223 */
224int main(int argc, char* const argv[])
225{
226 bool wantUsage = false;
Doug Zongker3f2933b2009-04-16 10:16:38 -0700227 bool check = false;
The Android Open Source Project88b60792009-03-03 19:28:42 -0800228 bool force = false;
229 bool verbose = false;
Raph Levien093d04c2014-07-07 16:00:29 -0700230 bool zopfli = false;
Dmitriy Ivanov13e59652014-07-23 15:27:21 -0700231 bool pageAlignSharedLibs = false;
The Android Open Source Project88b60792009-03-03 19:28:42 -0800232 int result = 1;
233 int alignment;
234 char* endp;
235
236 if (argc < 4) {
237 wantUsage = true;
238 goto bail;
239 }
240
241 argc--;
242 argv++;
243
244 while (argc && argv[0][0] == '-') {
245 const char* cp = argv[0] +1;
246
247 while (*cp != '\0') {
248 switch (*cp) {
Doug Zongker3f2933b2009-04-16 10:16:38 -0700249 case 'c':
250 check = true;
251 break;
The Android Open Source Project88b60792009-03-03 19:28:42 -0800252 case 'f':
253 force = true;
254 break;
255 case 'v':
256 verbose = true;
257 break;
Raph Levien093d04c2014-07-07 16:00:29 -0700258 case 'z':
259 zopfli = true;
260 break;
Dmitriy Ivanov13e59652014-07-23 15:27:21 -0700261 case 'p':
262 pageAlignSharedLibs = true;
263 break;
The Android Open Source Project88b60792009-03-03 19:28:42 -0800264 default:
265 fprintf(stderr, "ERROR: unknown flag -%c\n", *cp);
266 wantUsage = true;
267 goto bail;
268 }
269
270 cp++;
271 }
272
273 argc--;
274 argv++;
275 }
276
Doug Zongker3f2933b2009-04-16 10:16:38 -0700277 if (!((check && argc == 2) || (!check && argc == 3))) {
The Android Open Source Project88b60792009-03-03 19:28:42 -0800278 wantUsage = true;
279 goto bail;
280 }
281
282 alignment = strtol(argv[0], &endp, 10);
283 if (*endp != '\0' || alignment <= 0) {
284 fprintf(stderr, "Invalid value for alignment: %s\n", argv[0]);
285 wantUsage = true;
286 goto bail;
287 }
288
Doug Zongker3f2933b2009-04-16 10:16:38 -0700289 if (check) {
290 /* check existing archive for correct alignment */
Dmitriy Ivanov13e59652014-07-23 15:27:21 -0700291 result = verify(argv[1], alignment, verbose, pageAlignSharedLibs);
Doug Zongker3f2933b2009-04-16 10:16:38 -0700292 } else {
293 /* create the new archive */
Dan Willemsenb589ae42015-10-29 21:26:18 +0000294 result = process(argv[1], argv[2], alignment, force, zopfli, pageAlignSharedLibs);
The Android Open Source Project88b60792009-03-03 19:28:42 -0800295
Doug Zongker3f2933b2009-04-16 10:16:38 -0700296 /* trust, but verify */
Dmitriy Ivanov13e59652014-07-23 15:27:21 -0700297 if (result == 0) {
298 result = verify(argv[2], alignment, verbose, pageAlignSharedLibs);
299 }
Doug Zongker3f2933b2009-04-16 10:16:38 -0700300 }
The Android Open Source Project88b60792009-03-03 19:28:42 -0800301
302bail:
303 if (wantUsage) {
304 usage();
305 result = 2;
306 }
307
308 return result;
309}