blob: dd044496c36380d611e1d68595c15a043f94d006 [file] [log] [blame]
Joe Onorato8d626d62009-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 Onoratod502f052009-05-15 18:20:19 -040017#define LOG_TAG "backup_data"
18
Joe Onorato8d626d62009-05-15 09:07:06 -040019#include <utils/backup_helpers.h>
20#include <utils/ByteOrder.h>
21
22#include <stdio.h>
23#include <unistd.h>
24
Joe Onoratod502f052009-05-15 18:20:19 -040025#include <cutils/log.h>
26
Joe Onorato8d626d62009-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
42#define APP_MAGIC_V1 0x31707041 // App1 (little endian)
43#define ENTITY_MAGIC_V1 0x61746144 // Data (little endian)
44#define FOOTER_MAGIC_V1 0x746f6f46 // Foot (little endian)
45
Joe Onorato8d626d62009-05-15 09:07:06 -040046const static int ROUND_UP[4] = { 0, 3, 2, 1 };
47
48static inline size_t
49round_up(size_t n)
50{
51 return n + ROUND_UP[n % 4];
52}
53
54static inline size_t
55padding_extra(size_t n)
56{
57 return ROUND_UP[n % 4];
58}
59
60BackupDataWriter::BackupDataWriter(int fd)
61 :m_fd(fd),
62 m_status(NO_ERROR),
63 m_pos(0),
64 m_entityCount(0)
65{
66}
67
68BackupDataWriter::~BackupDataWriter()
69{
70}
71
72// Pad out anything they've previously written to the next 4 byte boundary.
73status_t
74BackupDataWriter::write_padding_for(int n)
75{
76 ssize_t amt;
77 ssize_t paddingSize;
78
79 paddingSize = padding_extra(n);
80 if (paddingSize > 0) {
81 uint32_t padding = 0xbcbcbcbc;
82 amt = write(m_fd, &padding, paddingSize);
83 if (amt != paddingSize) {
84 m_status = errno;
85 return m_status;
86 }
87 m_pos += amt;
88 }
89 return NO_ERROR;
90}
91
92status_t
Joe Onoratod502f052009-05-15 18:20:19 -040093BackupDataWriter::WriteAppHeader(const String8& packageName, int cookie)
Joe Onorato8d626d62009-05-15 09:07:06 -040094{
95 if (m_status != NO_ERROR) {
96 return m_status;
97 }
98
99 ssize_t amt;
100
101 amt = write_padding_for(m_pos);
102 if (amt != 0) {
103 return amt;
104 }
105
106 app_header_v1 header;
107 ssize_t nameLen;
108
109 nameLen = packageName.length();
110
111 header.type = tolel(APP_MAGIC_V1);
112 header.packageLen = tolel(nameLen);
Joe Onoratod502f052009-05-15 18:20:19 -0400113 header.cookie = cookie;
Joe Onorato8d626d62009-05-15 09:07:06 -0400114
115 amt = write(m_fd, &header, sizeof(app_header_v1));
116 if (amt != sizeof(app_header_v1)) {
117 m_status = errno;
118 return m_status;
119 }
120 m_pos += amt;
121
122 amt = write(m_fd, packageName.string(), nameLen+1);
123 if (amt != nameLen+1) {
124 m_status = errno;
125 return m_status;
126 }
127 m_pos += amt;
128
129 return NO_ERROR;
130}
131
132status_t
133BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
134{
135 if (m_status != NO_ERROR) {
136 return m_status;
137 }
138
139 ssize_t amt;
140
141 amt = write_padding_for(m_pos);
142 if (amt != 0) {
143 return amt;
144 }
145
146 entity_header_v1 header;
147 ssize_t keyLen;
148
149 keyLen = key.length();
150
151 header.type = tolel(ENTITY_MAGIC_V1);
152 header.keyLen = tolel(keyLen);
153 header.dataSize = tolel(dataSize);
154
155 amt = write(m_fd, &header, sizeof(entity_header_v1));
156 if (amt != sizeof(entity_header_v1)) {
157 m_status = errno;
158 return m_status;
159 }
160 m_pos += amt;
161
162 amt = write(m_fd, key.string(), keyLen+1);
163 if (amt != keyLen+1) {
164 m_status = errno;
165 return m_status;
166 }
167 m_pos += amt;
168
169 amt = write_padding_for(keyLen+1);
170
171 m_entityCount++;
172
173 return amt;
174}
175
176status_t
177BackupDataWriter::WriteEntityData(const void* data, size_t size)
178{
179 if (m_status != NO_ERROR) {
180 return m_status;
181 }
182
183 // We don't write padding here, because they're allowed to call this several
184 // times with smaller buffers. We write it at the end of WriteEntityHeader
185 // instead.
186 ssize_t amt = write(m_fd, data, size);
187 if (amt != (ssize_t)size) {
188 m_status = errno;
189 return m_status;
190 }
191 m_pos += amt;
192 return NO_ERROR;
193}
194
195status_t
Joe Onoratod502f052009-05-15 18:20:19 -0400196BackupDataWriter::WriteAppFooter(int cookie)
Joe Onorato8d626d62009-05-15 09:07:06 -0400197{
198 if (m_status != NO_ERROR) {
199 return m_status;
200 }
201
202 ssize_t amt;
203
204 amt = write_padding_for(m_pos);
205 if (amt != 0) {
206 return amt;
207 }
208
209 app_footer_v1 footer;
210 ssize_t nameLen;
211
212 footer.type = tolel(FOOTER_MAGIC_V1);
213 footer.entityCount = tolel(m_entityCount);
Joe Onoratod502f052009-05-15 18:20:19 -0400214 footer.cookie = cookie;
Joe Onorato8d626d62009-05-15 09:07:06 -0400215
216 amt = write(m_fd, &footer, sizeof(app_footer_v1));
217 if (amt != sizeof(app_footer_v1)) {
218 m_status = errno;
219 return m_status;
220 }
221 m_pos += amt;
222
223 return NO_ERROR;
224}
225
Joe Onoratod502f052009-05-15 18:20:19 -0400226
227BackupDataReader::BackupDataReader(int fd)
228 :m_fd(fd),
229 m_status(NO_ERROR),
230 m_pos(0),
231 m_entityCount(0)
232{
233 memset(&m_header, 0, sizeof(m_header));
234}
235
236BackupDataReader::~BackupDataReader()
237{
238}
239
240status_t
241BackupDataReader::Status()
242{
243 return m_status;
244}
245
246#define CHECK_SIZE(actual, expected) \
247 do { \
248 if ((actual) != (expected)) { \
249 if ((actual) == 0) { \
250 m_status = EIO; \
251 } else { \
252 m_status = errno; \
253 } \
254 return m_status; \
255 } \
256 } while(0)
257#define SKIP_PADDING() \
258 do { \
259 status_t err = skip_padding(); \
260 if (err != NO_ERROR) { \
261 m_status = err; \
262 return err; \
263 } \
264 } while(0)
265
266status_t
267BackupDataReader::ReadNextHeader()
268{
269 if (m_status != NO_ERROR) {
270 return m_status;
271 }
272
273 int amt;
274
275 SKIP_PADDING();
276 amt = read(m_fd, &m_header, sizeof(m_header));
277 CHECK_SIZE(amt, sizeof(m_header));
278
279 // validate and fix up the fields.
280 m_header.type = fromlel(m_header.type);
281 switch (m_header.type)
282 {
283 case APP_MAGIC_V1:
284 m_header.app.packageLen = fromlel(m_header.app.packageLen);
285 if (m_header.app.packageLen < 0) {
286 LOGD("App header at %d has packageLen<0: 0x%08x\n", (int)m_pos,
287 (int)m_header.app.packageLen);
288 m_status = EINVAL;
289 }
290 m_header.app.cookie = m_header.app.cookie;
291 break;
292 case ENTITY_MAGIC_V1:
293 m_header.entity.keyLen = fromlel(m_header.entity.keyLen);
294 if (m_header.entity.keyLen <= 0) {
295 LOGD("Entity header at %d has keyLen<=0: 0x%08x\n", (int)m_pos,
296 (int)m_header.entity.keyLen);
297 m_status = EINVAL;
298 }
299 m_header.entity.dataSize = fromlel(m_header.entity.dataSize);
300 if (m_header.entity.dataSize < 0) {
301 LOGD("Entity header at %d has dataSize<0: 0x%08x\n", (int)m_pos,
302 (int)m_header.entity.dataSize);
303 m_status = EINVAL;
304 }
305 m_entityCount++;
306 break;
307 case FOOTER_MAGIC_V1:
308 m_header.footer.entityCount = fromlel(m_header.footer.entityCount);
309 if (m_header.footer.entityCount < 0) {
310 LOGD("Entity header at %d has entityCount<0: 0x%08x\n", (int)m_pos,
311 (int)m_header.footer.entityCount);
312 m_status = EINVAL;
313 }
314 m_header.footer.cookie = m_header.footer.cookie;
315 break;
316 default:
317 LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type);
318 m_status = EINVAL;
319 }
320 m_pos += sizeof(m_header);
321
322 return m_status;
323}
324
325status_t
326BackupDataReader::ReadAppHeader(String8* packageName, int* cookie)
327{
328 if (m_status != NO_ERROR) {
329 return m_status;
330 }
331 if (m_header.type != APP_MAGIC_V1) {
332 return EINVAL;
333 }
334 size_t size = m_header.app.packageLen;
335 char* buf = packageName->lockBuffer(size);
336 if (packageName == NULL) {
337 packageName->unlockBuffer();
338 m_status = ENOMEM;
339 return m_status;
340 }
341 int amt = read(m_fd, buf, size+1);
342 CHECK_SIZE(amt, (int)size+1);
343 packageName->unlockBuffer(size);
344 m_pos += size+1;
345 *cookie = m_header.app.cookie;
346 return NO_ERROR;
347}
348
349bool
350BackupDataReader::HasEntities()
351{
352 return m_status == NO_ERROR && m_header.type == ENTITY_MAGIC_V1;
353}
354
355status_t
356BackupDataReader::ReadEntityHeader(String8* key, size_t* dataSize)
357{
358 if (m_status != NO_ERROR) {
359 return m_status;
360 }
361 if (m_header.type != ENTITY_MAGIC_V1) {
362 return EINVAL;
363 }
364 size_t size = m_header.app.packageLen;
365 char* buf = key->lockBuffer(size);
366 if (key == NULL) {
367 key->unlockBuffer();
368 m_status = ENOMEM;
369 return m_status;
370 }
371 int amt = read(m_fd, buf, size+1);
372 CHECK_SIZE(amt, (int)size+1);
373 key->unlockBuffer(size);
374 m_pos += size+1;
375 *dataSize = m_header.entity.dataSize;
376 SKIP_PADDING();
377 return NO_ERROR;
378}
379
380status_t
381BackupDataReader::ReadEntityData(void* data, size_t size)
382{
383 if (m_status != NO_ERROR) {
384 return m_status;
385 }
386 int amt = read(m_fd, data, size);
387 CHECK_SIZE(amt, (int)size);
388 m_pos += size;
389 return NO_ERROR;
390}
391
392status_t
393BackupDataReader::ReadAppFooter(int* cookie)
394{
395 if (m_status != NO_ERROR) {
396 return m_status;
397 }
398 if (m_header.type != FOOTER_MAGIC_V1) {
399 return EINVAL;
400 }
401 if (m_header.footer.entityCount != m_entityCount) {
402 LOGD("entity count mismatch actual=%d expected=%d", m_entityCount,
403 m_header.footer.entityCount);
404 m_status = EINVAL;
405 return m_status;
406 }
407 *cookie = m_header.footer.cookie;
408 return NO_ERROR;
409}
410
411status_t
412BackupDataReader::skip_padding()
413{
414 ssize_t amt;
415 ssize_t paddingSize;
416
417 paddingSize = padding_extra(m_pos);
418 if (paddingSize > 0) {
419 uint32_t padding;
420 amt = read(m_fd, &padding, paddingSize);
421 CHECK_SIZE(amt, paddingSize);
422 m_pos += amt;
423 }
424 return NO_ERROR;
425}
426
427
Joe Onorato8d626d62009-05-15 09:07:06 -0400428} // namespace android