1 /*
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 33 /* 32-bit signature version (4 bytes)
33 * 32-bit package version (4 bytes)
34 * 32-bit flags (4 bytes)
35 * 64-bit salt (8 bytes)
36 * 32-bit package name size (4 bytes)
37 * >=1-character package name (1 byte)
38 * 32-bit footer size (4 bytes)
39 * 32-bit footer marker (4 bytes)
40 */
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
50 #define kFlagsOffset 8
51 #define kSaltOffset 12
52 #define kPackageNameLenOffset 20
53 #define kPackageNameOffset 24
54
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
76 typedef off_t my_off64_t;
77 #else
78 #define my_lseek64 lseek64
79 typedef off64_t my_off64_t;
80 #endif
81
82 namespace android {
83
ObbFile()84 ObbFile::ObbFile()
85 : mPackageName("")
86 , mVersion(-1)
87 , mFlags(0)
88 {
89 memset(mSalt, 0, sizeof(mSalt));
90 }
91
~ObbFile()92 ObbFile::~ObbFile() {
93 }
94
readFrom(const char * filename)95 bool ObbFile::readFrom(const char* filename)
96 {
97 int fd;
98 bool success = false;
99
100 fd = ::open(filename, O_RDONLY);
101 if (fd < 0) {
102 LOGW("couldn't open file %s: %s", filename, strerror(errno));
103 goto out;
104 }
105 success = readFrom(fd);
106 close(fd);
107
108 if (!success) {
109 LOGW("failed to read from %s (fd=%d)\n", filename, fd);
110 }
111
112 out:
113 return success;
114 }
115
readFrom(int fd)116 bool ObbFile::readFrom(int fd)
117 {
118 if (fd < 0) {
119 LOGW("attempt to read from invalid fd\n");
120 return false;
121 }
122
123 return parseObbFile(fd);
124 }
125
parseObbFile(int fd)126 bool 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) {
162 LOGW("claimed footer size is too large (0x%08zx; file size is 0x%08llx)\n",
163 footerSize, fileLength);
164 return false;
165 }
166
167 if (footerSize < (kFooterMinSize - kFooterTagSize)) {
168 LOGW("claimed footer size is too small (0x%zx; minimum size is 0x%x)\n",
169 footerSize, kFooterMinSize - kFooterTagSize);
170 return false;
171 }
172 }
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
180 mFooterStart = fileOffset;
181
182 char* scanBuf = (char*)malloc(footerSize);
183 if (scanBuf == NULL) {
184 LOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
185 return false;
186 }
187
188 actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, footerSize));
189 // readAmount is guaranteed to be less than kMaxBufSize
190 if (actual != (ssize_t)footerSize) {
191 LOGI("couldn't read ObbFile footer: %s\n", strerror(errno));
192 free(scanBuf);
193 return false;
194 }
195
196 #ifdef DEBUG
197 for (int i = 0; i < footerSize; ++i) {
198 LOGI("char: 0x%02x\n", scanBuf[i]);
199 }
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);
210 mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset);
211
212 memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt));
213
214 uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
215 if (packageNameLen <= 0
216 || packageNameLen > (footerSize - kPackageNameOffset)) {
217 LOGW("bad ObbFile package name length (0x%04x; 0x%04x possible)\n",
218 packageNameLen, footerSize - kPackageNameOffset);
219 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);
227
228 #ifdef DEBUG
229 LOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
230 #endif
231
232 return true;
233 }
234
writeTo(const char * filename)235 bool 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
247 out:
248 if (!success) {
249 LOGW("failed to write to %s: %s\n", filename, strerror(errno));
250 }
251 return success;
252 }
253
writeTo(int fd)254 bool ObbFile::writeTo(int fd)
255 {
256 if (fd < 0) {
257 return false;
258 }
259
260 my_lseek64(fd, 0, SEEK_END);
261
262 if (mPackageName.size() == 0 || mVersion == -1) {
263 LOGW("tried to write uninitialized ObbFile data\n");
264 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)) {
272 LOGW("couldn't write signature version: %s\n", strerror(errno));
273 return false;
274 }
275
276 put4LE(intBuf, mVersion);
277 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
278 LOGW("couldn't write package version\n");
279 return false;
280 }
281
282 put4LE(intBuf, mFlags);
283 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
284 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));
290 return false;
291 }
292
293 size_t packageNameLen = mPackageName.size();
294 put4LE(intBuf, packageNameLen);
295 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
296 LOGW("couldn't write package name length: %s\n", strerror(errno));
297 return false;
298 }
299
300 if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
301 LOGW("couldn't write package name: %s\n", strerror(errno));
302 return false;
303 }
304
305 put4LE(intBuf, kPackageNameOffset + packageNameLen);
306 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
307 LOGW("couldn't write footer size: %s\n", strerror(errno));
308 return false;
309 }
310
311 put4LE(intBuf, kSignature);
312 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
313 LOGW("couldn't write footer magic signature: %s\n", strerror(errno));
314 return false;
315 }
316
317 return true;
318 }
319
removeFrom(const char * filename)320 bool 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
332 out:
333 if (!success) {
334 LOGW("failed to remove signature from %s: %s\n", filename, strerror(errno));
335 }
336 return success;
337 }
338
removeFrom(int fd)339 bool 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
354 }
355