2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #define LOG_TAG "ObbFile"
26 #include <androidfw/ObbFile.h>
27 #include <utils/Compat.h>
28 #include <utils/Log.h>
32 #define kFooterTagSize 8 /* last two 32-bit integers */
34 #define kFooterMinSize 33 /* 32-bit signature version (4 bytes)
35 * 32-bit package version (4 bytes)
36 * 32-bit flags (4 bytes)
37 * 64-bit salt (8 bytes)
38 * 32-bit package name size (4 bytes)
39 * >=1-character package name (1 byte)
40 * 32-bit footer size (4 bytes)
41 * 32-bit footer marker (4 bytes)
44 #define kMaxBufSize 32768 /* Maximum file read buffer */
46 #define kSignature 0x01059983U /* ObbFile signature */
48 #define kSigVersion 1 /* We only know about signature version 1 */
50 /* offsets in version 1 of the header */
51 #define kPackageVersionOffset 4
52 #define kFlagsOffset 8
53 #define kSaltOffset 12
54 #define kPackageNameLenOffset 20
55 #define kPackageNameOffset 24
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.
62 #ifndef TEMP_FAILURE_RETRY
63 /* Used to retry syscalls that can return EINTR. */
64 #define TEMP_FAILURE_RETRY(exp) ({ \
68 } while (_rc == -1 && errno == EINTR); \
80 memset(mSalt, 0, sizeof(mSalt));
86 bool ObbFile::readFrom(const char* filename)
91 fd = ::open(filename, O_RDONLY);
93 ALOGW("couldn't open file %s: %s", filename, strerror(errno));
96 success = readFrom(fd);
100 ALOGW("failed to read from %s (fd=%d)\n", filename, fd);
107 bool ObbFile::readFrom(int fd)
110 ALOGW("attempt to read from invalid fd\n");
114 return parseObbFile(fd);
117 bool ObbFile::parseObbFile(int fd)
119 off64_t fileLength = lseek64(fd, 0, SEEK_END);
121 if (fileLength < kFooterMinSize) {
122 if (fileLength < 0) {
123 ALOGW("error seeking in ObbFile: %s\n", strerror(errno));
125 ALOGW("file is only %lld (less than %d minimum)\n", fileLength, kFooterMinSize);
134 lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);
136 char footer[kFooterTagSize];
137 actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize));
138 if (actual != kFooterTagSize) {
139 ALOGW("couldn't read footer signature: %s\n", strerror(errno));
143 unsigned int fileSig = get4LE((unsigned char*)footer + sizeof(int32_t));
144 if (fileSig != kSignature) {
145 ALOGW("footer didn't match magic string (expected 0x%08x; got 0x%08x)\n",
146 kSignature, fileSig);
150 footerSize = get4LE((unsigned char*)footer);
151 if (footerSize > (size_t)fileLength - kFooterTagSize
152 || footerSize > kMaxBufSize) {
153 ALOGW("claimed footer size is too large (0x%08zx; file size is 0x%08llx)\n",
154 footerSize, fileLength);
158 if (footerSize < (kFooterMinSize - kFooterTagSize)) {
159 ALOGW("claimed footer size is too small (0x%zx; minimum size is 0x%x)\n",
160 footerSize, kFooterMinSize - kFooterTagSize);
165 off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
166 if (lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
167 ALOGW("seek %lld failed: %s\n", fileOffset, strerror(errno));
171 mFooterStart = fileOffset;
173 char* scanBuf = (char*)malloc(footerSize);
174 if (scanBuf == NULL) {
175 ALOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
179 actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, footerSize));
180 // readAmount is guaranteed to be less than kMaxBufSize
181 if (actual != (ssize_t)footerSize) {
182 ALOGI("couldn't read ObbFile footer: %s\n", strerror(errno));
188 for (int i = 0; i < footerSize; ++i) {
189 ALOGI("char: 0x%02x\n", scanBuf[i]);
193 uint32_t sigVersion = get4LE((unsigned char*)scanBuf);
194 if (sigVersion != kSigVersion) {
195 ALOGW("Unsupported ObbFile version %d\n", sigVersion);
200 mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
201 mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset);
203 memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt));
205 size_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
206 if (packageNameLen == 0
207 || packageNameLen > (footerSize - kPackageNameOffset)) {
208 ALOGW("bad ObbFile package name length (0x%04zx; 0x%04zx possible)\n",
209 packageNameLen, footerSize - kPackageNameOffset);
214 char* packageName = reinterpret_cast<char*>(scanBuf + kPackageNameOffset);
215 mPackageName = String8(const_cast<char*>(packageName), packageNameLen);
220 ALOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
226 bool ObbFile::writeTo(const char* filename)
229 bool success = false;
231 fd = ::open(filename, O_WRONLY);
235 success = writeTo(fd);
240 ALOGW("failed to write to %s: %s\n", filename, strerror(errno));
245 bool ObbFile::writeTo(int fd)
251 lseek64(fd, 0, SEEK_END);
253 if (mPackageName.size() == 0 || mVersion == -1) {
254 ALOGW("tried to write uninitialized ObbFile data\n");
258 unsigned char intBuf[sizeof(uint32_t)+1];
259 memset(&intBuf, 0, sizeof(intBuf));
261 put4LE(intBuf, kSigVersion);
262 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
263 ALOGW("couldn't write signature version: %s\n", strerror(errno));
267 put4LE(intBuf, mVersion);
268 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
269 ALOGW("couldn't write package version\n");
273 put4LE(intBuf, mFlags);
274 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
275 ALOGW("couldn't write package version\n");
279 if (write(fd, mSalt, sizeof(mSalt)) != (ssize_t)sizeof(mSalt)) {
280 ALOGW("couldn't write salt: %s\n", strerror(errno));
284 size_t packageNameLen = mPackageName.size();
285 put4LE(intBuf, packageNameLen);
286 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
287 ALOGW("couldn't write package name length: %s\n", strerror(errno));
291 if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
292 ALOGW("couldn't write package name: %s\n", strerror(errno));
296 put4LE(intBuf, kPackageNameOffset + packageNameLen);
297 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
298 ALOGW("couldn't write footer size: %s\n", strerror(errno));
302 put4LE(intBuf, kSignature);
303 if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
304 ALOGW("couldn't write footer magic signature: %s\n", strerror(errno));
311 bool ObbFile::removeFrom(const char* filename)
314 bool success = false;
316 fd = ::open(filename, O_RDWR);
320 success = removeFrom(fd);
325 ALOGW("failed to remove signature from %s: %s\n", filename, strerror(errno));
330 bool ObbFile::removeFrom(int fd)
340 ftruncate(fd, mFooterStart);