Home | History | Annotate | Download | only in androidfw
      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 
     26 #include <androidfw/ObbFile.h>
     27 #include <utils/Compat.h>
     28 #include <utils/Log.h>
     29 
     30 //#define DEBUG 1
     31 
     32 #define kFooterTagSize 8  /* last two 32-bit integers */
     33 
     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)
     42                            */
     43 
     44 #define kMaxBufSize    32768 /* Maximum file read buffer */
     45 
     46 #define kSignature     0x01059983U /* ObbFile signature */
     47 
     48 #define kSigVersion    1 /* We only know about signature version 1 */
     49 
     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
     56 
     57 /*
     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.
     61  */
     62 #ifndef TEMP_FAILURE_RETRY
     63 /* Used to retry syscalls that can return EINTR. */
     64 #define TEMP_FAILURE_RETRY(exp) ({         \
     65     typeof (exp) _rc;                      \
     66     do {                                   \
     67         _rc = (exp);                       \
     68     } while (_rc == -1 && errno == EINTR); \
     69     _rc; })
     70 #endif
     71 
     72 
     73 namespace android {
     74 
     75 ObbFile::ObbFile()
     76         : mPackageName("")
     77         , mVersion(-1)
     78         , mFlags(0)
     79 {
     80     memset(mSalt, 0, sizeof(mSalt));
     81 }
     82 
     83 ObbFile::~ObbFile() {
     84 }
     85 
     86 bool ObbFile::readFrom(const char* filename)
     87 {
     88     int fd;
     89     bool success = false;
     90 
     91     fd = ::open(filename, O_RDONLY);
     92     if (fd < 0) {
     93         ALOGW("couldn't open file %s: %s", filename, strerror(errno));
     94         goto out;
     95     }
     96     success = readFrom(fd);
     97     close(fd);
     98 
     99     if (!success) {
    100         ALOGW("failed to read from %s (fd=%d)\n", filename, fd);
    101     }
    102 
    103 out:
    104     return success;
    105 }
    106 
    107 bool ObbFile::readFrom(int fd)
    108 {
    109     if (fd < 0) {
    110         ALOGW("attempt to read from invalid fd\n");
    111         return false;
    112     }
    113 
    114     return parseObbFile(fd);
    115 }
    116 
    117 bool ObbFile::parseObbFile(int fd)
    118 {
    119     off64_t fileLength = lseek64(fd, 0, SEEK_END);
    120 
    121     if (fileLength < kFooterMinSize) {
    122         if (fileLength < 0) {
    123             ALOGW("error seeking in ObbFile: %s\n", strerror(errno));
    124         } else {
    125             ALOGW("file is only %lld (less than %d minimum)\n", fileLength, kFooterMinSize);
    126         }
    127         return false;
    128     }
    129 
    130     ssize_t actual;
    131     size_t footerSize;
    132 
    133     {
    134         lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);
    135 
    136         char *footer = new char[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));
    140             return false;
    141         }
    142 
    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);
    147             return false;
    148         }
    149 
    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);
    155             return false;
    156         }
    157 
    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);
    161             return false;
    162         }
    163     }
    164 
    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));
    168         return false;
    169     }
    170 
    171     mFooterStart = fileOffset;
    172 
    173     char* scanBuf = (char*)malloc(footerSize);
    174     if (scanBuf == NULL) {
    175         ALOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
    176         return false;
    177     }
    178 
    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));
    183         free(scanBuf);
    184         return false;
    185     }
    186 
    187 #ifdef DEBUG
    188     for (int i = 0; i < footerSize; ++i) {
    189         ALOGI("char: 0x%02x\n", scanBuf[i]);
    190     }
    191 #endif
    192 
    193     uint32_t sigVersion = get4LE((unsigned char*)scanBuf);
    194     if (sigVersion != kSigVersion) {
    195         ALOGW("Unsupported ObbFile version %d\n", sigVersion);
    196         free(scanBuf);
    197         return false;
    198     }
    199 
    200     mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
    201     mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset);
    202 
    203     memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt));
    204 
    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);
    210         free(scanBuf);
    211         return false;
    212     }
    213 
    214     char* packageName = reinterpret_cast<char*>(scanBuf + kPackageNameOffset);
    215     mPackageName = String8(const_cast<char*>(packageName), packageNameLen);
    216 
    217     free(scanBuf);
    218 
    219 #ifdef DEBUG
    220     ALOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
    221 #endif
    222 
    223     return true;
    224 }
    225 
    226 bool ObbFile::writeTo(const char* filename)
    227 {
    228     int fd;
    229     bool success = false;
    230 
    231     fd = ::open(filename, O_WRONLY);
    232     if (fd < 0) {
    233         goto out;
    234     }
    235     success = writeTo(fd);
    236     close(fd);
    237 
    238 out:
    239     if (!success) {
    240         ALOGW("failed to write to %s: %s\n", filename, strerror(errno));
    241     }
    242     return success;
    243 }
    244 
    245 bool ObbFile::writeTo(int fd)
    246 {
    247     if (fd < 0) {
    248         return false;
    249     }
    250 
    251     lseek64(fd, 0, SEEK_END);
    252 
    253     if (mPackageName.size() == 0 || mVersion == -1) {
    254         ALOGW("tried to write uninitialized ObbFile data\n");
    255         return false;
    256     }
    257 
    258     unsigned char intBuf[sizeof(uint32_t)+1];
    259     memset(&intBuf, 0, sizeof(intBuf));
    260 
    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));
    264         return false;
    265     }
    266 
    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");
    270         return false;
    271     }
    272 
    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");
    276         return false;
    277     }
    278 
    279     if (write(fd, mSalt, sizeof(mSalt)) != (ssize_t)sizeof(mSalt)) {
    280         ALOGW("couldn't write salt: %s\n", strerror(errno));
    281         return false;
    282     }
    283 
    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));
    288         return false;
    289     }
    290 
    291     if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
    292         ALOGW("couldn't write package name: %s\n", strerror(errno));
    293         return false;
    294     }
    295 
    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));
    299         return false;
    300     }
    301 
    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));
    305         return false;
    306     }
    307 
    308     return true;
    309 }
    310 
    311 bool ObbFile::removeFrom(const char* filename)
    312 {
    313     int fd;
    314     bool success = false;
    315 
    316     fd = ::open(filename, O_RDWR);
    317     if (fd < 0) {
    318         goto out;
    319     }
    320     success = removeFrom(fd);
    321     close(fd);
    322 
    323 out:
    324     if (!success) {
    325         ALOGW("failed to remove signature from %s: %s\n", filename, strerror(errno));
    326     }
    327     return success;
    328 }
    329 
    330 bool ObbFile::removeFrom(int fd)
    331 {
    332     if (fd < 0) {
    333         return false;
    334     }
    335 
    336     if (!readFrom(fd)) {
    337         return false;
    338     }
    339 
    340     ftruncate(fd, mFooterStart);
    341 
    342     return true;
    343 }
    344 
    345 }
    346