blob: ad4a30877ef0ff68b6e997e1418c5972d82e0025 [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 Onorato3ad977b2009-05-05 11:50:51 -070017#define LOG_TAG "file_backup_helper"
18
Mathias Agopian8ae23352009-06-04 13:53:57 -070019#include <utils/BackupHelpers.h>
Joe Onorato3ad977b2009-05-05 11:50:51 -070020
21#include <utils/KeyedVector.h>
22#include <utils/ByteOrder.h>
23#include <utils/String8.h>
24
25#include <errno.h>
26#include <sys/types.h>
27#include <sys/uio.h>
28#include <sys/stat.h>
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -070029#include <sys/time.h> // for utimes
Joe Onorato3ad977b2009-05-05 11:50:51 -070030#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
Joe Onoratoc825d3e2009-05-06 12:55:46 -040033#include <utime.h>
Joe Onorato3ad977b2009-05-05 11:50:51 -070034#include <fcntl.h>
35#include <zlib.h>
36
37#include <cutils/log.h>
38
Joe Onorato4535e402009-05-15 09:07:06 -040039namespace android {
Joe Onorato3ad977b2009-05-05 11:50:51 -070040
41#define MAGIC0 0x70616e53 // Snap
42#define MAGIC1 0x656c6946 // File
43
Christopher Tatefbb92382009-06-23 17:35:11 -070044/*
45 * File entity data format (v1):
46 *
47 * - 4-byte version number of the metadata, little endian (0x00000001 for v1)
48 * - 12 bytes of metadata
49 * - the file data itself
50 *
51 * i.e. a 16-byte metadata header followed by the raw file data. If the
52 * restore code does not recognize the metadata version, it can still
53 * interpret the file data itself correctly.
54 *
55 * file_metadata_v1:
56 *
57 * - 4 byte version number === 0x00000001 (little endian)
58 * - 4-byte access mode (little-endian)
59 * - undefined (8 bytes)
60 */
61
62struct file_metadata_v1 {
63 int version;
64 int mode;
65 int undefined_1;
66 int undefined_2;
67};
68
69const static int CURRENT_METADATA_VERSION = 1;
70
Joe Onorato568bc322009-06-26 17:19:11 -040071#if 1
72#define LOGP(f, x...)
73#else
74#if TEST_BACKUP_HELPERS
Joe Onorato23ecae32009-06-10 17:07:15 -070075#define LOGP(f, x...) printf(f "\n", x)
Joe Onorato4535e402009-05-15 09:07:06 -040076#else
Joe Onorato290bb012009-05-13 18:57:29 -040077#define LOGP(x...) LOGD(x)
Joe Onorato4535e402009-05-15 09:07:06 -040078#endif
Joe Onorato568bc322009-06-26 17:19:11 -040079#endif
Joe Onorato290bb012009-05-13 18:57:29 -040080
Joe Onorato3ad977b2009-05-05 11:50:51 -070081const static int ROUND_UP[4] = { 0, 3, 2, 1 };
82
83static inline int
84round_up(int n)
85{
86 return n + ROUND_UP[n % 4];
87}
88
89static int
90read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
91{
92 int bytesRead = 0;
93 int amt;
94 SnapshotHeader header;
95
96 amt = read(fd, &header, sizeof(header));
97 if (amt != sizeof(header)) {
98 return errno;
99 }
100 bytesRead += amt;
101
102 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
103 LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
104 return 1;
105 }
106
107 for (int i=0; i<header.fileCount; i++) {
108 FileState file;
109 char filenameBuf[128];
110
Joe Onorato23ecae32009-06-10 17:07:15 -0700111 amt = read(fd, &file, sizeof(FileState));
112 if (amt != sizeof(FileState)) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700113 LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
114 return 1;
115 }
116 bytesRead += amt;
117
118 // filename is not NULL terminated, but it is padded
119 int nameBufSize = round_up(file.nameLen);
120 char* filename = nameBufSize <= (int)sizeof(filenameBuf)
121 ? filenameBuf
122 : (char*)malloc(nameBufSize);
123 amt = read(fd, filename, nameBufSize);
124 if (amt == nameBufSize) {
125 snapshot->add(String8(filename, file.nameLen), file);
126 }
127 bytesRead += amt;
128 if (filename != filenameBuf) {
129 free(filename);
130 }
131 if (amt != nameBufSize) {
132 LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
133 return 1;
134 }
135 }
136
137 if (header.totalSize != bytesRead) {
138 LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
139 header.totalSize, bytesRead);
140 return 1;
141 }
142
143 return 0;
144}
145
146static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700147write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700148{
Joe Onoratoce88cb12009-06-11 11:27:16 -0700149 int fileCount = 0;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700150 int bytesWritten = sizeof(SnapshotHeader);
151 // preflight size
152 const int N = snapshot.size();
153 for (int i=0; i<N; i++) {
Joe Onoratoce88cb12009-06-11 11:27:16 -0700154 const FileRec& g = snapshot.valueAt(i);
155 if (!g.deleted) {
156 const String8& name = snapshot.keyAt(i);
157 bytesWritten += sizeof(FileState) + round_up(name.length());
158 fileCount++;
159 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700160 }
161
Joe Onorato4535e402009-05-15 09:07:06 -0400162 LOGP("write_snapshot_file fd=%d\n", fd);
163
Joe Onorato3ad977b2009-05-05 11:50:51 -0700164 int amt;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700165 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
Joe Onorato3ad977b2009-05-05 11:50:51 -0700166
167 amt = write(fd, &header, sizeof(header));
168 if (amt != sizeof(header)) {
169 LOGW("write_snapshot_file error writing header %s", strerror(errno));
170 return errno;
171 }
172
Joe Onoratoce88cb12009-06-11 11:27:16 -0700173 for (int i=0; i<N; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700174 FileRec r = snapshot.valueAt(i);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700175 if (!r.deleted) {
176 const String8& name = snapshot.keyAt(i);
177 int nameLen = r.s.nameLen = name.length();
Joe Onorato3ad977b2009-05-05 11:50:51 -0700178
Joe Onoratoce88cb12009-06-11 11:27:16 -0700179 amt = write(fd, &r.s, sizeof(FileState));
180 if (amt != sizeof(FileState)) {
181 LOGW("write_snapshot_file error writing header %s", strerror(errno));
Joe Onorato3ad977b2009-05-05 11:50:51 -0700182 return 1;
183 }
Joe Onoratoce88cb12009-06-11 11:27:16 -0700184
185 // filename is not NULL terminated, but it is padded
186 amt = write(fd, name.string(), nameLen);
187 if (amt != nameLen) {
188 LOGW("write_snapshot_file error writing filename %s", strerror(errno));
189 return 1;
190 }
191 int paddingLen = ROUND_UP[nameLen % 4];
192 if (paddingLen != 0) {
193 int padding = 0xabababab;
194 amt = write(fd, &padding, paddingLen);
195 if (amt != paddingLen) {
196 LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
197 paddingLen, strerror(errno));
198 return 1;
199 }
200 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700201 }
202 }
203
204 return 0;
205}
206
207static int
Joe Onoratod2110db2009-05-19 13:41:21 -0700208write_delete_file(BackupDataWriter* dataStream, const String8& key)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700209{
Joe Onorato290bb012009-05-13 18:57:29 -0400210 LOGP("write_delete_file %s\n", key.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700211 return dataStream->WriteEntityHeader(key, -1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700212}
213
214static int
Christopher Tatefbb92382009-06-23 17:35:11 -0700215write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
Joe Onorato23ecae32009-06-10 17:07:15 -0700216 char const* realFilename)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700217{
Christopher Tatefbb92382009-06-23 17:35:11 -0700218 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
Joe Onoratod2110db2009-05-19 13:41:21 -0700219
220 const int bufsize = 4*1024;
221 int err;
222 int amt;
223 int fileSize;
224 int bytesLeft;
Christopher Tatefbb92382009-06-23 17:35:11 -0700225 file_metadata_v1 metadata;
Joe Onoratod2110db2009-05-19 13:41:21 -0700226
227 char* buf = (char*)malloc(bufsize);
228 int crc = crc32(0L, Z_NULL, 0);
229
230
Christopher Tatefbb92382009-06-23 17:35:11 -0700231 fileSize = lseek(fd, 0, SEEK_END);
Joe Onoratod2110db2009-05-19 13:41:21 -0700232 lseek(fd, 0, SEEK_SET);
233
Christopher Tatefbb92382009-06-23 17:35:11 -0700234 if (sizeof(metadata) != 16) {
235 LOGE("ERROR: metadata block is the wrong size!");
236 }
237
238 bytesLeft = fileSize + sizeof(metadata);
Joe Onoratod2110db2009-05-19 13:41:21 -0700239 err = dataStream->WriteEntityHeader(key, bytesLeft);
240 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700241 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700242 return err;
243 }
244
Christopher Tatefbb92382009-06-23 17:35:11 -0700245 // store the file metadata first
246 metadata.version = tolel(CURRENT_METADATA_VERSION);
247 metadata.mode = tolel(mode);
248 metadata.undefined_1 = metadata.undefined_2 = 0;
249 err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
250 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700251 free(buf);
Christopher Tatefbb92382009-06-23 17:35:11 -0700252 return err;
253 }
254 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
255
256 // now store the file content
Joe Onoratod2110db2009-05-19 13:41:21 -0700257 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
258 bytesLeft -= amt;
259 if (bytesLeft < 0) {
260 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised.
261 }
262 err = dataStream->WriteEntityData(buf, amt);
263 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700264 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700265 return err;
266 }
267 }
268 if (bytesLeft != 0) {
269 if (bytesLeft > 0) {
270 // Pad out the space we promised in the buffer. We can't corrupt the buffer,
271 // even though the data we're sending is probably bad.
272 memset(buf, 0, bufsize);
273 while (bytesLeft > 0) {
274 amt = bytesLeft < bufsize ? bytesLeft : bufsize;
275 bytesLeft -= amt;
276 err = dataStream->WriteEntityData(buf, amt);
277 if (err != 0) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700278 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700279 return err;
280 }
281 }
282 }
283 LOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
Joe Onorato23ecae32009-06-10 17:07:15 -0700284 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
Joe Onoratod2110db2009-05-19 13:41:21 -0700285 }
286
Christopher Tate63bcb792009-06-24 13:57:29 -0700287 free(buf);
Joe Onoratod2110db2009-05-19 13:41:21 -0700288 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700289}
290
291static int
Joe Onorato23ecae32009-06-10 17:07:15 -0700292write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
Joe Onoratod2110db2009-05-19 13:41:21 -0700293{
294 int err;
Christopher Tatefbb92382009-06-23 17:35:11 -0700295 struct stat st;
296
297 err = stat(realFilename, &st);
298 if (err < 0) {
299 return errno;
300 }
301
Joe Onorato23ecae32009-06-10 17:07:15 -0700302 int fd = open(realFilename, O_RDONLY);
Joe Onoratod2110db2009-05-19 13:41:21 -0700303 if (fd == -1) {
304 return errno;
305 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700306
307 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
Joe Onoratod2110db2009-05-19 13:41:21 -0700308 close(fd);
309 return err;
310}
311
312static int
313compute_crc32(int fd)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700314{
315 const int bufsize = 4*1024;
316 int amt;
317
Joe Onorato3ad977b2009-05-05 11:50:51 -0700318 char* buf = (char*)malloc(bufsize);
319 int crc = crc32(0L, Z_NULL, 0);
320
Joe Onoratod2110db2009-05-19 13:41:21 -0700321 lseek(fd, 0, SEEK_SET);
322
Joe Onorato3ad977b2009-05-05 11:50:51 -0700323 while ((amt = read(fd, buf, bufsize)) != 0) {
324 crc = crc32(crc, (Bytef*)buf, amt);
325 }
326
Christopher Tate63bcb792009-06-24 13:57:29 -0700327 free(buf);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700328 return crc;
329}
330
331int
Joe Onoratod2110db2009-05-19 13:41:21 -0700332back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato23ecae32009-06-10 17:07:15 -0700333 char const* const* files, char const* const* keys, int fileCount)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700334{
335 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700336 KeyedVector<String8,FileState> oldSnapshot;
Joe Onorato23ecae32009-06-10 17:07:15 -0700337 KeyedVector<String8,FileRec> newSnapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700338
339 if (oldSnapshotFD != -1) {
340 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
341 if (err != 0) {
342 // On an error, treat this as a full backup.
343 oldSnapshot.clear();
344 }
345 }
346
347 for (int i=0; i<fileCount; i++) {
Joe Onorato23ecae32009-06-10 17:07:15 -0700348 String8 key(keys[i]);
349 FileRec r;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700350 char const* file = files[i];
351 r.file = file;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700352 struct stat st;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700353
Joe Onorato23ecae32009-06-10 17:07:15 -0700354 err = stat(file, &st);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700355 if (err != 0) {
Joe Onoratoce88cb12009-06-11 11:27:16 -0700356 r.deleted = true;
357 } else {
358 r.deleted = false;
359 r.s.modTime_sec = st.st_mtime;
360 r.s.modTime_nsec = 0; // workaround sim breakage
361 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700362 r.s.mode = st.st_mode;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700363 r.s.size = st.st_size;
364 // we compute the crc32 later down below, when we already have the file open.
Joe Onorato3ad977b2009-05-05 11:50:51 -0700365
Joe Onoratoce88cb12009-06-11 11:27:16 -0700366 if (newSnapshot.indexOfKey(key) >= 0) {
367 LOGP("back_up_files key already in use '%s'", key.string());
368 return -1;
369 }
Joe Onorato23ecae32009-06-10 17:07:15 -0700370 }
371 newSnapshot.add(key, r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700372 }
373
374 int n = 0;
375 int N = oldSnapshot.size();
376 int m = 0;
377
378 while (n<N && m<fileCount) {
379 const String8& p = oldSnapshot.keyAt(n);
380 const String8& q = newSnapshot.keyAt(m);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700381 FileRec& g = newSnapshot.editValueAt(m);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700382 int cmp = p.compare(q);
Joe Onoratoce88cb12009-06-11 11:27:16 -0700383 if (g.deleted || cmp < 0) {
384 // file removed
385 LOGP("file removed: %s", p.string());
386 g.deleted = true; // They didn't mention the file, but we noticed that it's gone.
387 dataStream->WriteEntityHeader(p, -1);
388 n++;
389 }
390 else if (cmp > 0) {
Joe Onorato3ad977b2009-05-05 11:50:51 -0700391 // file added
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700392 LOGP("file added: %s", g.file.string());
393 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700394 m++;
395 }
Joe Onorato3ad977b2009-05-05 11:50:51 -0700396 else {
397 // both files exist, check them
Joe Onorato3ad977b2009-05-05 11:50:51 -0700398 const FileState& f = oldSnapshot.valueAt(n);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700399
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700400 int fd = open(g.file.string(), O_RDONLY);
Christopher Tate0032ce82009-06-04 17:01:06 -0700401 if (fd < 0) {
Joe Onoratod2110db2009-05-19 13:41:21 -0700402 // We can't open the file. Don't report it as a delete either. Let the
403 // server keep the old version. Maybe they'll be able to deal with it
404 // on restore.
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700405 LOGP("Unable to open file %s - skipping", g.file.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700406 } else {
Joe Onorato23ecae32009-06-10 17:07:15 -0700407 g.s.crc32 = compute_crc32(fd);
Joe Onoratod2110db2009-05-19 13:41:21 -0700408
Joe Onorato23ecae32009-06-10 17:07:15 -0700409 LOGP("%s", q.string());
Christopher Tate11b15772009-06-23 13:03:00 -0700410 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
411 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
412 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
413 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
Joe Onorato23ecae32009-06-10 17:07:15 -0700414 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
Christopher Tate11b15772009-06-23 13:03:00 -0700415 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
Christopher Tatefbb92382009-06-23 17:35:11 -0700416 write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700417 }
418
419 close(fd);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700420 }
421 n++;
422 m++;
423 }
424 }
425
426 // these were deleted
427 while (n<N) {
Joe Onoratod2110db2009-05-19 13:41:21 -0700428 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700429 n++;
430 }
431
432 // these were added
433 while (m<fileCount) {
434 const String8& q = newSnapshot.keyAt(m);
Joe Onorato23ecae32009-06-10 17:07:15 -0700435 FileRec& g = newSnapshot.editValueAt(m);
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700436 write_update_file(dataStream, q, g.file.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700437 m++;
438 }
439
440 err = write_snapshot_file(newSnapshotFD, newSnapshot);
441
442 return 0;
443}
444
Christopher Tate4a627c72011-04-01 14:43:32 -0700445// Utility function, equivalent to stpcpy(): perform a strcpy, but instead of
446// returning the initial dest, return a pointer to the trailing NUL.
447static char* strcpy_ptr(char* dest, const char* str) {
448 if (dest && str) {
449 while ((*dest = *str) != 0) {
450 dest++;
451 str++;
452 }
453 }
454 return dest;
455}
456
457int write_tarfile(const String8& packageName, const String8& domain,
458 const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
459{
460 // In the output stream everything is stored relative to the root
461 const char* relstart = filepath.string() + rootpath.length();
462 if (*relstart == '/') relstart++; // won't be true when path == rootpath
463 String8 relpath(relstart);
464
465 // Too long a name for the ustar format?
466 // "apps/" + packagename + '/' + domainpath < 155 chars
467 // relpath < 100 chars
468 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
469 LOGE("Filename [%s] too long, skipping", relpath.string());
470 return -1;
471 }
472
473 int err = 0;
474 struct stat64 s;
475 if (lstat64(filepath.string(), &s) != 0) {
476 err = errno;
477 LOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
478 return err;
479 }
480
481 const int isdir = S_ISDIR(s.st_mode);
482
483 // !!! TODO: use mmap when possible to avoid churning the buffer cache
484 // !!! TODO: this will break with symlinks; need to use readlink(2)
485 int fd = open(filepath.string(), O_RDONLY);
486 if (fd < 0) {
487 err = errno;
488 LOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
489 return err;
490 }
491
492 // read/write up to this much at a time.
493 const size_t BUFSIZE = 32 * 1024;
494
495 char* buf = new char[BUFSIZE];
496 if (buf == NULL) {
497 LOGE("Out of mem allocating transfer buffer");
498 err = ENOMEM;
499 goto done;
500 }
501
502 // Good to go -- first construct the standard tar header at the start of the buffer
503 memset(buf, 0, 512); // tar header is 512 bytes
504
505 // Magic fields for the ustar file format
506 strcat(buf + 257, "ustar");
507 strcat(buf + 263, "00");
508
509 {
510 // Prefix and main relative path. Path lengths have been preflighted.
511
512 // [ 345 : 155 ] filename path prefix [ustar]
513 //
514 // packagename and domain can each be empty.
515 char* cp = buf + 345;
516 if (packageName.length() > 0) {
517 // it's an app; so prefix with "apps/packagename/"
518 cp = strcpy_ptr(cp, "apps/");
519 cp = strcpy_ptr(cp, packageName.string());
520 }
521
522 if (domain.length() > 0) {
523 // only need a / if there was a package name
524 if (packageName.length() > 0) *cp++ = '/';
525 cp = strcpy_ptr(cp, domain.string());
526 }
527
528 // [ 0 : 100 ]; file name/path
529 strncpy(buf, relpath.string(), 100);
530
531 LOGI(" Name: %s/%s", buf + 345, buf);
532 }
533
534 // [ 100 : 8 ] file mode
535 snprintf(buf + 100, 8, "0%o", s.st_mode);
536
537 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time
538 // [ 116 : 8 ] gid -- ignored in Android format
539 snprintf(buf + 108, 8, "0%lo", s.st_uid);
540 snprintf(buf + 116, 8, "0%lo", s.st_gid);
541
542 // [ 124 : 12 ] file size in bytes
543 snprintf(buf + 124, 12, "0%llo", s.st_size);
544
545 // [ 136 : 12 ] last mod time as a UTC time_t
546 snprintf(buf + 136, 12, "%0lo", s.st_mtime);
547
548 // [ 148 : 8 ] checksum -- to be calculated with this field as space chars
549 memset(buf + 148, ' ', 8);
550
551 // [ 156 : 1 ] link/file type
552 uint8_t type;
553 if (isdir) {
554 type = '5'; // tar magic: '5' == directory
555 } else if (S_ISREG(s.st_mode)) {
556 type = '0'; // tar magic: '0' == normal file
557 } else {
558 LOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
559 goto cleanup;
560 }
561 buf[156] = type;
562
563 // [ 157 : 100 ] name of linked file [not implemented]
564
565 // Now go back and calculate the header checksum
566 {
567 uint16_t sum = 0;
568 for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) {
569 sum += *p;
570 }
571
572 // Now write the real checksum value:
573 // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC
574 sprintf(buf + 148, "%06o", sum); // the trailing space is already in place
575 }
576
577 // Write the 512-byte tar file header block to the output
578 writer->WriteEntityData(buf, 512);
579
580 // Now write the file data itself, for real files. We honor tar's convention that
581 // only full 512-byte blocks are sent to write().
582 if (!isdir) {
583 off64_t toWrite = s.st_size;
584 while (toWrite > 0) {
585 size_t toRead = (toWrite < BUFSIZE) ? toWrite : BUFSIZE;
586 ssize_t nRead = read(fd, buf, toRead);
587 if (nRead < 0) {
588 err = errno;
589 LOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
590 err, strerror(err));
591 break;
592 } else if (nRead == 0) {
593 LOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
594 filepath.string());
595 err = EIO;
596 break;
597 }
598
599 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This
600 // depends on the OS guarantee that for ordinary files, read() will never return
601 // less than the number of bytes requested.
602 ssize_t partial = (nRead+512) % 512;
603 if (partial > 0) {
604 ssize_t remainder = 512 - partial;
605 memset(buf + nRead, 0, remainder);
606 nRead += remainder;
607 }
608 writer->WriteEntityData(buf, nRead);
609 toWrite -= nRead;
610 }
611 }
612
613cleanup:
614 delete [] buf;
615done:
616 close(fd);
617 return err;
618}
619// end tarfile
620
621
622
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700623#define RESTORE_BUF_SIZE (8*1024)
624
625RestoreHelperBase::RestoreHelperBase()
626{
627 m_buf = malloc(RESTORE_BUF_SIZE);
Christopher Tate63bcb792009-06-24 13:57:29 -0700628 m_loggedUnknownMetadata = false;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700629}
630
631RestoreHelperBase::~RestoreHelperBase()
632{
633 free(m_buf);
634}
635
636status_t
637RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
638{
639 ssize_t err;
640 size_t dataSize;
641 String8 key;
642 int fd;
643 void* buf = m_buf;
644 ssize_t amt;
645 int mode;
646 int crc;
647 struct stat st;
648 FileRec r;
649
650 err = in->ReadEntityHeader(&key, &dataSize);
651 if (err != NO_ERROR) {
652 return err;
653 }
Joe Onorato5d605dc2009-06-18 18:23:43 -0700654
Christopher Tatefbb92382009-06-23 17:35:11 -0700655 // Get the metadata block off the head of the file entity and use that to
656 // set up the output file
657 file_metadata_v1 metadata;
658 amt = in->ReadEntityData(&metadata, sizeof(metadata));
659 if (amt != sizeof(metadata)) {
660 LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
661 (long)amt, strerror(errno));
662 return EIO;
663 }
664 metadata.version = fromlel(metadata.version);
665 metadata.mode = fromlel(metadata.mode);
666 if (metadata.version > CURRENT_METADATA_VERSION) {
Christopher Tate63bcb792009-06-24 13:57:29 -0700667 if (!m_loggedUnknownMetadata) {
668 m_loggedUnknownMetadata = true;
669 LOGW("Restoring file with unsupported metadata version %d (currently %d)",
670 metadata.version, CURRENT_METADATA_VERSION);
671 }
Christopher Tatefbb92382009-06-23 17:35:11 -0700672 }
673 mode = metadata.mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700674
675 // Write the file and compute the crc
676 crc = crc32(0L, Z_NULL, 0);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700677 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
678 if (fd == -1) {
679 LOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700680 return errno;
681 }
682
683 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
684 err = write(fd, buf, amt);
685 if (err != amt) {
686 close(fd);
Joe Onorato5d605dc2009-06-18 18:23:43 -0700687 LOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700688 return errno;
689 }
690 crc = crc32(crc, (Bytef*)buf, amt);
691 }
692
693 close(fd);
694
695 // Record for the snapshot
696 err = stat(filename.string(), &st);
697 if (err != 0) {
698 LOGW("Error stating file that we just created %s", filename.string());
699 return errno;
700 }
701
702 r.file = filename;
703 r.deleted = false;
704 r.s.modTime_sec = st.st_mtime;
705 r.s.modTime_nsec = 0; // workaround sim breakage
706 //r.s.modTime_nsec = st.st_mtime_nsec;
Christopher Tate11b15772009-06-23 13:03:00 -0700707 r.s.mode = st.st_mode;
Joe Onoratod2d9ceb2009-06-18 13:11:18 -0700708 r.s.size = st.st_size;
709 r.s.crc32 = crc;
710
711 m_files.add(key, r);
712
713 return NO_ERROR;
714}
715
716status_t
717RestoreHelperBase::WriteSnapshot(int fd)
718{
719 return write_snapshot_file(fd, m_files);;
720}
721
Joe Onorato3ad977b2009-05-05 11:50:51 -0700722#if TEST_BACKUP_HELPERS
723
724#define SCRATCH_DIR "/data/backup_helper_test/"
725
726static int
727write_text_file(const char* path, const char* data)
728{
729 int amt;
730 int fd;
731 int len;
732
733 fd = creat(path, 0666);
734 if (fd == -1) {
735 fprintf(stderr, "creat %s failed\n", path);
736 return errno;
737 }
738
739 len = strlen(data);
740 amt = write(fd, data, len);
741 if (amt != len) {
742 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
743 return errno;
744 }
745
746 close(fd);
747
748 return 0;
749}
750
751static int
752compare_file(const char* path, const unsigned char* data, int len)
753{
754 int fd;
755 int amt;
756
757 fd = open(path, O_RDONLY);
758 if (fd == -1) {
759 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
760 return errno;
761 }
762
763 unsigned char* contents = (unsigned char*)malloc(len);
764 if (contents == NULL) {
765 fprintf(stderr, "malloc(%d) failed\n", len);
766 return ENOMEM;
767 }
768
769 bool sizesMatch = true;
770 amt = lseek(fd, 0, SEEK_END);
771 if (amt != len) {
772 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
773 sizesMatch = false;
774 }
775 lseek(fd, 0, SEEK_SET);
776
777 int readLen = amt < len ? amt : len;
778 amt = read(fd, contents, readLen);
779 if (amt != readLen) {
780 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
781 }
782
783 bool contentsMatch = true;
784 for (int i=0; i<readLen; i++) {
785 if (data[i] != contents[i]) {
786 if (contentsMatch) {
787 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
788 contentsMatch = false;
789 }
790 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
791 }
792 }
793
Christopher Tate63bcb792009-06-24 13:57:29 -0700794 free(contents);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700795 return contentsMatch && sizesMatch ? 0 : 1;
796}
797
798int
799backup_helper_test_empty()
800{
801 int err;
802 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700803 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700804 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
805
806 system("rm -r " SCRATCH_DIR);
807 mkdir(SCRATCH_DIR, 0777);
808
809 // write
810 fd = creat(filename, 0666);
811 if (fd == -1) {
812 fprintf(stderr, "error creating %s\n", filename);
813 return 1;
814 }
815
816 err = write_snapshot_file(fd, snapshot);
817
818 close(fd);
819
820 if (err != 0) {
821 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
822 return err;
823 }
824
825 static const unsigned char correct_data[] = {
826 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
827 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
828 };
829
830 err = compare_file(filename, correct_data, sizeof(correct_data));
831 if (err != 0) {
832 return err;
833 }
834
835 // read
836 fd = open(filename, O_RDONLY);
837 if (fd == -1) {
838 fprintf(stderr, "error opening for read %s\n", filename);
839 return 1;
840 }
841
842 KeyedVector<String8,FileState> readSnapshot;
843 err = read_snapshot_file(fd, &readSnapshot);
844 if (err != 0) {
845 fprintf(stderr, "read_snapshot_file failed %d\n", err);
846 return err;
847 }
848
849 if (readSnapshot.size() != 0) {
850 fprintf(stderr, "readSnapshot should be length 0\n");
851 return 1;
852 }
853
854 return 0;
855}
856
857int
858backup_helper_test_four()
859{
860 int err;
861 int fd;
Joe Onorato23ecae32009-06-10 17:07:15 -0700862 KeyedVector<String8,FileRec> snapshot;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700863 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
864
865 system("rm -r " SCRATCH_DIR);
866 mkdir(SCRATCH_DIR, 0777);
867
868 // write
869 fd = creat(filename, 0666);
870 if (fd == -1) {
871 fprintf(stderr, "error opening %s\n", filename);
872 return 1;
873 }
874
875 String8 filenames[4];
876 FileState states[4];
Joe Onorato23ecae32009-06-10 17:07:15 -0700877 FileRec r;
Joe Onoratoce88cb12009-06-11 11:27:16 -0700878 r.deleted = false;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700879
880 states[0].modTime_sec = 0xfedcba98;
881 states[0].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700882 states[0].mode = 0777; // decimal 511, hex 0x000001ff
Joe Onorato3ad977b2009-05-05 11:50:51 -0700883 states[0].size = 0xababbcbc;
884 states[0].crc32 = 0x12345678;
885 states[0].nameLen = -12;
Joe Onorato23ecae32009-06-10 17:07:15 -0700886 r.s = states[0];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700887 filenames[0] = String8("bytes_of_padding");
Joe Onorato23ecae32009-06-10 17:07:15 -0700888 snapshot.add(filenames[0], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700889
890 states[1].modTime_sec = 0x93400031;
891 states[1].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700892 states[1].mode = 0666; // decimal 438, hex 0x000001b6
Joe Onorato3ad977b2009-05-05 11:50:51 -0700893 states[1].size = 0x88557766;
894 states[1].crc32 = 0x22334422;
895 states[1].nameLen = -1;
Joe Onorato23ecae32009-06-10 17:07:15 -0700896 r.s = states[1];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700897 filenames[1] = String8("bytes_of_padding3");
Joe Onorato23ecae32009-06-10 17:07:15 -0700898 snapshot.add(filenames[1], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700899
900 states[2].modTime_sec = 0x33221144;
901 states[2].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700902 states[2].mode = 0744; // decimal 484, hex 0x000001e4
Joe Onorato3ad977b2009-05-05 11:50:51 -0700903 states[2].size = 0x11223344;
904 states[2].crc32 = 0x01122334;
905 states[2].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700906 r.s = states[2];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700907 filenames[2] = String8("bytes_of_padding_2");
Joe Onorato23ecae32009-06-10 17:07:15 -0700908 snapshot.add(filenames[2], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700909
910 states[3].modTime_sec = 0x33221144;
911 states[3].modTime_nsec = 0xdeadbeef;
Christopher Tate11b15772009-06-23 13:03:00 -0700912 states[3].mode = 0755; // decimal 493, hex 0x000001ed
Joe Onorato3ad977b2009-05-05 11:50:51 -0700913 states[3].size = 0x11223344;
914 states[3].crc32 = 0x01122334;
915 states[3].nameLen = 0;
Joe Onorato23ecae32009-06-10 17:07:15 -0700916 r.s = states[3];
Joe Onorato3ad977b2009-05-05 11:50:51 -0700917 filenames[3] = String8("bytes_of_padding__1");
Joe Onorato23ecae32009-06-10 17:07:15 -0700918 snapshot.add(filenames[3], r);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700919
920 err = write_snapshot_file(fd, snapshot);
921
922 close(fd);
923
924 if (err != 0) {
925 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
926 return err;
927 }
928
929 static const unsigned char correct_data[] = {
930 // header
931 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
Christopher Tate11b15772009-06-23 13:03:00 -0700932 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00,
Joe Onorato3ad977b2009-05-05 11:50:51 -0700933
934 // bytes_of_padding
935 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -0700936 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab,
937 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00,
938 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
939 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
Joe Onorato3ad977b2009-05-05 11:50:51 -0700940
941 // bytes_of_padding3
942 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -0700943 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88,
944 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00,
945 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
946 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
947 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -0700948
Joe Onorato3ad977b2009-05-05 11:50:51 -0700949 // bytes of padding2
950 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -0700951 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
952 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00,
953 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
954 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
955 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -0700956
Joe Onorato3ad977b2009-05-05 11:50:51 -0700957 // bytes of padding3
958 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
Christopher Tate11b15772009-06-23 13:03:00 -0700959 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
960 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00,
961 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66,
962 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67,
963 0x5f, 0x5f, 0x31, 0xab
Joe Onorato3ad977b2009-05-05 11:50:51 -0700964 };
965
966 err = compare_file(filename, correct_data, sizeof(correct_data));
967 if (err != 0) {
968 return err;
969 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -0700970
Joe Onorato3ad977b2009-05-05 11:50:51 -0700971 // read
972 fd = open(filename, O_RDONLY);
973 if (fd == -1) {
974 fprintf(stderr, "error opening for read %s\n", filename);
975 return 1;
976 }
977
978
979 KeyedVector<String8,FileState> readSnapshot;
980 err = read_snapshot_file(fd, &readSnapshot);
981 if (err != 0) {
982 fprintf(stderr, "read_snapshot_file failed %d\n", err);
983 return err;
984 }
985
986 if (readSnapshot.size() != 4) {
987 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
988 return 1;
989 }
990
991 bool matched = true;
992 for (size_t i=0; i<readSnapshot.size(); i++) {
993 const String8& name = readSnapshot.keyAt(i);
994 const FileState state = readSnapshot.valueAt(i);
995
996 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
Christopher Tate11b15772009-06-23 13:03:00 -0700997 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
Joe Onorato3ad977b2009-05-05 11:50:51 -0700998 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
Christopher Tate11b15772009-06-23 13:03:00 -0700999 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
1000 " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
1001 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
1002 states[i].crc32, name.length(), filenames[i].string(),
1003 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
1004 state.nameLen, name.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -07001005 matched = false;
1006 }
1007 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001008
Joe Onorato3ad977b2009-05-05 11:50:51 -07001009 return matched ? 0 : 1;
1010}
1011
Joe Onorato4535e402009-05-15 09:07:06 -04001012// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
1013const unsigned char DATA_GOLDEN_FILE[] = {
Joe Onorato2e1da322009-05-15 18:20:19 -04001014 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
1015 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
1016 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
1017 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
Joe Onorato5f15d152009-06-16 16:31:35 -04001018 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
1019 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
Joe Onorato4535e402009-05-15 09:07:06 -04001020 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1021 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001022 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
Joe Onorato5f15d152009-06-16 16:31:35 -04001023 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
Joe Onorato2e1da322009-05-15 18:20:19 -04001024 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
1025 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -04001026 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -04001027 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
1028 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato5f15d152009-06-16 16:31:35 -04001029 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
Joe Onorato4535e402009-05-15 09:07:06 -04001030 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
1031 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
1032 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
Joe Onorato5f15d152009-06-16 16:31:35 -04001033 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
1034
Joe Onorato4535e402009-05-15 09:07:06 -04001035};
1036const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
1037
1038static int
1039test_write_header_and_entity(BackupDataWriter& writer, const char* str)
1040{
1041 int err;
1042 String8 text(str);
1043
Joe Onorato4535e402009-05-15 09:07:06 -04001044 err = writer.WriteEntityHeader(text, text.length()+1);
1045 if (err != 0) {
1046 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
1047 return err;
1048 }
1049
1050 err = writer.WriteEntityData(text.string(), text.length()+1);
1051 if (err != 0) {
1052 fprintf(stderr, "write failed for data '%s'\n", text.string());
1053 return errno;
1054 }
1055
1056 return err;
1057}
1058
1059int
1060backup_helper_test_data_writer()
1061{
1062 int err;
1063 int fd;
1064 const char* filename = SCRATCH_DIR "data_writer.data";
1065
1066 system("rm -r " SCRATCH_DIR);
1067 mkdir(SCRATCH_DIR, 0777);
1068 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001069
Joe Onorato4535e402009-05-15 09:07:06 -04001070 fd = creat(filename, 0666);
1071 if (fd == -1) {
1072 fprintf(stderr, "error creating: %s\n", strerror(errno));
1073 return errno;
1074 }
1075
1076 BackupDataWriter writer(fd);
1077
1078 err = 0;
1079 err |= test_write_header_and_entity(writer, "no_padding_");
1080 err |= test_write_header_and_entity(writer, "padded_to__3");
1081 err |= test_write_header_and_entity(writer, "padded_to_2__");
1082 err |= test_write_header_and_entity(writer, "padded_to1");
1083
Joe Onorato4535e402009-05-15 09:07:06 -04001084 close(fd);
1085
1086 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1087 if (err != 0) {
1088 return err;
1089 }
1090
1091 return err;
1092}
1093
Joe Onorato2e1da322009-05-15 18:20:19 -04001094int
1095test_read_header_and_entity(BackupDataReader& reader, const char* str)
1096{
1097 int err;
1098 int bufSize = strlen(str)+1;
1099 char* buf = (char*)malloc(bufSize);
1100 String8 string;
1101 int cookie = 0x11111111;
1102 size_t actualSize;
Joe Onorato5f15d152009-06-16 16:31:35 -04001103 bool done;
1104 int type;
Christopher Tate11b15772009-06-23 13:03:00 -07001105 ssize_t nRead;
Joe Onorato2e1da322009-05-15 18:20:19 -04001106
1107 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
1108
Joe Onorato5f15d152009-06-16 16:31:35 -04001109 err = reader.ReadNextHeader(&done, &type);
1110 if (done) {
1111 fprintf(stderr, "should not be done yet\n");
1112 goto finished;
1113 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001114 if (err != 0) {
1115 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001116 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001117 }
Joe Onorato5f15d152009-06-16 16:31:35 -04001118 if (type != BACKUP_HEADER_ENTITY_V1) {
Joe Onorato2e1da322009-05-15 18:20:19 -04001119 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001120 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
Joe Onorato2e1da322009-05-15 18:20:19 -04001121 }
1122
1123 err = reader.ReadEntityHeader(&string, &actualSize);
1124 if (err != 0) {
1125 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001126 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001127 }
1128 if (string != str) {
1129 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
1130 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001131 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001132 }
1133 if ((int)actualSize != bufSize) {
1134 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
1135 actualSize);
1136 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001137 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001138 }
1139
Christopher Tate11b15772009-06-23 13:03:00 -07001140 nRead = reader.ReadEntityData(buf, bufSize);
1141 if (nRead < 0) {
1142 err = reader.Status();
Joe Onorato2e1da322009-05-15 18:20:19 -04001143 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
Joe Onorato5f15d152009-06-16 16:31:35 -04001144 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001145 }
1146
1147 if (0 != memcmp(buf, str, bufSize)) {
1148 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
Joe Onorato5f15d152009-06-16 16:31:35 -04001149 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
1150 buf[0], buf[1], buf[2], buf[3]);
Joe Onorato2e1da322009-05-15 18:20:19 -04001151 err = EINVAL;
Joe Onorato5f15d152009-06-16 16:31:35 -04001152 goto finished;
Joe Onorato2e1da322009-05-15 18:20:19 -04001153 }
1154
1155 // The next read will confirm whether it got the right amount of data.
1156
Joe Onorato5f15d152009-06-16 16:31:35 -04001157finished:
Joe Onorato2e1da322009-05-15 18:20:19 -04001158 if (err != NO_ERROR) {
1159 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
1160 }
Christopher Tate63bcb792009-06-24 13:57:29 -07001161 free(buf);
Joe Onorato2e1da322009-05-15 18:20:19 -04001162 return err;
1163}
1164
1165int
1166backup_helper_test_data_reader()
1167{
1168 int err;
1169 int fd;
1170 const char* filename = SCRATCH_DIR "data_reader.data";
1171
1172 system("rm -r " SCRATCH_DIR);
1173 mkdir(SCRATCH_DIR, 0777);
1174 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001175
Joe Onorato2e1da322009-05-15 18:20:19 -04001176 fd = creat(filename, 0666);
1177 if (fd == -1) {
1178 fprintf(stderr, "error creating: %s\n", strerror(errno));
1179 return errno;
1180 }
1181
1182 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1183 if (err != DATA_GOLDEN_FILE_SIZE) {
1184 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1185 return errno;
1186 }
1187
1188 close(fd);
1189
1190 fd = open(filename, O_RDONLY);
1191 if (fd == -1) {
1192 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1193 filename);
1194 return errno;
1195 }
1196
1197 {
1198 BackupDataReader reader(fd);
1199
1200 err = 0;
1201
1202 if (err == NO_ERROR) {
1203 err = test_read_header_and_entity(reader, "no_padding_");
1204 }
1205
1206 if (err == NO_ERROR) {
1207 err = test_read_header_and_entity(reader, "padded_to__3");
1208 }
1209
1210 if (err == NO_ERROR) {
1211 err = test_read_header_and_entity(reader, "padded_to_2__");
1212 }
1213
1214 if (err == NO_ERROR) {
1215 err = test_read_header_and_entity(reader, "padded_to1");
1216 }
Joe Onorato2e1da322009-05-15 18:20:19 -04001217 }
1218
1219 close(fd);
1220
1221 return err;
1222}
1223
Joe Onorato3ad977b2009-05-05 11:50:51 -07001224static int
1225get_mod_time(const char* filename, struct timeval times[2])
1226{
1227 int err;
1228 struct stat64 st;
1229 err = stat64(filename, &st);
1230 if (err != 0) {
1231 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1232 return errno;
1233 }
1234 times[0].tv_sec = st.st_atime;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001235 times[1].tv_sec = st.st_mtime;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001236
1237 // If st_atime is a macro then struct stat64 uses struct timespec
1238 // to store the access and modif time values and typically
1239 // st_*time_nsec is not defined. In glibc, this is controlled by
1240 // __USE_MISC.
1241#ifdef __USE_MISC
1242#if !defined(st_atime) || defined(st_atime_nsec)
1243#error "Check if this __USE_MISC conditional is still needed."
1244#endif
1245 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1246 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1247#else
1248 times[0].tv_usec = st.st_atime_nsec / 1000;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001249 times[1].tv_usec = st.st_mtime_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001250#endif
1251
Joe Onorato3ad977b2009-05-05 11:50:51 -07001252 return 0;
1253}
1254
1255int
1256backup_helper_test_files()
1257{
1258 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001259 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -04001260 int dataStreamFD;
1261 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -07001262
1263 system("rm -r " SCRATCH_DIR);
1264 mkdir(SCRATCH_DIR, 0777);
1265 mkdir(SCRATCH_DIR "data", 0777);
1266
1267 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1268 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1269 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1270 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1271 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1272 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1273
1274 char const* files_before[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001275 SCRATCH_DIR "data/b",
1276 SCRATCH_DIR "data/c",
1277 SCRATCH_DIR "data/d",
1278 SCRATCH_DIR "data/e",
1279 SCRATCH_DIR "data/f"
1280 };
1281
1282 char const* keys_before[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001283 "data/b",
1284 "data/c",
1285 "data/d",
1286 "data/e",
1287 "data/f"
1288 };
1289
Joe Onorato4535e402009-05-15 09:07:06 -04001290 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1291 if (dataStreamFD == -1) {
1292 fprintf(stderr, "error creating: %s\n", strerror(errno));
1293 return errno;
1294 }
1295
Joe Onorato3ad977b2009-05-05 11:50:51 -07001296 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1297 if (newSnapshotFD == -1) {
1298 fprintf(stderr, "error creating: %s\n", strerror(errno));
1299 return errno;
1300 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001301
1302 {
1303 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001304
Joe Onorato23ecae32009-06-10 17:07:15 -07001305 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
Joe Onoratod2110db2009-05-19 13:41:21 -07001306 if (err != 0) {
1307 return err;
1308 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001309 }
1310
Joe Onorato4535e402009-05-15 09:07:06 -04001311 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001312 close(newSnapshotFD);
1313
1314 sleep(3);
1315
1316 struct timeval d_times[2];
1317 struct timeval e_times[2];
1318
1319 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1320 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1321 if (err != 0) {
1322 return err;
1323 }
1324
1325 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1326 unlink(SCRATCH_DIR "data/c");
1327 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1328 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1329 utimes(SCRATCH_DIR "data/d", d_times);
1330 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1331 utimes(SCRATCH_DIR "data/e", e_times);
1332 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1333 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001334
Joe Onorato3ad977b2009-05-05 11:50:51 -07001335 char const* files_after[] = {
Joe Onorato23ecae32009-06-10 17:07:15 -07001336 SCRATCH_DIR "data/a", // added
1337 SCRATCH_DIR "data/b", // same
1338 SCRATCH_DIR "data/c", // different mod time
1339 SCRATCH_DIR "data/d", // different size (same mod time)
1340 SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1341 SCRATCH_DIR "data/g" // added
1342 };
1343
1344 char const* keys_after[] = {
Joe Onorato3ad977b2009-05-05 11:50:51 -07001345 "data/a", // added
1346 "data/b", // same
1347 "data/c", // different mod time
1348 "data/d", // different size (same mod time)
1349 "data/e", // different contents (same mod time, same size)
1350 "data/g" // added
1351 };
1352
1353 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1354 if (oldSnapshotFD == -1) {
1355 fprintf(stderr, "error opening: %s\n", strerror(errno));
1356 return errno;
1357 }
1358
Joe Onorato4535e402009-05-15 09:07:06 -04001359 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1360 if (dataStreamFD == -1) {
1361 fprintf(stderr, "error creating: %s\n", strerror(errno));
1362 return errno;
1363 }
1364
Joe Onorato3ad977b2009-05-05 11:50:51 -07001365 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1366 if (newSnapshotFD == -1) {
1367 fprintf(stderr, "error creating: %s\n", strerror(errno));
1368 return errno;
1369 }
1370
Joe Onoratod2110db2009-05-19 13:41:21 -07001371 {
1372 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001373
Joe Onorato23ecae32009-06-10 17:07:15 -07001374 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
Joe Onoratod2110db2009-05-19 13:41:21 -07001375 if (err != 0) {
1376 return err;
1377 }
1378}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001379
1380 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001381 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001382 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001383
Joe Onorato3ad977b2009-05-05 11:50:51 -07001384 return 0;
1385}
1386
Joe Onorato23ecae32009-06-10 17:07:15 -07001387int
1388backup_helper_test_null_base()
1389{
1390 int err;
1391 int oldSnapshotFD;
1392 int dataStreamFD;
1393 int newSnapshotFD;
1394
1395 system("rm -r " SCRATCH_DIR);
1396 mkdir(SCRATCH_DIR, 0777);
1397 mkdir(SCRATCH_DIR "data", 0777);
1398
1399 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1400
1401 char const* files[] = {
1402 SCRATCH_DIR "data/a",
1403 };
1404
1405 char const* keys[] = {
1406 "a",
1407 };
1408
1409 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1410 if (dataStreamFD == -1) {
1411 fprintf(stderr, "error creating: %s\n", strerror(errno));
1412 return errno;
1413 }
1414
1415 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1416 if (newSnapshotFD == -1) {
1417 fprintf(stderr, "error creating: %s\n", strerror(errno));
1418 return errno;
1419 }
1420
1421 {
1422 BackupDataWriter dataStream(dataStreamFD);
1423
1424 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1425 if (err != 0) {
1426 return err;
1427 }
1428 }
1429
1430 close(dataStreamFD);
1431 close(newSnapshotFD);
1432
1433 return 0;
1434}
1435
Joe Onoratoce88cb12009-06-11 11:27:16 -07001436int
1437backup_helper_test_missing_file()
1438{
1439 int err;
1440 int oldSnapshotFD;
1441 int dataStreamFD;
1442 int newSnapshotFD;
1443
1444 system("rm -r " SCRATCH_DIR);
1445 mkdir(SCRATCH_DIR, 0777);
1446 mkdir(SCRATCH_DIR "data", 0777);
1447
1448 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1449
1450 char const* files[] = {
1451 SCRATCH_DIR "data/a",
1452 SCRATCH_DIR "data/b",
1453 SCRATCH_DIR "data/c",
1454 };
1455
1456 char const* keys[] = {
1457 "a",
1458 "b",
1459 "c",
1460 };
1461
1462 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1463 if (dataStreamFD == -1) {
1464 fprintf(stderr, "error creating: %s\n", strerror(errno));
1465 return errno;
1466 }
1467
1468 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1469 if (newSnapshotFD == -1) {
1470 fprintf(stderr, "error creating: %s\n", strerror(errno));
1471 return errno;
1472 }
1473
1474 {
1475 BackupDataWriter dataStream(dataStreamFD);
1476
1477 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1478 if (err != 0) {
1479 return err;
1480 }
1481 }
1482
1483 close(dataStreamFD);
1484 close(newSnapshotFD);
1485
1486 return 0;
1487}
1488
Joe Onorato23ecae32009-06-10 17:07:15 -07001489
Joe Onorato3ad977b2009-05-05 11:50:51 -07001490#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001491
1492}