blob: e170ab88c12c6f30a71c75f65b8e5b183ae20bb6 [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 Root02ca31f2010-08-12 07:36:02 -070032#define kFooterMinSize 25 /* 32-bit signature version (4 bytes)
33 * 32-bit package version (4 bytes)
34 * 32-bit flags (4 bytes)
35 * 32-bit package name size (4-bytes)
36 * >=1-character package name (1 byte)
37 * 32-bit footer size (4 bytes)
38 * 32-bit footer marker (4 bytes)
Kenny Root7cee34a2010-06-01 10:34:29 -070039 */
40
41#define kMaxBufSize 32768 /* Maximum file read buffer */
42
43#define kSignature 0x01059983U /* ObbFile signature */
44
45#define kSigVersion 1 /* We only know about signature version 1 */
46
47/* offsets in version 1 of the header */
48#define kPackageVersionOffset 4
Kenny Root02ca31f2010-08-12 07:36:02 -070049#define kFlagsOffset 8
50#define kPackageNameLenOffset 12
51#define kPackageNameOffset 16
Kenny Root7cee34a2010-06-01 10:34:29 -070052
53/*
54 * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
55 * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
56 * not already defined, then define it here.
57 */
58#ifndef TEMP_FAILURE_RETRY
59/* Used to retry syscalls that can return EINTR. */
60#define TEMP_FAILURE_RETRY(exp) ({ \
61 typeof (exp) _rc; \
62 do { \
63 _rc = (exp); \
64 } while (_rc == -1 && errno == EINTR); \
65 _rc; })
66#endif
67
68/*
69 * Work around situations where off_t is 64-bit and use off64_t in
70 * situations where it's 32-bit.
71 */
72#ifdef OFF_T_IS_64_BIT
73#define my_lseek64 lseek
74typedef off_t my_off64_t;
75#else
76#define my_lseek64 lseek64
77typedef off64_t my_off64_t;
78#endif
79
80namespace android {
81
82ObbFile::ObbFile() :
Kenny Root02ca31f2010-08-12 07:36:02 -070083 mPackageName(""),
84 mVersion(-1),
85 mFlags(0)
86{
Kenny Root7cee34a2010-06-01 10:34:29 -070087}
88
89ObbFile::~ObbFile() {
90}
91
92bool ObbFile::readFrom(const char* filename)
93{
94 int fd;
95 bool success = false;
96
97 fd = ::open(filename, O_RDONLY);
98 if (fd < 0) {
Kenny Root87315aa2010-07-12 09:02:18 -070099 LOGW("couldn't open file %s: %s", filename, strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -0700100 goto out;
101 }
102 success = readFrom(fd);
103 close(fd);
104
Kenny Root7cee34a2010-06-01 10:34:29 -0700105 if (!success) {
Kenny Root87315aa2010-07-12 09:02:18 -0700106 LOGW("failed to read from %s (fd=%d)\n", filename, fd);
Kenny Root7cee34a2010-06-01 10:34:29 -0700107 }
Kenny Root87315aa2010-07-12 09:02:18 -0700108
109out:
Kenny Root7cee34a2010-06-01 10:34:29 -0700110 return success;
111}
112
113bool ObbFile::readFrom(int fd)
114{
115 if (fd < 0) {
Kenny Root87315aa2010-07-12 09:02:18 -0700116 LOGW("attempt to read from invalid fd\n");
Kenny Root7cee34a2010-06-01 10:34:29 -0700117 return false;
118 }
119
120 return parseObbFile(fd);
121}
122
123bool ObbFile::parseObbFile(int fd)
124{
125 my_off64_t fileLength = my_lseek64(fd, 0, SEEK_END);
126
127 if (fileLength < kFooterMinSize) {
128 if (fileLength < 0) {
129 LOGW("error seeking in ObbFile: %s\n", strerror(errno));
130 } else {
131 LOGW("file is only %lld (less than %d minimum)\n", fileLength, kFooterMinSize);
132 }
133 return false;
134 }
135
136 ssize_t actual;
137 size_t footerSize;
138
139 {
140 my_lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);
141
142 char *footer = new char[kFooterTagSize];
143 actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize));
144 if (actual != kFooterTagSize) {
145 LOGW("couldn't read footer signature: %s\n", strerror(errno));
146 return false;
147 }
148
149 unsigned int fileSig = get4LE((unsigned char*)footer + sizeof(int32_t));
150 if (fileSig != kSignature) {
151 LOGW("footer didn't match magic string (expected 0x%08x; got 0x%08x)\n",
152 kSignature, fileSig);
153 return false;
154 }
155
156 footerSize = get4LE((unsigned char*)footer);
157 if (footerSize > (size_t)fileLength - kFooterTagSize
158 || footerSize > kMaxBufSize) {
Kenny Root87315aa2010-07-12 09:02:18 -0700159 LOGW("claimed footer size is too large (0x%08zx; file size is 0x%08llx)\n",
Kenny Root7cee34a2010-06-01 10:34:29 -0700160 footerSize, fileLength);
161 return false;
162 }
Kenny Root87315aa2010-07-12 09:02:18 -0700163
Kenny Root6e7ac5f2010-07-19 10:31:34 -0700164 if (footerSize < (kFooterMinSize - kFooterTagSize)) {
165 LOGW("claimed footer size is too small (0x%zx; minimum size is 0x%x)\n",
166 footerSize, kFooterMinSize - kFooterTagSize);
Kenny Root87315aa2010-07-12 09:02:18 -0700167 return false;
168 }
Kenny Root7cee34a2010-06-01 10:34:29 -0700169 }
170
171 my_off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
172 if (my_lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
173 LOGW("seek %lld failed: %s\n", fileOffset, strerror(errno));
174 return false;
175 }
176
Kenny Root6e7ac5f2010-07-19 10:31:34 -0700177 mFooterStart = fileOffset;
178
Kenny Root87315aa2010-07-12 09:02:18 -0700179 char* scanBuf = (char*)malloc(footerSize);
Kenny Root7cee34a2010-06-01 10:34:29 -0700180 if (scanBuf == NULL) {
181 LOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
182 return false;
183 }
184
Kenny Root87315aa2010-07-12 09:02:18 -0700185 actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, footerSize));
Kenny Root7cee34a2010-06-01 10:34:29 -0700186 // readAmount is guaranteed to be less than kMaxBufSize
Kenny Root87315aa2010-07-12 09:02:18 -0700187 if (actual != (ssize_t)footerSize) {
Kenny Root7cee34a2010-06-01 10:34:29 -0700188 LOGI("couldn't read ObbFile footer: %s\n", strerror(errno));
189 free(scanBuf);
190 return false;
191 }
192
193#ifdef DEBUG
Kenny Root87315aa2010-07-12 09:02:18 -0700194 for (int i = 0; i < footerSize; ++i) {
Kenny Root7cee34a2010-06-01 10:34:29 -0700195 LOGI("char: 0x%02x", scanBuf[i]);
196 }
197#endif
198
199 uint32_t sigVersion = get4LE((unsigned char*)scanBuf);
200 if (sigVersion != kSigVersion) {
201 LOGW("Unsupported ObbFile version %d\n", sigVersion);
202 free(scanBuf);
203 return false;
204 }
205
206 mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
Kenny Root02ca31f2010-08-12 07:36:02 -0700207 mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset);
Kenny Root7cee34a2010-06-01 10:34:29 -0700208
209 uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
210 if (packageNameLen <= 0
211 || packageNameLen > (footerSize - kPackageNameOffset)) {
Kenny Root87315aa2010-07-12 09:02:18 -0700212 LOGW("bad ObbFile package name length (0x%04x; 0x%04x possible)\n",
213 packageNameLen, footerSize - kPackageNameOffset);
Kenny Root7cee34a2010-06-01 10:34:29 -0700214 free(scanBuf);
215 return false;
216 }
217
218 char* packageName = reinterpret_cast<char*>(scanBuf + kPackageNameOffset);
219 mPackageName = String8(const_cast<char*>(packageName), packageNameLen);
220
221 free(scanBuf);
Kenny Root87315aa2010-07-12 09:02:18 -0700222
223#ifdef DEBUG
224 LOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
225#endif
226
Kenny Root7cee34a2010-06-01 10:34:29 -0700227 return true;
228}
229
230bool ObbFile::writeTo(const char* filename)
231{
232 int fd;
233 bool success = false;
234
235 fd = ::open(filename, O_WRONLY);
236 if (fd < 0) {
237 goto out;
238 }
239 success = writeTo(fd);
240 close(fd);
241
242out:
243 if (!success) {
244 LOGW("failed to write to %s: %s\n", filename, strerror(errno));
245 }
246 return success;
247}
248
249bool ObbFile::writeTo(int fd)
250{
251 if (fd < 0) {
252 return false;
253 }
254
Kenny Root87315aa2010-07-12 09:02:18 -0700255 my_lseek64(fd, 0, SEEK_END);
256
Kenny Root7cee34a2010-06-01 10:34:29 -0700257 if (mPackageName.size() == 0 || mVersion == -1) {
258 LOGW("tried to write uninitialized ObbFile data");
259 return false;
260 }
261
262 unsigned char intBuf[sizeof(uint32_t)+1];
263 memset(&intBuf, 0, sizeof(intBuf));
264
265 put4LE(intBuf, kSigVersion);
266 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
267 LOGW("couldn't write signature version: %s", strerror(errno));
268 return false;
269 }
270
271 put4LE(intBuf, mVersion);
272 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
273 LOGW("couldn't write package version");
274 return false;
275 }
276
Kenny Root02ca31f2010-08-12 07:36:02 -0700277 put4LE(intBuf, mFlags);
278 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
279 LOGW("couldn't write package version");
280 return false;
281 }
282
Kenny Root7cee34a2010-06-01 10:34:29 -0700283 size_t packageNameLen = mPackageName.size();
284 put4LE(intBuf, packageNameLen);
285 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
286 LOGW("couldn't write package name length: %s", strerror(errno));
287 return false;
288 }
289
290 if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
291 LOGW("couldn't write package name: %s", strerror(errno));
292 return false;
293 }
294
Kenny Root02ca31f2010-08-12 07:36:02 -0700295 put4LE(intBuf, kPackageNameOffset + packageNameLen);
Kenny Root7cee34a2010-06-01 10:34:29 -0700296 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
297 LOGW("couldn't write footer size: %s", strerror(errno));
298 return false;
299 }
300
301 put4LE(intBuf, kSignature);
302 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
303 LOGW("couldn't write footer magic signature: %s", strerror(errno));
304 return false;
305 }
306
307 return true;
308}
309
Kenny Root6e7ac5f2010-07-19 10:31:34 -0700310bool ObbFile::removeFrom(const char* filename)
311{
312 int fd;
313 bool success = false;
314
315 fd = ::open(filename, O_RDWR);
316 if (fd < 0) {
317 goto out;
318 }
319 success = removeFrom(fd);
320 close(fd);
321
322out:
323 if (!success) {
324 LOGW("failed to remove signature from %s: %s\n", filename, strerror(errno));
325 }
326 return success;
327}
328
329bool ObbFile::removeFrom(int fd)
330{
331 if (fd < 0) {
332 return false;
333 }
334
335 if (!readFrom(fd)) {
336 return false;
337 }
338
339 ftruncate(fd, mFooterStart);
340
341 return true;
342}
343
Kenny Root7cee34a2010-06-01 10:34:29 -0700344}