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 84 ObbFile::ObbFile() 85 : mPackageName("") 86 , mVersion(-1) 87 , mFlags(0) 88 { 89 memset(mSalt, 0, sizeof(mSalt)); 90 } 91 92 ObbFile::~ObbFile() { 93 } 94 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 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 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 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 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 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 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