blob: c7f1fdb58ee4be76221d36a97fb16aebe03b7c44 [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
17#include <utils/backup_helpers.h>
18#include <utils/ByteOrder.h>
19
20#include <stdio.h>
21#include <unistd.h>
22
23namespace android {
24
25/*
26 * File Format (v1):
27 *
28 * All ints are stored little-endian.
29 *
30 * - An app_header_v1 struct.
31 * - The name of the package, utf-8, null terminated, padded to 4-byte boundary.
32 * - A sequence of zero or more key/value paires (entities), each with
33 * - A entity_header_v1 struct
34 * - The key, utf-8, null terminated, padded to 4-byte boundary.
35 * - The value, padded to 4 byte boundary
36 */
37
38#define APP_MAGIC_V1 0x31707041 // App1 (little endian)
39#define ENTITY_MAGIC_V1 0x61746144 // Data (little endian)
40#define FOOTER_MAGIC_V1 0x746f6f46 // Foot (little endian)
41
42typedef struct {
43 int type; // == APP_MAGIC_V1
44 int packageLen; // length of the name of the package that follows, not including the null.
45} app_header_v1;
46
47typedef struct {
48 int type; // ENTITY_MAGIC_V1
49 int keyLen; // length of the key name, not including the null terminator
50 int dataSize; // size of the data, not including the padding
51} entity_header_v1;
52
53typedef struct {
54 int type; // FOOTER_MAGIC_V1
55 int entityCount; // the number of entities that were written
56} app_footer_v1;
57
58const static int ROUND_UP[4] = { 0, 3, 2, 1 };
59
60static inline size_t
61round_up(size_t n)
62{
63 return n + ROUND_UP[n % 4];
64}
65
66static inline size_t
67padding_extra(size_t n)
68{
69 return ROUND_UP[n % 4];
70}
71
72BackupDataWriter::BackupDataWriter(int fd)
73 :m_fd(fd),
74 m_status(NO_ERROR),
75 m_pos(0),
76 m_entityCount(0)
77{
78}
79
80BackupDataWriter::~BackupDataWriter()
81{
82}
83
84// Pad out anything they've previously written to the next 4 byte boundary.
85status_t
86BackupDataWriter::write_padding_for(int n)
87{
88 ssize_t amt;
89 ssize_t paddingSize;
90
91 paddingSize = padding_extra(n);
92 if (paddingSize > 0) {
93 uint32_t padding = 0xbcbcbcbc;
94 amt = write(m_fd, &padding, paddingSize);
95 if (amt != paddingSize) {
96 m_status = errno;
97 return m_status;
98 }
99 m_pos += amt;
100 }
101 return NO_ERROR;
102}
103
104status_t
105BackupDataWriter::WriteAppHeader(const String8& packageName)
106{
107 if (m_status != NO_ERROR) {
108 return m_status;
109 }
110
111 ssize_t amt;
112
113 amt = write_padding_for(m_pos);
114 if (amt != 0) {
115 return amt;
116 }
117
118 app_header_v1 header;
119 ssize_t nameLen;
120
121 nameLen = packageName.length();
122
123 header.type = tolel(APP_MAGIC_V1);
124 header.packageLen = tolel(nameLen);
125
126 amt = write(m_fd, &header, sizeof(app_header_v1));
127 if (amt != sizeof(app_header_v1)) {
128 m_status = errno;
129 return m_status;
130 }
131 m_pos += amt;
132
133 amt = write(m_fd, packageName.string(), nameLen+1);
134 if (amt != nameLen+1) {
135 m_status = errno;
136 return m_status;
137 }
138 m_pos += amt;
139
140 return NO_ERROR;
141}
142
143status_t
144BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
145{
146 if (m_status != NO_ERROR) {
147 return m_status;
148 }
149
150 ssize_t amt;
151
152 amt = write_padding_for(m_pos);
153 if (amt != 0) {
154 return amt;
155 }
156
157 entity_header_v1 header;
158 ssize_t keyLen;
159
160 keyLen = key.length();
161
162 header.type = tolel(ENTITY_MAGIC_V1);
163 header.keyLen = tolel(keyLen);
164 header.dataSize = tolel(dataSize);
165
166 amt = write(m_fd, &header, sizeof(entity_header_v1));
167 if (amt != sizeof(entity_header_v1)) {
168 m_status = errno;
169 return m_status;
170 }
171 m_pos += amt;
172
173 amt = write(m_fd, key.string(), keyLen+1);
174 if (amt != keyLen+1) {
175 m_status = errno;
176 return m_status;
177 }
178 m_pos += amt;
179
180 amt = write_padding_for(keyLen+1);
181
182 m_entityCount++;
183
184 return amt;
185}
186
187status_t
188BackupDataWriter::WriteEntityData(const void* data, size_t size)
189{
190 if (m_status != NO_ERROR) {
191 return m_status;
192 }
193
194 // We don't write padding here, because they're allowed to call this several
195 // times with smaller buffers. We write it at the end of WriteEntityHeader
196 // instead.
197 ssize_t amt = write(m_fd, data, size);
198 if (amt != (ssize_t)size) {
199 m_status = errno;
200 return m_status;
201 }
202 m_pos += amt;
203 return NO_ERROR;
204}
205
206status_t
207BackupDataWriter::WriteAppFooter()
208{
209 if (m_status != NO_ERROR) {
210 return m_status;
211 }
212
213 ssize_t amt;
214
215 amt = write_padding_for(m_pos);
216 if (amt != 0) {
217 return amt;
218 }
219
220 app_footer_v1 footer;
221 ssize_t nameLen;
222
223 footer.type = tolel(FOOTER_MAGIC_V1);
224 footer.entityCount = tolel(m_entityCount);
225
226 amt = write(m_fd, &footer, sizeof(app_footer_v1));
227 if (amt != sizeof(app_footer_v1)) {
228 m_status = errno;
229 return m_status;
230 }
231 m_pos += amt;
232
233 return NO_ERROR;
234}
235
236} // namespace android