1/* 2 * Copyright (C) 2009 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#define LOG_TAG "backup_data" 18 19#include <stdio.h> 20#include <string.h> 21#include <unistd.h> 22 23#include <androidfw/BackupHelpers.h> 24#include <log/log.h> 25#include <utils/ByteOrder.h> 26 27namespace android { 28 29static const bool kIsDebug = false; 30 31/* 32 * File Format (v1): 33 * 34 * All ints are stored little-endian. 35 * 36 * - An app_header_v1 struct. 37 * - The name of the package, utf-8, null terminated, padded to 4-byte boundary. 38 * - A sequence of zero or more key/value paires (entities), each with 39 * - A entity_header_v1 struct 40 * - The key, utf-8, null terminated, padded to 4-byte boundary. 41 * - The value, padded to 4 byte boundary 42 */ 43 44const static int ROUND_UP[4] = { 0, 3, 2, 1 }; 45 46static inline size_t 47padding_extra(size_t n) 48{ 49 return ROUND_UP[n % 4]; 50} 51 52BackupDataWriter::BackupDataWriter(int fd) 53 :m_fd(fd), 54 m_status(NO_ERROR), 55 m_entityCount(0) 56{ 57 m_pos = (ssize_t) lseek(fd, 0, SEEK_CUR); 58 if (kIsDebug) ALOGI("BackupDataWriter(%d) @ %ld", fd, (long)m_pos); 59} 60 61BackupDataWriter::~BackupDataWriter() 62{ 63} 64 65// Pad out anything they've previously written to the next 4 byte boundary. 66status_t 67BackupDataWriter::write_padding_for(int n) 68{ 69 ssize_t amt; 70 ssize_t paddingSize; 71 72 paddingSize = padding_extra(n); 73 if (paddingSize > 0) { 74 uint32_t padding = 0xbcbcbcbc; 75 if (kIsDebug) ALOGI("writing %zd padding bytes for %d", paddingSize, n); 76 amt = write(m_fd, &padding, paddingSize); 77 if (amt != paddingSize) { 78 m_status = errno; 79 return m_status; 80 } 81 m_pos += amt; 82 } 83 return NO_ERROR; 84} 85 86status_t 87BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) 88{ 89 if (m_status != NO_ERROR) { 90 return m_status; 91 } 92 93 ssize_t amt; 94 95 amt = write_padding_for(m_pos); 96 if (amt != 0) { 97 return amt; 98 } 99 100 String8 k; 101 if (m_keyPrefix.length() > 0) { 102 k = m_keyPrefix; 103 k += ":"; 104 k += key; 105 } else { 106 k = key; 107 } 108 if (kIsDebug) { 109 ALOGD("Writing header: prefix='%s' key='%s' dataSize=%zu", m_keyPrefix.string(), 110 key.string(), dataSize); 111 } 112 113 entity_header_v1 header; 114 ssize_t keyLen; 115 116 keyLen = k.length(); 117 118 header.type = tolel(BACKUP_HEADER_ENTITY_V1); 119 header.keyLen = tolel(keyLen); 120 header.dataSize = tolel(dataSize); 121 122 if (kIsDebug) ALOGI("writing entity header, %zu bytes", sizeof(entity_header_v1)); 123 amt = write(m_fd, &header, sizeof(entity_header_v1)); 124 if (amt != sizeof(entity_header_v1)) { 125 m_status = errno; 126 return m_status; 127 } 128 m_pos += amt; 129 130 if (kIsDebug) ALOGI("writing entity header key, %zd bytes", keyLen+1); 131 amt = write(m_fd, k.string(), keyLen+1); 132 if (amt != keyLen+1) { 133 m_status = errno; 134 return m_status; 135 } 136 m_pos += amt; 137 138 amt = write_padding_for(keyLen+1); 139 140 m_entityCount++; 141 142 return amt; 143} 144 145status_t 146BackupDataWriter::WriteEntityData(const void* data, size_t size) 147{ 148 if (kIsDebug) ALOGD("Writing data: size=%lu", (unsigned long) size); 149 150 if (m_status != NO_ERROR) { 151 if (kIsDebug) { 152 ALOGD("Not writing data - stream in error state %d (%s)", m_status, strerror(m_status)); 153 } 154 return m_status; 155 } 156 157 // We don't write padding here, because they're allowed to call this several 158 // times with smaller buffers. We write it at the end of WriteEntityHeader 159 // instead. 160 ssize_t amt = write(m_fd, data, size); 161 if (amt != (ssize_t)size) { 162 m_status = errno; 163 if (kIsDebug) ALOGD("write returned error %d (%s)", m_status, strerror(m_status)); 164 return m_status; 165 } 166 m_pos += amt; 167 return NO_ERROR; 168} 169 170void 171BackupDataWriter::SetKeyPrefix(const String8& keyPrefix) 172{ 173 m_keyPrefix = keyPrefix; 174} 175 176 177BackupDataReader::BackupDataReader(int fd) 178 :m_fd(fd), 179 m_done(false), 180 m_status(NO_ERROR), 181 m_entityCount(0) 182{ 183 memset(&m_header, 0, sizeof(m_header)); 184 m_pos = (ssize_t) lseek(fd, 0, SEEK_CUR); 185 if (kIsDebug) ALOGI("BackupDataReader(%d) @ %ld", fd, (long)m_pos); 186} 187 188BackupDataReader::~BackupDataReader() 189{ 190} 191 192status_t 193BackupDataReader::Status() 194{ 195 return m_status; 196} 197 198#define CHECK_SIZE(actual, expected) \ 199 do { \ 200 if ((actual) != (expected)) { \ 201 if ((actual) == 0) { \ 202 m_status = EIO; \ 203 m_done = true; \ 204 } else { \ 205 m_status = errno; \ 206 ALOGD("CHECK_SIZE(a=%ld e=%ld) failed at line %d m_status='%s'", \ 207 long(actual), long(expected), __LINE__, strerror(m_status)); \ 208 } \ 209 return m_status; \ 210 } \ 211 } while(0) 212#define SKIP_PADDING() \ 213 do { \ 214 status_t err = skip_padding(); \ 215 if (err != NO_ERROR) { \ 216 ALOGD("SKIP_PADDING FAILED at line %d", __LINE__); \ 217 m_status = err; \ 218 return err; \ 219 } \ 220 } while(0) 221 222status_t 223BackupDataReader::ReadNextHeader(bool* done, int* type) 224{ 225 *done = m_done; 226 if (m_status != NO_ERROR) { 227 return m_status; 228 } 229 230 int amt; 231 232 amt = skip_padding(); 233 if (amt == EIO) { 234 *done = m_done = true; 235 return NO_ERROR; 236 } 237 else if (amt != NO_ERROR) { 238 return amt; 239 } 240 amt = read(m_fd, &m_header, sizeof(m_header)); 241 *done = m_done = (amt == 0); 242 if (*done) { 243 return NO_ERROR; 244 } 245 CHECK_SIZE(amt, sizeof(m_header)); 246 m_pos += sizeof(m_header); 247 if (type) { 248 *type = m_header.type; 249 } 250 251 // validate and fix up the fields. 252 m_header.type = fromlel(m_header.type); 253 switch (m_header.type) 254 { 255 case BACKUP_HEADER_ENTITY_V1: 256 { 257 m_header.entity.keyLen = fromlel(m_header.entity.keyLen); 258 if (m_header.entity.keyLen <= 0) { 259 ALOGD("Entity header at %d has keyLen<=0: 0x%08x\n", (int)m_pos, 260 (int)m_header.entity.keyLen); 261 m_status = EINVAL; 262 } 263 m_header.entity.dataSize = fromlel(m_header.entity.dataSize); 264 m_entityCount++; 265 266 // read the rest of the header (filename) 267 size_t size = m_header.entity.keyLen; 268 char* buf = m_key.lockBuffer(size); 269 if (buf == NULL) { 270 m_status = ENOMEM; 271 return m_status; 272 } 273 int amt = read(m_fd, buf, size+1); 274 CHECK_SIZE(amt, (int)size+1); 275 m_key.unlockBuffer(size); 276 m_pos += size+1; 277 SKIP_PADDING(); 278 m_dataEndPos = m_pos + m_header.entity.dataSize; 279 280 break; 281 } 282 default: 283 ALOGD("Chunk header at %d has invalid type: 0x%08x", 284 (int)(m_pos - sizeof(m_header)), (int)m_header.type); 285 m_status = EINVAL; 286 } 287 288 return m_status; 289} 290 291bool 292BackupDataReader::HasEntities() 293{ 294 return m_status == NO_ERROR && m_header.type == BACKUP_HEADER_ENTITY_V1; 295} 296 297status_t 298BackupDataReader::ReadEntityHeader(String8* key, size_t* dataSize) 299{ 300 if (m_status != NO_ERROR) { 301 return m_status; 302 } 303 if (m_header.type != BACKUP_HEADER_ENTITY_V1) { 304 return EINVAL; 305 } 306 *key = m_key; 307 *dataSize = m_header.entity.dataSize; 308 return NO_ERROR; 309} 310 311status_t 312BackupDataReader::SkipEntityData() 313{ 314 if (m_status != NO_ERROR) { 315 return m_status; 316 } 317 if (m_header.type != BACKUP_HEADER_ENTITY_V1) { 318 return EINVAL; 319 } 320 if (m_header.entity.dataSize > 0) { 321 int pos = lseek(m_fd, m_dataEndPos, SEEK_SET); 322 if (pos == -1) { 323 return errno; 324 } 325 m_pos = pos; 326 } 327 SKIP_PADDING(); 328 return NO_ERROR; 329} 330 331ssize_t 332BackupDataReader::ReadEntityData(void* data, size_t size) 333{ 334 if (m_status != NO_ERROR) { 335 return -1; 336 } 337 int remaining = m_dataEndPos - m_pos; 338 if (kIsDebug) { 339 ALOGD("ReadEntityData size=%zu m_pos=0x%zx m_dataEndPos=0x%zx remaining=%d\n", 340 size, m_pos, m_dataEndPos, remaining); 341 } 342 if (remaining <= 0) { 343 return 0; 344 } 345 if (((int)size) > remaining) { 346 size = remaining; 347 } 348 if (kIsDebug) { 349 ALOGD(" reading %zu bytes", size); 350 } 351 int amt = read(m_fd, data, size); 352 if (amt < 0) { 353 m_status = errno; 354 return -1; 355 } 356 if (amt == 0) { 357 m_status = EIO; 358 m_done = true; 359 } 360 m_pos += amt; 361 return amt; 362} 363 364status_t 365BackupDataReader::skip_padding() 366{ 367 ssize_t amt; 368 ssize_t paddingSize; 369 370 paddingSize = padding_extra(m_pos); 371 if (paddingSize > 0) { 372 uint32_t padding; 373 amt = read(m_fd, &padding, paddingSize); 374 CHECK_SIZE(amt, paddingSize); 375 m_pos += amt; 376 } 377 return NO_ERROR; 378} 379 380 381} // namespace android 382