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