| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 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" | 
| Kenny Root | 18092dd | 2010-11-24 12:56:06 -0800 | [diff] [blame] | 25 |  | 
 | 26 | #include <utils/Compat.h> | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 27 | #include <utils/Log.h> | 
 | 28 | #include <utils/ObbFile.h> | 
 | 29 |  | 
 | 30 | //#define DEBUG 1 | 
 | 31 |  | 
 | 32 | #define kFooterTagSize 8  /* last two 32-bit integers */ | 
 | 33 |  | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 34 | #define kFooterMinSize 33 /* 32-bit signature version (4 bytes) | 
| Kenny Root | 28e9b9f | 2010-08-12 07:36:02 -0700 | [diff] [blame] | 35 |                            * 32-bit package version (4 bytes) | 
 | 36 |                            * 32-bit flags (4 bytes) | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 37 |                            * 64-bit salt (8 bytes) | 
 | 38 |                            * 32-bit package name size (4 bytes) | 
| Kenny Root | 28e9b9f | 2010-08-12 07:36:02 -0700 | [diff] [blame] | 39 |                            * >=1-character package name (1 byte) | 
 | 40 |                            * 32-bit footer size (4 bytes) | 
 | 41 |                            * 32-bit footer marker (4 bytes) | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 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 | 
| Kenny Root | 28e9b9f | 2010-08-12 07:36:02 -0700 | [diff] [blame] | 52 | #define kFlagsOffset          8 | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 53 | #define kSaltOffset           12 | 
 | 54 | #define kPackageNameLenOffset 20 | 
 | 55 | #define kPackageNameOffset    24 | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 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 |  | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 72 |  | 
 | 73 | namespace android { | 
 | 74 |  | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 75 | ObbFile::ObbFile() | 
 | 76 |         : mPackageName("") | 
 | 77 |         , mVersion(-1) | 
 | 78 |         , mFlags(0) | 
| Kenny Root | 28e9b9f | 2010-08-12 07:36:02 -0700 | [diff] [blame] | 79 | { | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 80 |     memset(mSalt, 0, sizeof(mSalt)); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 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) { | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 93 |         LOGW("couldn't open file %s: %s", filename, strerror(errno)); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 94 |         goto out; | 
 | 95 |     } | 
 | 96 |     success = readFrom(fd); | 
 | 97 |     close(fd); | 
 | 98 |  | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 99 |     if (!success) { | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 100 |         LOGW("failed to read from %s (fd=%d)\n", filename, fd); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 101 |     } | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 102 |  | 
 | 103 | out: | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 104 |     return success; | 
 | 105 | } | 
 | 106 |  | 
 | 107 | bool ObbFile::readFrom(int fd) | 
 | 108 | { | 
 | 109 |     if (fd < 0) { | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 110 |         LOGW("attempt to read from invalid fd\n"); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 111 |         return false; | 
 | 112 |     } | 
 | 113 |  | 
 | 114 |     return parseObbFile(fd); | 
 | 115 | } | 
 | 116 |  | 
 | 117 | bool ObbFile::parseObbFile(int fd) | 
 | 118 | { | 
| Kenny Root | 18092dd | 2010-11-24 12:56:06 -0800 | [diff] [blame] | 119 |     off64_t fileLength = lseek64(fd, 0, SEEK_END); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 120 |  | 
 | 121 |     if (fileLength < kFooterMinSize) { | 
 | 122 |         if (fileLength < 0) { | 
 | 123 |             LOGW("error seeking in ObbFile: %s\n", strerror(errno)); | 
 | 124 |         } else { | 
 | 125 |             LOGW("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 |     { | 
| Kenny Root | 18092dd | 2010-11-24 12:56:06 -0800 | [diff] [blame] | 134 |         lseek64(fd, fileLength - kFooterTagSize, SEEK_SET); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 135 |  | 
 | 136 |         char *footer = new char[kFooterTagSize]; | 
 | 137 |         actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize)); | 
 | 138 |         if (actual != kFooterTagSize) { | 
 | 139 |             LOGW("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 |             LOGW("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) { | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 153 |             LOGW("claimed footer size is too large (0x%08zx; file size is 0x%08llx)\n", | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 154 |                     footerSize, fileLength); | 
 | 155 |             return false; | 
 | 156 |         } | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 157 |  | 
| Kenny Root | 1dfd9f8 | 2010-07-19 10:31:34 -0700 | [diff] [blame] | 158 |         if (footerSize < (kFooterMinSize - kFooterTagSize)) { | 
 | 159 |             LOGW("claimed footer size is too small (0x%zx; minimum size is 0x%x)\n", | 
 | 160 |                     footerSize, kFooterMinSize - kFooterTagSize); | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 161 |             return false; | 
 | 162 |         } | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 163 |     } | 
 | 164 |  | 
| Kenny Root | 18092dd | 2010-11-24 12:56:06 -0800 | [diff] [blame] | 165 |     off64_t fileOffset = fileLength - footerSize - kFooterTagSize; | 
 | 166 |     if (lseek64(fd, fileOffset, SEEK_SET) != fileOffset) { | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 167 |         LOGW("seek %lld failed: %s\n", fileOffset, strerror(errno)); | 
 | 168 |         return false; | 
 | 169 |     } | 
 | 170 |  | 
| Kenny Root | 1dfd9f8 | 2010-07-19 10:31:34 -0700 | [diff] [blame] | 171 |     mFooterStart = fileOffset; | 
 | 172 |  | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 173 |     char* scanBuf = (char*)malloc(footerSize); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 174 |     if (scanBuf == NULL) { | 
 | 175 |         LOGW("couldn't allocate scanBuf: %s\n", strerror(errno)); | 
 | 176 |         return false; | 
 | 177 |     } | 
 | 178 |  | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 179 |     actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, footerSize)); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 180 |     // readAmount is guaranteed to be less than kMaxBufSize | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 181 |     if (actual != (ssize_t)footerSize) { | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 182 |         LOGI("couldn't read ObbFile footer: %s\n", strerror(errno)); | 
 | 183 |         free(scanBuf); | 
 | 184 |         return false; | 
 | 185 |     } | 
 | 186 |  | 
 | 187 | #ifdef DEBUG | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 188 |     for (int i = 0; i < footerSize; ++i) { | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 189 |         LOGI("char: 0x%02x\n", scanBuf[i]); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 190 |     } | 
 | 191 | #endif | 
 | 192 |  | 
 | 193 |     uint32_t sigVersion = get4LE((unsigned char*)scanBuf); | 
 | 194 |     if (sigVersion != kSigVersion) { | 
 | 195 |         LOGW("Unsupported ObbFile version %d\n", sigVersion); | 
 | 196 |         free(scanBuf); | 
 | 197 |         return false; | 
 | 198 |     } | 
 | 199 |  | 
 | 200 |     mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset); | 
| Kenny Root | 28e9b9f | 2010-08-12 07:36:02 -0700 | [diff] [blame] | 201 |     mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 202 |  | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 203 |     memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt)); | 
 | 204 |  | 
| Kenny Root | 18092dd | 2010-11-24 12:56:06 -0800 | [diff] [blame] | 205 |     size_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset); | 
 | 206 |     if (packageNameLen == 0 | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 207 |             || packageNameLen > (footerSize - kPackageNameOffset)) { | 
| Kenny Root | 18092dd | 2010-11-24 12:56:06 -0800 | [diff] [blame] | 208 |         LOGW("bad ObbFile package name length (0x%04zx; 0x%04zx possible)\n", | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 209 |                 packageNameLen, footerSize - kPackageNameOffset); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 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); | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 218 |  | 
 | 219 | #ifdef DEBUG | 
 | 220 |     LOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion); | 
 | 221 | #endif | 
 | 222 |  | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 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 |         LOGW("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 |  | 
| Kenny Root | 18092dd | 2010-11-24 12:56:06 -0800 | [diff] [blame] | 251 |     lseek64(fd, 0, SEEK_END); | 
| Kenny Root | fa59afb | 2010-07-12 09:02:18 -0700 | [diff] [blame] | 252 |  | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 253 |     if (mPackageName.size() == 0 || mVersion == -1) { | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 254 |         LOGW("tried to write uninitialized ObbFile data\n"); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 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)) { | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 263 |         LOGW("couldn't write signature version: %s\n", strerror(errno)); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 264 |         return false; | 
 | 265 |     } | 
 | 266 |  | 
 | 267 |     put4LE(intBuf, mVersion); | 
 | 268 |     if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 269 |         LOGW("couldn't write package version\n"); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 270 |         return false; | 
 | 271 |     } | 
 | 272 |  | 
| Kenny Root | 28e9b9f | 2010-08-12 07:36:02 -0700 | [diff] [blame] | 273 |     put4LE(intBuf, mFlags); | 
 | 274 |     if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 275 |         LOGW("couldn't write package version\n"); | 
 | 276 |         return false; | 
 | 277 |     } | 
 | 278 |  | 
 | 279 |     if (write(fd, mSalt, sizeof(mSalt)) != (ssize_t)sizeof(mSalt)) { | 
 | 280 |         LOGW("couldn't write salt: %s\n", strerror(errno)); | 
| Kenny Root | 28e9b9f | 2010-08-12 07:36:02 -0700 | [diff] [blame] | 281 |         return false; | 
 | 282 |     } | 
 | 283 |  | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 284 |     size_t packageNameLen = mPackageName.size(); | 
 | 285 |     put4LE(intBuf, packageNameLen); | 
 | 286 |     if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 287 |         LOGW("couldn't write package name length: %s\n", strerror(errno)); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 288 |         return false; | 
 | 289 |     } | 
 | 290 |  | 
 | 291 |     if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) { | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 292 |         LOGW("couldn't write package name: %s\n", strerror(errno)); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 293 |         return false; | 
 | 294 |     } | 
 | 295 |  | 
| Kenny Root | 28e9b9f | 2010-08-12 07:36:02 -0700 | [diff] [blame] | 296 |     put4LE(intBuf, kPackageNameOffset + packageNameLen); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 297 |     if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 298 |         LOGW("couldn't write footer size: %s\n", strerror(errno)); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 299 |         return false; | 
 | 300 |     } | 
 | 301 |  | 
 | 302 |     put4LE(intBuf, kSignature); | 
 | 303 |     if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) { | 
| Kenny Root | 95a6889 | 2010-10-13 15:00:07 -0700 | [diff] [blame] | 304 |         LOGW("couldn't write footer magic signature: %s\n", strerror(errno)); | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 305 |         return false; | 
 | 306 |     } | 
 | 307 |  | 
 | 308 |     return true; | 
 | 309 | } | 
 | 310 |  | 
| Kenny Root | 1dfd9f8 | 2010-07-19 10:31:34 -0700 | [diff] [blame] | 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 |         LOGW("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 |  | 
| Kenny Root | b94a9a6 | 2010-06-01 10:34:29 -0700 | [diff] [blame] | 345 | } |