blob: 95332a35eb7d55f481134dc439b946d49331a547 [file] [log] [blame]
Kenny Root7cee34a2010-06-01 10:34:29 -07001/*
2 * Copyright (C) 2010 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 */
16
17#include <errno.h>
18#include <fcntl.h>
19#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23
24#define LOG_TAG "ObbFile"
Kenny Rootddb76c42010-11-24 12:56:06 -080025
Mathias Agopianb13b9bd2012-02-17 18:27:36 -080026#include <androidfw/ObbFile.h>
Kenny Rootddb76c42010-11-24 12:56:06 -080027#include <utils/Compat.h>
Kenny Root7cee34a2010-06-01 10:34:29 -070028#include <utils/Log.h>
Kenny Root7cee34a2010-06-01 10:34:29 -070029
30//#define DEBUG 1
31
32#define kFooterTagSize 8 /* last two 32-bit integers */
33
Kenny Root3b1abba2010-10-13 15:00:07 -070034#define kFooterMinSize 33 /* 32-bit signature version (4 bytes)
Kenny Root02ca31f2010-08-12 07:36:02 -070035 * 32-bit package version (4 bytes)
36 * 32-bit flags (4 bytes)
Kenny Root3b1abba2010-10-13 15:00:07 -070037 * 64-bit salt (8 bytes)
38 * 32-bit package name size (4 bytes)
Kenny Root02ca31f2010-08-12 07:36:02 -070039 * >=1-character package name (1 byte)
40 * 32-bit footer size (4 bytes)
41 * 32-bit footer marker (4 bytes)
Kenny Root7cee34a2010-06-01 10:34:29 -070042 */
43
44#define kMaxBufSize 32768 /* Maximum file read buffer */
45
46#define kSignature 0x01059983U /* ObbFile signature */
47
48#define kSigVersion 1 /* We only know about signature version 1 */
49
50/* offsets in version 1 of the header */
51#define kPackageVersionOffset 4
Kenny Root02ca31f2010-08-12 07:36:02 -070052#define kFlagsOffset 8
Kenny Root3b1abba2010-10-13 15:00:07 -070053#define kSaltOffset 12
54#define kPackageNameLenOffset 20
55#define kPackageNameOffset 24
Kenny Root7cee34a2010-06-01 10:34:29 -070056
57/*
58 * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
59 * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
60 * not already defined, then define it here.
61 */
62#ifndef TEMP_FAILURE_RETRY
63/* Used to retry syscalls that can return EINTR. */
64#define TEMP_FAILURE_RETRY(exp) ({ \
65 typeof (exp) _rc; \
66 do { \
67 _rc = (exp); \
68 } while (_rc == -1 && errno == EINTR); \
69 _rc; })
70#endif
71
Kenny Root7cee34a2010-06-01 10:34:29 -070072
73namespace android {
74
Kenny Root3b1abba2010-10-13 15:00:07 -070075ObbFile::ObbFile()
76 : mPackageName("")
77 , mVersion(-1)
78 , mFlags(0)
Kenny Root02ca31f2010-08-12 07:36:02 -070079{
Kenny Root3b1abba2010-10-13 15:00:07 -070080 memset(mSalt, 0, sizeof(mSalt));
Kenny Root7cee34a2010-06-01 10:34:29 -070081}
82
83ObbFile::~ObbFile() {
84}
85
86bool ObbFile::readFrom(const char* filename)
87{
88 int fd;
89 bool success = false;
90
91 fd = ::open(filename, O_RDONLY);
92 if (fd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +000093 ALOGW("couldn't open file %s: %s", filename, strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -070094 goto out;
95 }
96 success = readFrom(fd);
97 close(fd);
98
Kenny Root7cee34a2010-06-01 10:34:29 -070099 if (!success) {
Steve Block8564c8d2012-01-05 23:22:43 +0000100 ALOGW("failed to read from %s (fd=%d)\n", filename, fd);
Kenny Root7cee34a2010-06-01 10:34:29 -0700101 }
Kenny Root87315aa2010-07-12 09:02:18 -0700102
103out:
Kenny Root7cee34a2010-06-01 10:34:29 -0700104 return success;
105}
106
107bool ObbFile::readFrom(int fd)
108{
109 if (fd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000110 ALOGW("attempt to read from invalid fd\n");
Kenny Root7cee34a2010-06-01 10:34:29 -0700111 return false;
112 }
113
114 return parseObbFile(fd);
115}
116
117bool ObbFile::parseObbFile(int fd)
118{
Kenny Rootddb76c42010-11-24 12:56:06 -0800119 off64_t fileLength = lseek64(fd, 0, SEEK_END);
Kenny Root7cee34a2010-06-01 10:34:29 -0700120
121 if (fileLength < kFooterMinSize) {
122 if (fileLength < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000123 ALOGW("error seeking in ObbFile: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700124 } else {
Andreas Gampe2204f0b2014-10-21 23:04:54 -0700125 ALOGW("file is only %lld (less than %d minimum)\n", (long long int)fileLength, kFooterMinSize);
Kenny Root7cee34a2010-06-01 10:34:29 -0700126 }
127 return false;
128 }
129
130 ssize_t actual;
131 size_t footerSize;
132
133 {
Kenny Rootddb76c42010-11-24 12:56:06 -0800134 lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);
Kenny Root7cee34a2010-06-01 10:34:29 -0700135
Elliott Hughesc367d482013-10-29 13:12:55 -0700136 char footer[kFooterTagSize];
Kenny Root7cee34a2010-06-01 10:34:29 -0700137 actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize));
138 if (actual != kFooterTagSize) {
Steve Block8564c8d2012-01-05 23:22:43 +0000139 ALOGW("couldn't read footer signature: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700140 return false;
141 }
142
143 unsigned int fileSig = get4LE((unsigned char*)footer + sizeof(int32_t));
144 if (fileSig != kSignature) {
Steve Block8564c8d2012-01-05 23:22:43 +0000145 ALOGW("footer didn't match magic string (expected 0x%08x; got 0x%08x)\n",
Kenny Root7cee34a2010-06-01 10:34:29 -0700146 kSignature, fileSig);
147 return false;
148 }
149
150 footerSize = get4LE((unsigned char*)footer);
151 if (footerSize > (size_t)fileLength - kFooterTagSize
152 || footerSize > kMaxBufSize) {
Andreas Gampe2204f0b2014-10-21 23:04:54 -0700153 ALOGW("claimed footer size is too large (0x%08zx; file size is 0x%08lld)\n",
154 footerSize, (long long int)fileLength);
Kenny Root7cee34a2010-06-01 10:34:29 -0700155 return false;
156 }
Kenny Root87315aa2010-07-12 09:02:18 -0700157
Kenny Root6e7ac5f2010-07-19 10:31:34 -0700158 if (footerSize < (kFooterMinSize - kFooterTagSize)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000159 ALOGW("claimed footer size is too small (0x%zx; minimum size is 0x%x)\n",
Kenny Root6e7ac5f2010-07-19 10:31:34 -0700160 footerSize, kFooterMinSize - kFooterTagSize);
Kenny Root87315aa2010-07-12 09:02:18 -0700161 return false;
162 }
Kenny Root7cee34a2010-06-01 10:34:29 -0700163 }
164
Kenny Rootddb76c42010-11-24 12:56:06 -0800165 off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
166 if (lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
Andreas Gampe2204f0b2014-10-21 23:04:54 -0700167 ALOGW("seek %lld failed: %s\n", (long long int)fileOffset, strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700168 return false;
169 }
170
Kenny Root6e7ac5f2010-07-19 10:31:34 -0700171 mFooterStart = fileOffset;
172
Kenny Root87315aa2010-07-12 09:02:18 -0700173 char* scanBuf = (char*)malloc(footerSize);
Kenny Root7cee34a2010-06-01 10:34:29 -0700174 if (scanBuf == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000175 ALOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700176 return false;
177 }
178
Kenny Root87315aa2010-07-12 09:02:18 -0700179 actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, footerSize));
Kenny Root7cee34a2010-06-01 10:34:29 -0700180 // readAmount is guaranteed to be less than kMaxBufSize
Kenny Root87315aa2010-07-12 09:02:18 -0700181 if (actual != (ssize_t)footerSize) {
Steve Block6215d3f2012-01-04 20:05:49 +0000182 ALOGI("couldn't read ObbFile footer: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700183 free(scanBuf);
184 return false;
185 }
186
187#ifdef DEBUG
Kenny Root87315aa2010-07-12 09:02:18 -0700188 for (int i = 0; i < footerSize; ++i) {
Steve Block6215d3f2012-01-04 20:05:49 +0000189 ALOGI("char: 0x%02x\n", scanBuf[i]);
Kenny Root7cee34a2010-06-01 10:34:29 -0700190 }
191#endif
192
193 uint32_t sigVersion = get4LE((unsigned char*)scanBuf);
194 if (sigVersion != kSigVersion) {
Steve Block8564c8d2012-01-05 23:22:43 +0000195 ALOGW("Unsupported ObbFile version %d\n", sigVersion);
Kenny Root7cee34a2010-06-01 10:34:29 -0700196 free(scanBuf);
197 return false;
198 }
199
200 mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
Kenny Root02ca31f2010-08-12 07:36:02 -0700201 mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset);
Kenny Root7cee34a2010-06-01 10:34:29 -0700202
Kenny Root3b1abba2010-10-13 15:00:07 -0700203 memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt));
204
Kenny Rootddb76c42010-11-24 12:56:06 -0800205 size_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
206 if (packageNameLen == 0
Kenny Root7cee34a2010-06-01 10:34:29 -0700207 || packageNameLen > (footerSize - kPackageNameOffset)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000208 ALOGW("bad ObbFile package name length (0x%04zx; 0x%04zx possible)\n",
Kenny Root87315aa2010-07-12 09:02:18 -0700209 packageNameLen, footerSize - kPackageNameOffset);
Kenny Root7cee34a2010-06-01 10:34:29 -0700210 free(scanBuf);
211 return false;
212 }
213
214 char* packageName = reinterpret_cast<char*>(scanBuf + kPackageNameOffset);
215 mPackageName = String8(const_cast<char*>(packageName), packageNameLen);
216
217 free(scanBuf);
Kenny Root87315aa2010-07-12 09:02:18 -0700218
219#ifdef DEBUG
Steve Block6215d3f2012-01-04 20:05:49 +0000220 ALOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
Kenny Root87315aa2010-07-12 09:02:18 -0700221#endif
222
Kenny Root7cee34a2010-06-01 10:34:29 -0700223 return true;
224}
225
226bool ObbFile::writeTo(const char* filename)
227{
228 int fd;
229 bool success = false;
230
231 fd = ::open(filename, O_WRONLY);
232 if (fd < 0) {
233 goto out;
234 }
235 success = writeTo(fd);
236 close(fd);
237
238out:
239 if (!success) {
Steve Block8564c8d2012-01-05 23:22:43 +0000240 ALOGW("failed to write to %s: %s\n", filename, strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700241 }
242 return success;
243}
244
245bool ObbFile::writeTo(int fd)
246{
247 if (fd < 0) {
248 return false;
249 }
250
Kenny Rootddb76c42010-11-24 12:56:06 -0800251 lseek64(fd, 0, SEEK_END);
Kenny Root87315aa2010-07-12 09:02:18 -0700252
Kenny Root7cee34a2010-06-01 10:34:29 -0700253 if (mPackageName.size() == 0 || mVersion == -1) {
Steve Block8564c8d2012-01-05 23:22:43 +0000254 ALOGW("tried to write uninitialized ObbFile data\n");
Kenny Root7cee34a2010-06-01 10:34:29 -0700255 return false;
256 }
257
258 unsigned char intBuf[sizeof(uint32_t)+1];
259 memset(&intBuf, 0, sizeof(intBuf));
260
261 put4LE(intBuf, kSigVersion);
262 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000263 ALOGW("couldn't write signature version: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700264 return false;
265 }
266
267 put4LE(intBuf, mVersion);
268 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000269 ALOGW("couldn't write package version\n");
Kenny Root7cee34a2010-06-01 10:34:29 -0700270 return false;
271 }
272
Kenny Root02ca31f2010-08-12 07:36:02 -0700273 put4LE(intBuf, mFlags);
274 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000275 ALOGW("couldn't write package version\n");
Kenny Root3b1abba2010-10-13 15:00:07 -0700276 return false;
277 }
278
279 if (write(fd, mSalt, sizeof(mSalt)) != (ssize_t)sizeof(mSalt)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000280 ALOGW("couldn't write salt: %s\n", strerror(errno));
Kenny Root02ca31f2010-08-12 07:36:02 -0700281 return false;
282 }
283
Kenny Root7cee34a2010-06-01 10:34:29 -0700284 size_t packageNameLen = mPackageName.size();
285 put4LE(intBuf, packageNameLen);
286 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000287 ALOGW("couldn't write package name length: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700288 return false;
289 }
290
291 if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
Steve Block8564c8d2012-01-05 23:22:43 +0000292 ALOGW("couldn't write package name: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700293 return false;
294 }
295
Kenny Root02ca31f2010-08-12 07:36:02 -0700296 put4LE(intBuf, kPackageNameOffset + packageNameLen);
Kenny Root7cee34a2010-06-01 10:34:29 -0700297 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000298 ALOGW("couldn't write footer size: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700299 return false;
300 }
301
302 put4LE(intBuf, kSignature);
303 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000304 ALOGW("couldn't write footer magic signature: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700305 return false;
306 }
307
308 return true;
309}
310
Kenny Root6e7ac5f2010-07-19 10:31:34 -0700311bool ObbFile::removeFrom(const char* filename)
312{
313 int fd;
314 bool success = false;
315
316 fd = ::open(filename, O_RDWR);
317 if (fd < 0) {
318 goto out;
319 }
320 success = removeFrom(fd);
321 close(fd);
322
323out:
324 if (!success) {
Steve Block8564c8d2012-01-05 23:22:43 +0000325 ALOGW("failed to remove signature from %s: %s\n", filename, strerror(errno));
Kenny Root6e7ac5f2010-07-19 10:31:34 -0700326 }
327 return success;
328}
329
330bool ObbFile::removeFrom(int fd)
331{
332 if (fd < 0) {
333 return false;
334 }
335
336 if (!readFrom(fd)) {
337 return false;
338 }
339
Nick Kralevich9709a1f2015-04-24 20:25:50 -0700340 if (ftruncate(fd, mFooterStart) == -1) {
341 return false;
342 }
Kenny Root6e7ac5f2010-07-19 10:31:34 -0700343
344 return true;
345}
346
Kenny Root7cee34a2010-06-01 10:34:29 -0700347}