blob: 120f23d3628e04d8d6d2a64c62d686d26585194c [file] [log] [blame]
Joe Onorato4535e402009-05-15 09:07:06 -04001/*
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
Joe Onorato2e1da322009-05-15 18:20:19 -040017#define LOG_TAG "backup_data"
18
Mathias Agopian8ae23352009-06-04 13:53:57 -070019#include <utils/BackupHelpers.h>
Joe Onorato4535e402009-05-15 09:07:06 -040020#include <utils/ByteOrder.h>
21
22#include <stdio.h>
23#include <unistd.h>
24
Joe Onorato2e1da322009-05-15 18:20:19 -040025#include <cutils/log.h>
26
Joe Onorato4535e402009-05-15 09:07:06 -040027namespace 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
Joe Onorato4535e402009-05-15 09:07:06 -040042const 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
Joe Onorato2e1da322009-05-15 18:20:19 -040089BackupDataWriter::WriteAppHeader(const String8& packageName, int cookie)
Joe Onorato4535e402009-05-15 09:07:06 -040090{
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 app_header_v1 header;
103 ssize_t nameLen;
104
105 nameLen = packageName.length();
106
Joe Onoratod2110db2009-05-19 13:41:21 -0700107 header.type = tolel(BACKUP_HEADER_APP_V1);
Joe Onorato4535e402009-05-15 09:07:06 -0400108 header.packageLen = tolel(nameLen);
Joe Onorato2e1da322009-05-15 18:20:19 -0400109 header.cookie = cookie;
Joe Onorato4535e402009-05-15 09:07:06 -0400110
111 amt = write(m_fd, &header, sizeof(app_header_v1));
112 if (amt != sizeof(app_header_v1)) {
113 m_status = errno;
114 return m_status;
115 }
116 m_pos += amt;
117
118 amt = write(m_fd, packageName.string(), nameLen+1);
119 if (amt != nameLen+1) {
120 m_status = errno;
121 return m_status;
122 }
123 m_pos += amt;
124
125 return NO_ERROR;
126}
127
128status_t
129BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
130{
131 if (m_status != NO_ERROR) {
132 return m_status;
133 }
134
135 ssize_t amt;
136
137 amt = write_padding_for(m_pos);
138 if (amt != 0) {
139 return amt;
140 }
141
142 entity_header_v1 header;
143 ssize_t keyLen;
144
145 keyLen = key.length();
146
Joe Onoratod2110db2009-05-19 13:41:21 -0700147 header.type = tolel(BACKUP_HEADER_ENTITY_V1);
Joe Onorato4535e402009-05-15 09:07:06 -0400148 header.keyLen = tolel(keyLen);
149 header.dataSize = tolel(dataSize);
150
151 amt = write(m_fd, &header, sizeof(entity_header_v1));
152 if (amt != sizeof(entity_header_v1)) {
153 m_status = errno;
154 return m_status;
155 }
156 m_pos += amt;
157
158 amt = write(m_fd, key.string(), keyLen+1);
159 if (amt != keyLen+1) {
160 m_status = errno;
161 return m_status;
162 }
163 m_pos += amt;
164
165 amt = write_padding_for(keyLen+1);
166
167 m_entityCount++;
168
169 return amt;
170}
171
172status_t
173BackupDataWriter::WriteEntityData(const void* data, size_t size)
174{
175 if (m_status != NO_ERROR) {
176 return m_status;
177 }
178
179 // We don't write padding here, because they're allowed to call this several
180 // times with smaller buffers. We write it at the end of WriteEntityHeader
181 // instead.
182 ssize_t amt = write(m_fd, data, size);
183 if (amt != (ssize_t)size) {
184 m_status = errno;
185 return m_status;
186 }
187 m_pos += amt;
188 return NO_ERROR;
189}
190
191status_t
Joe Onorato2e1da322009-05-15 18:20:19 -0400192BackupDataWriter::WriteAppFooter(int cookie)
Joe Onorato4535e402009-05-15 09:07:06 -0400193{
194 if (m_status != NO_ERROR) {
195 return m_status;
196 }
197
198 ssize_t amt;
199
200 amt = write_padding_for(m_pos);
201 if (amt != 0) {
202 return amt;
203 }
204
205 app_footer_v1 footer;
206 ssize_t nameLen;
207
Joe Onoratod2110db2009-05-19 13:41:21 -0700208 footer.type = tolel(BACKUP_FOOTER_APP_V1);
Joe Onorato4535e402009-05-15 09:07:06 -0400209 footer.entityCount = tolel(m_entityCount);
Joe Onorato2e1da322009-05-15 18:20:19 -0400210 footer.cookie = cookie;
Joe Onorato4535e402009-05-15 09:07:06 -0400211
212 amt = write(m_fd, &footer, sizeof(app_footer_v1));
213 if (amt != sizeof(app_footer_v1)) {
214 m_status = errno;
215 return m_status;
216 }
217 m_pos += amt;
218
219 return NO_ERROR;
220}
221
Joe Onorato2e1da322009-05-15 18:20:19 -0400222
223BackupDataReader::BackupDataReader(int fd)
224 :m_fd(fd),
225 m_status(NO_ERROR),
226 m_pos(0),
227 m_entityCount(0)
228{
229 memset(&m_header, 0, sizeof(m_header));
230}
231
232BackupDataReader::~BackupDataReader()
233{
234}
235
236status_t
237BackupDataReader::Status()
238{
239 return m_status;
240}
241
242#define CHECK_SIZE(actual, expected) \
243 do { \
244 if ((actual) != (expected)) { \
245 if ((actual) == 0) { \
246 m_status = EIO; \
247 } else { \
248 m_status = errno; \
249 } \
250 return m_status; \
251 } \
252 } while(0)
253#define SKIP_PADDING() \
254 do { \
255 status_t err = skip_padding(); \
256 if (err != NO_ERROR) { \
257 m_status = err; \
258 return err; \
259 } \
260 } while(0)
261
262status_t
Joe Onoratod2110db2009-05-19 13:41:21 -0700263BackupDataReader::ReadNextHeader(int* type)
Joe Onorato2e1da322009-05-15 18:20:19 -0400264{
265 if (m_status != NO_ERROR) {
266 return m_status;
267 }
268
269 int amt;
270
271 SKIP_PADDING();
272 amt = read(m_fd, &m_header, sizeof(m_header));
273 CHECK_SIZE(amt, sizeof(m_header));
274
275 // validate and fix up the fields.
276 m_header.type = fromlel(m_header.type);
277 switch (m_header.type)
278 {
Joe Onoratod2110db2009-05-19 13:41:21 -0700279 case BACKUP_HEADER_APP_V1:
Joe Onorato2e1da322009-05-15 18:20:19 -0400280 m_header.app.packageLen = fromlel(m_header.app.packageLen);
281 if (m_header.app.packageLen < 0) {
282 LOGD("App header at %d has packageLen<0: 0x%08x\n", (int)m_pos,
283 (int)m_header.app.packageLen);
284 m_status = EINVAL;
285 }
286 m_header.app.cookie = m_header.app.cookie;
287 break;
Joe Onoratod2110db2009-05-19 13:41:21 -0700288 case BACKUP_HEADER_ENTITY_V1:
Joe Onorato2e1da322009-05-15 18:20:19 -0400289 m_header.entity.keyLen = fromlel(m_header.entity.keyLen);
290 if (m_header.entity.keyLen <= 0) {
291 LOGD("Entity header at %d has keyLen<=0: 0x%08x\n", (int)m_pos,
292 (int)m_header.entity.keyLen);
293 m_status = EINVAL;
294 }
295 m_header.entity.dataSize = fromlel(m_header.entity.dataSize);
Joe Onorato2e1da322009-05-15 18:20:19 -0400296 m_entityCount++;
297 break;
Joe Onoratod2110db2009-05-19 13:41:21 -0700298 case BACKUP_FOOTER_APP_V1:
Joe Onorato2e1da322009-05-15 18:20:19 -0400299 m_header.footer.entityCount = fromlel(m_header.footer.entityCount);
300 if (m_header.footer.entityCount < 0) {
301 LOGD("Entity header at %d has entityCount<0: 0x%08x\n", (int)m_pos,
302 (int)m_header.footer.entityCount);
303 m_status = EINVAL;
304 }
305 m_header.footer.cookie = m_header.footer.cookie;
306 break;
307 default:
308 LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type);
309 m_status = EINVAL;
310 }
311 m_pos += sizeof(m_header);
Joe Onoratod2110db2009-05-19 13:41:21 -0700312 if (type) {
313 *type = m_header.type;
314 }
Joe Onorato2e1da322009-05-15 18:20:19 -0400315
316 return m_status;
317}
318
319status_t
320BackupDataReader::ReadAppHeader(String8* packageName, int* cookie)
321{
322 if (m_status != NO_ERROR) {
323 return m_status;
324 }
Joe Onoratod2110db2009-05-19 13:41:21 -0700325 if (m_header.type != BACKUP_HEADER_APP_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -0400326 return EINVAL;
327 }
328 size_t size = m_header.app.packageLen;
329 char* buf = packageName->lockBuffer(size);
330 if (packageName == NULL) {
331 packageName->unlockBuffer();
332 m_status = ENOMEM;
333 return m_status;
334 }
335 int amt = read(m_fd, buf, size+1);
336 CHECK_SIZE(amt, (int)size+1);
337 packageName->unlockBuffer(size);
338 m_pos += size+1;
339 *cookie = m_header.app.cookie;
340 return NO_ERROR;
341}
342
343bool
344BackupDataReader::HasEntities()
345{
Joe Onoratod2110db2009-05-19 13:41:21 -0700346 return m_status == NO_ERROR && m_header.type == BACKUP_HEADER_ENTITY_V1;
Joe Onorato2e1da322009-05-15 18:20:19 -0400347}
348
349status_t
350BackupDataReader::ReadEntityHeader(String8* key, size_t* dataSize)
351{
352 if (m_status != NO_ERROR) {
353 return m_status;
354 }
Joe Onoratod2110db2009-05-19 13:41:21 -0700355 if (m_header.type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -0400356 return EINVAL;
357 }
Joe Onoratod2110db2009-05-19 13:41:21 -0700358 size_t size = m_header.entity.keyLen;
Joe Onorato2e1da322009-05-15 18:20:19 -0400359 char* buf = key->lockBuffer(size);
360 if (key == NULL) {
361 key->unlockBuffer();
362 m_status = ENOMEM;
363 return m_status;
364 }
365 int amt = read(m_fd, buf, size+1);
366 CHECK_SIZE(amt, (int)size+1);
367 key->unlockBuffer(size);
368 m_pos += size+1;
369 *dataSize = m_header.entity.dataSize;
370 SKIP_PADDING();
371 return NO_ERROR;
372}
373
374status_t
Joe Onoratod2110db2009-05-19 13:41:21 -0700375BackupDataReader::SkipEntityData()
376{
377 if (m_status != NO_ERROR) {
378 return m_status;
379 }
380 if (m_header.type != BACKUP_HEADER_ENTITY_V1) {
381 return EINVAL;
382 }
383 if (m_header.entity.dataSize > 0) {
384 int pos = lseek(m_fd, m_header.entity.dataSize, SEEK_CUR);
385 return pos == -1 ? (int)errno : (int)NO_ERROR;
386 } else {
387 return NO_ERROR;
388 }
389}
390
391status_t
Joe Onorato2e1da322009-05-15 18:20:19 -0400392BackupDataReader::ReadEntityData(void* data, size_t size)
393{
394 if (m_status != NO_ERROR) {
395 return m_status;
396 }
397 int amt = read(m_fd, data, size);
398 CHECK_SIZE(amt, (int)size);
399 m_pos += size;
400 return NO_ERROR;
401}
402
403status_t
404BackupDataReader::ReadAppFooter(int* cookie)
405{
406 if (m_status != NO_ERROR) {
407 return m_status;
408 }
Joe Onoratod2110db2009-05-19 13:41:21 -0700409 if (m_header.type != BACKUP_FOOTER_APP_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -0400410 return EINVAL;
411 }
412 if (m_header.footer.entityCount != m_entityCount) {
413 LOGD("entity count mismatch actual=%d expected=%d", m_entityCount,
414 m_header.footer.entityCount);
415 m_status = EINVAL;
416 return m_status;
417 }
418 *cookie = m_header.footer.cookie;
419 return NO_ERROR;
420}
421
422status_t
423BackupDataReader::skip_padding()
424{
425 ssize_t amt;
426 ssize_t paddingSize;
427
428 paddingSize = padding_extra(m_pos);
429 if (paddingSize > 0) {
430 uint32_t padding;
431 amt = read(m_fd, &padding, paddingSize);
432 CHECK_SIZE(amt, paddingSize);
433 m_pos += amt;
434 }
435 return NO_ERROR;
436}
437
438
Joe Onorato4535e402009-05-15 09:07:06 -0400439} // namespace android