blob: fe49300eb25d1c047864cceaba02a815cbe571ef [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
32#define kFooterMinSize 21 /* 32-bit signature version
33 * 32-bit package version
34 * 32-bit package name size
35 * 1-character package name
36 * 32-bit footer size
37 * 32-bit footer marker
38 */
39
40#define kMaxBufSize 32768 /* Maximum file read buffer */
41
42#define kSignature 0x01059983U /* ObbFile signature */
43
44#define kSigVersion 1 /* We only know about signature version 1 */
45
46/* offsets in version 1 of the header */
47#define kPackageVersionOffset 4
48#define kPackageNameLenOffset 8
49#define kPackageNameOffset 12
50
51/*
52 * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
53 * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
54 * not already defined, then define it here.
55 */
56#ifndef TEMP_FAILURE_RETRY
57/* Used to retry syscalls that can return EINTR. */
58#define TEMP_FAILURE_RETRY(exp) ({ \
59 typeof (exp) _rc; \
60 do { \
61 _rc = (exp); \
62 } while (_rc == -1 && errno == EINTR); \
63 _rc; })
64#endif
65
66/*
67 * Work around situations where off_t is 64-bit and use off64_t in
68 * situations where it's 32-bit.
69 */
70#ifdef OFF_T_IS_64_BIT
71#define my_lseek64 lseek
72typedef off_t my_off64_t;
73#else
74#define my_lseek64 lseek64
75typedef off64_t my_off64_t;
76#endif
77
78namespace android {
79
80ObbFile::ObbFile() :
81 mVersion(-1) {
82}
83
84ObbFile::~ObbFile() {
85}
86
87bool ObbFile::readFrom(const char* filename)
88{
89 int fd;
90 bool success = false;
91
92 fd = ::open(filename, O_RDONLY);
93 if (fd < 0) {
Kenny Root87315aa2010-07-12 09:02:18 -070094 LOGW("couldn't open file %s: %s", filename, strerror(errno));
Kenny Root7cee34a2010-06-01 10:34:29 -070095 goto out;
96 }
97 success = readFrom(fd);
98 close(fd);
99
Kenny Root7cee34a2010-06-01 10:34:29 -0700100 if (!success) {
Kenny Root87315aa2010-07-12 09:02:18 -0700101 LOGW("failed to read from %s (fd=%d)\n", filename, fd);
Kenny Root7cee34a2010-06-01 10:34:29 -0700102 }
Kenny Root87315aa2010-07-12 09:02:18 -0700103
104out:
Kenny Root7cee34a2010-06-01 10:34:29 -0700105 return success;
106}
107
108bool ObbFile::readFrom(int fd)
109{
110 if (fd < 0) {
Kenny Root87315aa2010-07-12 09:02:18 -0700111 LOGW("attempt to read from invalid fd\n");
Kenny Root7cee34a2010-06-01 10:34:29 -0700112 return false;
113 }
114
115 return parseObbFile(fd);
116}
117
118bool ObbFile::parseObbFile(int fd)
119{
120 my_off64_t fileLength = my_lseek64(fd, 0, SEEK_END);
121
122 if (fileLength < kFooterMinSize) {
123 if (fileLength < 0) {
124 LOGW("error seeking in ObbFile: %s\n", strerror(errno));
125 } else {
126 LOGW("file is only %lld (less than %d minimum)\n", fileLength, kFooterMinSize);
127 }
128 return false;
129 }
130
131 ssize_t actual;
132 size_t footerSize;
133
134 {
135 my_lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);
136
137 char *footer = new char[kFooterTagSize];
138 actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize));
139 if (actual != kFooterTagSize) {
140 LOGW("couldn't read footer signature: %s\n", strerror(errno));
141 return false;
142 }
143
144 unsigned int fileSig = get4LE((unsigned char*)footer + sizeof(int32_t));
145 if (fileSig != kSignature) {
146 LOGW("footer didn't match magic string (expected 0x%08x; got 0x%08x)\n",
147 kSignature, fileSig);
148 return false;
149 }
150
151 footerSize = get4LE((unsigned char*)footer);
152 if (footerSize > (size_t)fileLength - kFooterTagSize
153 || footerSize > kMaxBufSize) {
Kenny Root87315aa2010-07-12 09:02:18 -0700154 LOGW("claimed footer size is too large (0x%08zx; file size is 0x%08llx)\n",
Kenny Root7cee34a2010-06-01 10:34:29 -0700155 footerSize, fileLength);
156 return false;
157 }
Kenny Root87315aa2010-07-12 09:02:18 -0700158
159 if (footerSize < kFooterMinSize) {
160 LOGW("claimed footer size is too small (%08zx; minimum size is 0x%x)\n",
161 footerSize, kFooterMinSize);
162 return false;
163 }
Kenny Root7cee34a2010-06-01 10:34:29 -0700164 }
165
166 my_off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
167 if (my_lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
168 LOGW("seek %lld failed: %s\n", fileOffset, strerror(errno));
169 return false;
170 }
171
Kenny Root87315aa2010-07-12 09:02:18 -0700172 char* scanBuf = (char*)malloc(footerSize);
Kenny Root7cee34a2010-06-01 10:34:29 -0700173 if (scanBuf == NULL) {
174 LOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
175 return false;
176 }
177
Kenny Root87315aa2010-07-12 09:02:18 -0700178 actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, footerSize));
Kenny Root7cee34a2010-06-01 10:34:29 -0700179 // readAmount is guaranteed to be less than kMaxBufSize
Kenny Root87315aa2010-07-12 09:02:18 -0700180 if (actual != (ssize_t)footerSize) {
Kenny Root7cee34a2010-06-01 10:34:29 -0700181 LOGI("couldn't read ObbFile footer: %s\n", strerror(errno));
182 free(scanBuf);
183 return false;
184 }
185
186#ifdef DEBUG
Kenny Root87315aa2010-07-12 09:02:18 -0700187 for (int i = 0; i < footerSize; ++i) {
Kenny Root7cee34a2010-06-01 10:34:29 -0700188 LOGI("char: 0x%02x", scanBuf[i]);
189 }
190#endif
191
192 uint32_t sigVersion = get4LE((unsigned char*)scanBuf);
193 if (sigVersion != kSigVersion) {
194 LOGW("Unsupported ObbFile version %d\n", sigVersion);
195 free(scanBuf);
196 return false;
197 }
198
199 mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
200
201 uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
202 if (packageNameLen <= 0
203 || packageNameLen > (footerSize - kPackageNameOffset)) {
Kenny Root87315aa2010-07-12 09:02:18 -0700204 LOGW("bad ObbFile package name length (0x%04x; 0x%04x possible)\n",
205 packageNameLen, footerSize - kPackageNameOffset);
Kenny Root7cee34a2010-06-01 10:34:29 -0700206 free(scanBuf);
207 return false;
208 }
209
210 char* packageName = reinterpret_cast<char*>(scanBuf + kPackageNameOffset);
211 mPackageName = String8(const_cast<char*>(packageName), packageNameLen);
212
213 free(scanBuf);
Kenny Root87315aa2010-07-12 09:02:18 -0700214
215#ifdef DEBUG
216 LOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
217#endif
218
Kenny Root7cee34a2010-06-01 10:34:29 -0700219 return true;
220}
221
222bool ObbFile::writeTo(const char* filename)
223{
224 int fd;
225 bool success = false;
226
227 fd = ::open(filename, O_WRONLY);
228 if (fd < 0) {
229 goto out;
230 }
231 success = writeTo(fd);
232 close(fd);
233
234out:
235 if (!success) {
236 LOGW("failed to write to %s: %s\n", filename, strerror(errno));
237 }
238 return success;
239}
240
241bool ObbFile::writeTo(int fd)
242{
243 if (fd < 0) {
244 return false;
245 }
246
Kenny Root87315aa2010-07-12 09:02:18 -0700247 my_lseek64(fd, 0, SEEK_END);
248
Kenny Root7cee34a2010-06-01 10:34:29 -0700249 if (mPackageName.size() == 0 || mVersion == -1) {
250 LOGW("tried to write uninitialized ObbFile data");
251 return false;
252 }
253
254 unsigned char intBuf[sizeof(uint32_t)+1];
255 memset(&intBuf, 0, sizeof(intBuf));
256
257 put4LE(intBuf, kSigVersion);
258 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
259 LOGW("couldn't write signature version: %s", strerror(errno));
260 return false;
261 }
262
263 put4LE(intBuf, mVersion);
264 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
265 LOGW("couldn't write package version");
266 return false;
267 }
268
269 size_t packageNameLen = mPackageName.size();
270 put4LE(intBuf, packageNameLen);
271 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
272 LOGW("couldn't write package name length: %s", strerror(errno));
273 return false;
274 }
275
276 if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
277 LOGW("couldn't write package name: %s", strerror(errno));
278 return false;
279 }
280
281 put4LE(intBuf, 3*sizeof(uint32_t) + packageNameLen);
282 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
283 LOGW("couldn't write footer size: %s", strerror(errno));
284 return false;
285 }
286
287 put4LE(intBuf, kSignature);
288 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
289 LOGW("couldn't write footer magic signature: %s", strerror(errno));
290 return false;
291 }
292
293 return true;
294}
295
296}