blob: 2c3724c0af08407ad26057a5b7160f354a962956 [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"
25#include <utils/Log.h>
26#include <utils/ObbFile.h>
27
28//#define DEBUG 1
29
30#define kFooterTagSize 8 /* last two 32-bit integers */
31
Kenny Root3b1abba2010-10-13 15:00:07 -070032#define kFooterMinSize 33 /* 32-bit signature version (4 bytes)
Kenny Root02ca31f2010-08-12 07:36:02 -070033 * 32-bit package version (4 bytes)
34 * 32-bit flags (4 bytes)
Kenny Root3b1abba2010-10-13 15:00:07 -070035 * 64-bit salt (8 bytes)
36 * 32-bit package name size (4 bytes)
Kenny Root02ca31f2010-08-12 07:36:02 -070037 * >=1-character package name (1 byte)
38 * 32-bit footer size (4 bytes)
39 * 32-bit footer marker (4 bytes)
Kenny Root7cee34a2010-06-01 10:34:29 -070040 */
41
42#define kMaxBufSize 32768 /* Maximum file read buffer */
43
44#define kSignature 0x01059983U /* ObbFile signature */
45
46#define kSigVersion 1 /* We only know about signature version 1 */
47
48/* offsets in version 1 of the header */
49#define kPackageVersionOffset 4
Kenny Root02ca31f2010-08-12 07:36:02 -070050#define kFlagsOffset 8
Kenny Root3b1abba2010-10-13 15:00:07 -070051#define kSaltOffset 12
52#define kPackageNameLenOffset 20
53#define kPackageNameOffset 24
Kenny Root7cee34a2010-06-01 10:34:29 -070054
55/*
56 * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
57 * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
58 * not already defined, then define it here.
59 */
60#ifndef TEMP_FAILURE_RETRY
61/* Used to retry syscalls that can return EINTR. */
62#define TEMP_FAILURE_RETRY(exp) ({ \
63 typeof (exp) _rc; \
64 do { \
65 _rc = (exp); \
66 } while (_rc == -1 && errno == EINTR); \
67 _rc; })
68#endif
69
70/*
71 * Work around situations where off_t is 64-bit and use off64_t in
72 * situations where it's 32-bit.
73 */
74#ifdef OFF_T_IS_64_BIT
75#define my_lseek64 lseek
76typedef off_t my_off64_t;
77#else
78#define my_lseek64 lseek64
79typedef off64_t my_off64_t;
80#endif
81
82namespace android {
83
Kenny Root3b1abba2010-10-13 15:00:07 -070084ObbFile::ObbFile()
85 : mPackageName("")
86 , mVersion(-1)
87 , mFlags(0)
Kenny Root02ca31f2010-08-12 07:36:02 -070088{
Kenny Root3b1abba2010-10-13 15:00:07 -070089 memset(mSalt, 0, sizeof(mSalt));
Kenny Root7cee34a2010-06-01 10:34:29 -070090}
91
92ObbFile::~ObbFile() {
93}
94
95bool ObbFile::readFrom(const char* filename)
96{
97 int fd;
98 bool success = false;
99
100 fd = ::open(filename, O_RDONLY);
101 if (fd < 0) {
Kenny Root87315aa2010-07-12 09:02:18 -0700102 LOGW("couldn't open file %s: %s", filename, strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700103 goto out;
104 }
105 success = readFrom(fd);
106 close(fd);
107
Kenny Root7cee34a2010-06-01 10:34:29 -0700108 if (!success) {
Kenny Root87315aa2010-07-12 09:02:18 -0700109 LOGW("failed to read from %s (fd=%d)\n", filename, fd);
Kenny Root7cee34a2010-06-01 10:34:29 -0700110 }
Kenny Root87315aa2010-07-12 09:02:18 -0700111
112out:
Kenny Root7cee34a2010-06-01 10:34:29 -0700113 return success;
114}
115
116bool ObbFile::readFrom(int fd)
117{
118 if (fd < 0) {
Kenny Root87315aa2010-07-12 09:02:18 -0700119 LOGW("attempt to read from invalid fd\n");
Kenny Root7cee34a2010-06-01 10:34:29 -0700120 return false;
121 }
122
123 return parseObbFile(fd);
124}
125
126bool ObbFile::parseObbFile(int fd)
127{
128 my_off64_t fileLength = my_lseek64(fd, 0, SEEK_END);
129
130 if (fileLength < kFooterMinSize) {
131 if (fileLength < 0) {
132 LOGW("error seeking in ObbFile: %s\n", strerror(errno));
133 } else {
134 LOGW("file is only %lld (less than %d minimum)\n", fileLength, kFooterMinSize);
135 }
136 return false;
137 }
138
139 ssize_t actual;
140 size_t footerSize;
141
142 {
143 my_lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);
144
145 char *footer = new char[kFooterTagSize];
146 actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize));
147 if (actual != kFooterTagSize) {
148 LOGW("couldn't read footer signature: %s\n", strerror(errno));
149 return false;
150 }
151
152 unsigned int fileSig = get4LE((unsigned char*)footer + sizeof(int32_t));
153 if (fileSig != kSignature) {
154 LOGW("footer didn't match magic string (expected 0x%08x; got 0x%08x)\n",
155 kSignature, fileSig);
156 return false;
157 }
158
159 footerSize = get4LE((unsigned char*)footer);
160 if (footerSize > (size_t)fileLength - kFooterTagSize
161 || footerSize > kMaxBufSize) {
Kenny Root87315aa2010-07-12 09:02:18 -0700162 LOGW("claimed footer size is too large (0x%08zx; file size is 0x%08llx)\n",
Kenny Root7cee34a2010-06-01 10:34:29 -0700163 footerSize, fileLength);
164 return false;
165 }
Kenny Root87315aa2010-07-12 09:02:18 -0700166
Kenny Root6e7ac5f2010-07-19 10:31:34 -0700167 if (footerSize < (kFooterMinSize - kFooterTagSize)) {
168 LOGW("claimed footer size is too small (0x%zx; minimum size is 0x%x)\n",
169 footerSize, kFooterMinSize - kFooterTagSize);
Kenny Root87315aa2010-07-12 09:02:18 -0700170 return false;
171 }
Kenny Root7cee34a2010-06-01 10:34:29 -0700172 }
173
174 my_off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
175 if (my_lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
176 LOGW("seek %lld failed: %s\n", fileOffset, strerror(errno));
177 return false;
178 }
179
Kenny Root6e7ac5f2010-07-19 10:31:34 -0700180 mFooterStart = fileOffset;
181
Kenny Root87315aa2010-07-12 09:02:18 -0700182 char* scanBuf = (char*)malloc(footerSize);
Kenny Root7cee34a2010-06-01 10:34:29 -0700183 if (scanBuf == NULL) {
184 LOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
185 return false;
186 }
187
Kenny Root87315aa2010-07-12 09:02:18 -0700188 actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, footerSize));
Kenny Root7cee34a2010-06-01 10:34:29 -0700189 // readAmount is guaranteed to be less than kMaxBufSize
Kenny Root87315aa2010-07-12 09:02:18 -0700190 if (actual != (ssize_t)footerSize) {
Kenny Root7cee34a2010-06-01 10:34:29 -0700191 LOGI("couldn't read ObbFile footer: %s\n", strerror(errno));
192 free(scanBuf);
193 return false;
194 }
195
196#ifdef DEBUG
Kenny Root87315aa2010-07-12 09:02:18 -0700197 for (int i = 0; i < footerSize; ++i) {
Kenny Root3b1abba2010-10-13 15:00:07 -0700198 LOGI("char: 0x%02x\n", scanBuf[i]);
Kenny Root7cee34a2010-06-01 10:34:29 -0700199 }
200#endif
201
202 uint32_t sigVersion = get4LE((unsigned char*)scanBuf);
203 if (sigVersion != kSigVersion) {
204 LOGW("Unsupported ObbFile version %d\n", sigVersion);
205 free(scanBuf);
206 return false;
207 }
208
209 mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
Kenny Root02ca31f2010-08-12 07:36:02 -0700210 mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset);
Kenny Root7cee34a2010-06-01 10:34:29 -0700211
Kenny Root3b1abba2010-10-13 15:00:07 -0700212 memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt));
213
Kenny Root7cee34a2010-06-01 10:34:29 -0700214 uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
215 if (packageNameLen <= 0
216 || packageNameLen > (footerSize - kPackageNameOffset)) {
Kenny Root87315aa2010-07-12 09:02:18 -0700217 LOGW("bad ObbFile package name length (0x%04x; 0x%04x possible)\n",
218 packageNameLen, footerSize - kPackageNameOffset);
Kenny Root7cee34a2010-06-01 10:34:29 -0700219 free(scanBuf);
220 return false;
221 }
222
223 char* packageName = reinterpret_cast<char*>(scanBuf + kPackageNameOffset);
224 mPackageName = String8(const_cast<char*>(packageName), packageNameLen);
225
226 free(scanBuf);
Kenny Root87315aa2010-07-12 09:02:18 -0700227
228#ifdef DEBUG
229 LOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
230#endif
231
Kenny Root7cee34a2010-06-01 10:34:29 -0700232 return true;
233}
234
235bool ObbFile::writeTo(const char* filename)
236{
237 int fd;
238 bool success = false;
239
240 fd = ::open(filename, O_WRONLY);
241 if (fd < 0) {
242 goto out;
243 }
244 success = writeTo(fd);
245 close(fd);
246
247out:
248 if (!success) {
249 LOGW("failed to write to %s: %s\n", filename, strerror(errno));
250 }
251 return success;
252}
253
254bool ObbFile::writeTo(int fd)
255{
256 if (fd < 0) {
257 return false;
258 }
259
Kenny Root87315aa2010-07-12 09:02:18 -0700260 my_lseek64(fd, 0, SEEK_END);
261
Kenny Root7cee34a2010-06-01 10:34:29 -0700262 if (mPackageName.size() == 0 || mVersion == -1) {
Kenny Root3b1abba2010-10-13 15:00:07 -0700263 LOGW("tried to write uninitialized ObbFile data\n");
Kenny Root7cee34a2010-06-01 10:34:29 -0700264 return false;
265 }
266
267 unsigned char intBuf[sizeof(uint32_t)+1];
268 memset(&intBuf, 0, sizeof(intBuf));
269
270 put4LE(intBuf, kSigVersion);
271 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
Kenny Root3b1abba2010-10-13 15:00:07 -0700272 LOGW("couldn't write signature version: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700273 return false;
274 }
275
276 put4LE(intBuf, mVersion);
277 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
Kenny Root3b1abba2010-10-13 15:00:07 -0700278 LOGW("couldn't write package version\n");
Kenny Root7cee34a2010-06-01 10:34:29 -0700279 return false;
280 }
281
Kenny Root02ca31f2010-08-12 07:36:02 -0700282 put4LE(intBuf, mFlags);
283 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
Kenny Root3b1abba2010-10-13 15:00:07 -0700284 LOGW("couldn't write package version\n");
285 return false;
286 }
287
288 if (write(fd, mSalt, sizeof(mSalt)) != (ssize_t)sizeof(mSalt)) {
289 LOGW("couldn't write salt: %s\n", strerror(errno));
Kenny Root02ca31f2010-08-12 07:36:02 -0700290 return false;
291 }
292
Kenny Root7cee34a2010-06-01 10:34:29 -0700293 size_t packageNameLen = mPackageName.size();
294 put4LE(intBuf, packageNameLen);
295 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
Kenny Root3b1abba2010-10-13 15:00:07 -0700296 LOGW("couldn't write package name length: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700297 return false;
298 }
299
300 if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
Kenny Root3b1abba2010-10-13 15:00:07 -0700301 LOGW("couldn't write package name: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700302 return false;
303 }
304
Kenny Root02ca31f2010-08-12 07:36:02 -0700305 put4LE(intBuf, kPackageNameOffset + packageNameLen);
Kenny Root7cee34a2010-06-01 10:34:29 -0700306 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
Kenny Root3b1abba2010-10-13 15:00:07 -0700307 LOGW("couldn't write footer size: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700308 return false;
309 }
310
311 put4LE(intBuf, kSignature);
312 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
Kenny Root3b1abba2010-10-13 15:00:07 -0700313 LOGW("couldn't write footer magic signature: %s\n", strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700314 return false;
315 }
316
317 return true;
318}
319
Kenny Root6e7ac5f2010-07-19 10:31:34 -0700320bool ObbFile::removeFrom(const char* filename)
321{
322 int fd;
323 bool success = false;
324
325 fd = ::open(filename, O_RDWR);
326 if (fd < 0) {
327 goto out;
328 }
329 success = removeFrom(fd);
330 close(fd);
331
332out:
333 if (!success) {
334 LOGW("failed to remove signature from %s: %s\n", filename, strerror(errno));
335 }
336 return success;
337}
338
339bool ObbFile::removeFrom(int fd)
340{
341 if (fd < 0) {
342 return false;
343 }
344
345 if (!readFrom(fd)) {
346 return false;
347 }
348
349 ftruncate(fd, mFooterStart);
350
351 return true;
352}
353
Kenny Root7cee34a2010-06-01 10:34:29 -0700354}