blob: bf569455df5b35a245f516a0f22535e7672ad027 [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
19#include <utils/backup_helpers.h>
20
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>
29#include <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>
Joe Onoratoc825d3e2009-05-06 12:55:46 -040032#include <utime.h>
Joe Onorato3ad977b2009-05-05 11:50:51 -070033#include <fcntl.h>
34#include <zlib.h>
35
36#include <cutils/log.h>
37
Joe Onorato4535e402009-05-15 09:07:06 -040038namespace android {
Joe Onorato3ad977b2009-05-05 11:50:51 -070039
40#define MAGIC0 0x70616e53 // Snap
41#define MAGIC1 0x656c6946 // File
42
Joe Onorato4535e402009-05-15 09:07:06 -040043#if TEST_BACKUP_HELPERS
44#define LOGP(x...) printf(x)
45#else
Joe Onorato290bb012009-05-13 18:57:29 -040046#define LOGP(x...) LOGD(x)
Joe Onorato4535e402009-05-15 09:07:06 -040047#endif
Joe Onorato290bb012009-05-13 18:57:29 -040048
Joe Onorato3ad977b2009-05-05 11:50:51 -070049struct SnapshotHeader {
50 int magic0;
51 int fileCount;
52 int magic1;
53 int totalSize;
54};
55
56struct FileState {
57 int modTime_sec;
58 int modTime_nsec;
59 int size;
60 int crc32;
61 int nameLen;
62};
63
64const static int ROUND_UP[4] = { 0, 3, 2, 1 };
65
66static inline int
67round_up(int n)
68{
69 return n + ROUND_UP[n % 4];
70}
71
72static int
73read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
74{
75 int bytesRead = 0;
76 int amt;
77 SnapshotHeader header;
78
79 amt = read(fd, &header, sizeof(header));
80 if (amt != sizeof(header)) {
81 return errno;
82 }
83 bytesRead += amt;
84
85 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
86 LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
87 return 1;
88 }
89
90 for (int i=0; i<header.fileCount; i++) {
91 FileState file;
92 char filenameBuf[128];
93
94 amt = read(fd, &file, sizeof(file));
95 if (amt != sizeof(file)) {
96 LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
97 return 1;
98 }
99 bytesRead += amt;
100
101 // filename is not NULL terminated, but it is padded
102 int nameBufSize = round_up(file.nameLen);
103 char* filename = nameBufSize <= (int)sizeof(filenameBuf)
104 ? filenameBuf
105 : (char*)malloc(nameBufSize);
106 amt = read(fd, filename, nameBufSize);
107 if (amt == nameBufSize) {
108 snapshot->add(String8(filename, file.nameLen), file);
109 }
110 bytesRead += amt;
111 if (filename != filenameBuf) {
112 free(filename);
113 }
114 if (amt != nameBufSize) {
115 LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
116 return 1;
117 }
118 }
119
120 if (header.totalSize != bytesRead) {
121 LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
122 header.totalSize, bytesRead);
123 return 1;
124 }
125
126 return 0;
127}
128
129static int
130write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot)
131{
132 int bytesWritten = sizeof(SnapshotHeader);
133 // preflight size
134 const int N = snapshot.size();
135 for (int i=0; i<N; i++) {
136 const String8& name = snapshot.keyAt(i);
137 bytesWritten += sizeof(FileState) + round_up(name.length());
138 }
139
Joe Onorato4535e402009-05-15 09:07:06 -0400140 LOGP("write_snapshot_file fd=%d\n", fd);
141
Joe Onorato3ad977b2009-05-05 11:50:51 -0700142 int amt;
143 SnapshotHeader header = { MAGIC0, N, MAGIC1, bytesWritten };
144
145 amt = write(fd, &header, sizeof(header));
146 if (amt != sizeof(header)) {
147 LOGW("write_snapshot_file error writing header %s", strerror(errno));
148 return errno;
149 }
150
151 for (int i=0; i<header.fileCount; i++) {
152 const String8& name = snapshot.keyAt(i);
153 FileState file = snapshot.valueAt(i);
154 int nameLen = file.nameLen = name.length();
155
156 amt = write(fd, &file, sizeof(file));
157 if (amt != sizeof(file)) {
158 LOGW("write_snapshot_file error writing header %s", strerror(errno));
159 return 1;
160 }
161
162 // filename is not NULL terminated, but it is padded
163 amt = write(fd, name.string(), nameLen);
164 if (amt != nameLen) {
165 LOGW("write_snapshot_file error writing filename %s", strerror(errno));
166 return 1;
167 }
168 int paddingLen = ROUND_UP[nameLen % 4];
169 if (paddingLen != 0) {
170 int padding = 0xabababab;
171 amt = write(fd, &padding, paddingLen);
172 if (amt != paddingLen) {
173 LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
174 paddingLen, strerror(errno));
175 return 1;
176 }
177 }
178 }
179
180 return 0;
181}
182
183static int
184write_delete_file(const String8& key)
185{
Joe Onorato290bb012009-05-13 18:57:29 -0400186 LOGP("write_delete_file %s\n", key.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700187 return 0;
188}
189
190static int
191write_update_file(const String8& realFilename, const String8& key)
192{
Joe Onorato290bb012009-05-13 18:57:29 -0400193 LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700194 return 0;
195}
196
197static int
198compute_crc32(const String8& filename)
199{
200 const int bufsize = 4*1024;
201 int amt;
202
203 int fd = open(filename.string(), O_RDONLY);
204 if (fd == -1) {
205 return -1;
206 }
207
208 char* buf = (char*)malloc(bufsize);
209 int crc = crc32(0L, Z_NULL, 0);
210
211 while ((amt = read(fd, buf, bufsize)) != 0) {
212 crc = crc32(crc, (Bytef*)buf, amt);
213 }
214
215 close(fd);
216 free(buf);
217
218 return crc;
219}
220
221int
Joe Onorato290bb012009-05-13 18:57:29 -0400222back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD,
Joe Onorato3ad977b2009-05-05 11:50:51 -0700223 char const* fileBase, char const* const* files, int fileCount)
224{
225 int err;
226 const String8 base(fileBase);
227 KeyedVector<String8,FileState> oldSnapshot;
228 KeyedVector<String8,FileState> newSnapshot;
229
230 if (oldSnapshotFD != -1) {
231 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
232 if (err != 0) {
233 // On an error, treat this as a full backup.
234 oldSnapshot.clear();
235 }
236 }
237
238 for (int i=0; i<fileCount; i++) {
239 String8 name(files[i]);
240 FileState s;
241 struct stat st;
242 String8 realFilename(base);
243 realFilename.appendPath(name);
244
245 err = stat(realFilename.string(), &st);
246 if (err != 0) {
247 LOGW("Error stating file %s", realFilename.string());
248 continue;
249 }
250
251 s.modTime_sec = st.st_mtime;
Joe Onoratoc825d3e2009-05-06 12:55:46 -0400252 s.modTime_nsec = 0; // workaround sim breakage
253 //s.modTime_nsec = st.st_mtime_nsec;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700254 s.size = st.st_size;
255 s.crc32 = compute_crc32(realFilename);
256
257 newSnapshot.add(name, s);
258 }
259
260 int n = 0;
261 int N = oldSnapshot.size();
262 int m = 0;
263
264 while (n<N && m<fileCount) {
265 const String8& p = oldSnapshot.keyAt(n);
266 const String8& q = newSnapshot.keyAt(m);
267 int cmp = p.compare(q);
268 if (cmp > 0) {
269 // file added
270 String8 realFilename(base);
271 realFilename.appendPath(q);
Joe Onorato4535e402009-05-15 09:07:06 -0400272 LOGP("file added: %s\n", realFilename.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700273 write_update_file(realFilename, q);
274 m++;
275 }
276 else if (cmp < 0) {
277 // file removed
Joe Onorato4535e402009-05-15 09:07:06 -0400278 LOGP("file removed: %s\n", p.string());
Joe Onorato3ad977b2009-05-05 11:50:51 -0700279 write_delete_file(p);
280 n++;
281 }
282 else {
283 // both files exist, check them
284 String8 realFilename(base);
285 realFilename.appendPath(q);
286 const FileState& f = oldSnapshot.valueAt(n);
287 const FileState& g = newSnapshot.valueAt(m);
288
Joe Onorato290bb012009-05-13 18:57:29 -0400289 LOGP("%s\n", q.string());
290 LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n",
Joe Onorato3ad977b2009-05-05 11:50:51 -0700291 f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
Joe Onorato290bb012009-05-13 18:57:29 -0400292 LOGP(" old: modTime=%d,%d size=%-3d crc32=0x%08x\n",
Joe Onorato3ad977b2009-05-05 11:50:51 -0700293 g.modTime_sec, g.modTime_nsec, g.size, g.crc32);
294 if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec
295 || f.size != g.size || f.crc32 != g.crc32) {
296 write_update_file(realFilename, p);
297 }
298 n++;
299 m++;
300 }
301 }
302
303 // these were deleted
304 while (n<N) {
305 write_delete_file(oldSnapshot.keyAt(n));
306 n++;
307 }
308
309 // these were added
310 while (m<fileCount) {
311 const String8& q = newSnapshot.keyAt(m);
312 String8 realFilename(base);
313 realFilename.appendPath(q);
314 write_update_file(realFilename, q);
315 m++;
316 }
317
318 err = write_snapshot_file(newSnapshotFD, newSnapshot);
319
320 return 0;
321}
322
323#if TEST_BACKUP_HELPERS
324
325#define SCRATCH_DIR "/data/backup_helper_test/"
326
327static int
328write_text_file(const char* path, const char* data)
329{
330 int amt;
331 int fd;
332 int len;
333
334 fd = creat(path, 0666);
335 if (fd == -1) {
336 fprintf(stderr, "creat %s failed\n", path);
337 return errno;
338 }
339
340 len = strlen(data);
341 amt = write(fd, data, len);
342 if (amt != len) {
343 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
344 return errno;
345 }
346
347 close(fd);
348
349 return 0;
350}
351
352static int
353compare_file(const char* path, const unsigned char* data, int len)
354{
355 int fd;
356 int amt;
357
358 fd = open(path, O_RDONLY);
359 if (fd == -1) {
360 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
361 return errno;
362 }
363
364 unsigned char* contents = (unsigned char*)malloc(len);
365 if (contents == NULL) {
366 fprintf(stderr, "malloc(%d) failed\n", len);
367 return ENOMEM;
368 }
369
370 bool sizesMatch = true;
371 amt = lseek(fd, 0, SEEK_END);
372 if (amt != len) {
373 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
374 sizesMatch = false;
375 }
376 lseek(fd, 0, SEEK_SET);
377
378 int readLen = amt < len ? amt : len;
379 amt = read(fd, contents, readLen);
380 if (amt != readLen) {
381 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
382 }
383
384 bool contentsMatch = true;
385 for (int i=0; i<readLen; i++) {
386 if (data[i] != contents[i]) {
387 if (contentsMatch) {
388 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
389 contentsMatch = false;
390 }
391 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
392 }
393 }
394
395 return contentsMatch && sizesMatch ? 0 : 1;
396}
397
398int
399backup_helper_test_empty()
400{
401 int err;
402 int fd;
403 KeyedVector<String8,FileState> snapshot;
404 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
405
406 system("rm -r " SCRATCH_DIR);
407 mkdir(SCRATCH_DIR, 0777);
408
409 // write
410 fd = creat(filename, 0666);
411 if (fd == -1) {
412 fprintf(stderr, "error creating %s\n", filename);
413 return 1;
414 }
415
416 err = write_snapshot_file(fd, snapshot);
417
418 close(fd);
419
420 if (err != 0) {
421 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
422 return err;
423 }
424
425 static const unsigned char correct_data[] = {
426 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
427 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
428 };
429
430 err = compare_file(filename, correct_data, sizeof(correct_data));
431 if (err != 0) {
432 return err;
433 }
434
435 // read
436 fd = open(filename, O_RDONLY);
437 if (fd == -1) {
438 fprintf(stderr, "error opening for read %s\n", filename);
439 return 1;
440 }
441
442 KeyedVector<String8,FileState> readSnapshot;
443 err = read_snapshot_file(fd, &readSnapshot);
444 if (err != 0) {
445 fprintf(stderr, "read_snapshot_file failed %d\n", err);
446 return err;
447 }
448
449 if (readSnapshot.size() != 0) {
450 fprintf(stderr, "readSnapshot should be length 0\n");
451 return 1;
452 }
453
454 return 0;
455}
456
457int
458backup_helper_test_four()
459{
460 int err;
461 int fd;
462 KeyedVector<String8,FileState> snapshot;
463 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
464
465 system("rm -r " SCRATCH_DIR);
466 mkdir(SCRATCH_DIR, 0777);
467
468 // write
469 fd = creat(filename, 0666);
470 if (fd == -1) {
471 fprintf(stderr, "error opening %s\n", filename);
472 return 1;
473 }
474
475 String8 filenames[4];
476 FileState states[4];
477
478 states[0].modTime_sec = 0xfedcba98;
479 states[0].modTime_nsec = 0xdeadbeef;
480 states[0].size = 0xababbcbc;
481 states[0].crc32 = 0x12345678;
482 states[0].nameLen = -12;
483 filenames[0] = String8("bytes_of_padding");
484 snapshot.add(filenames[0], states[0]);
485
486 states[1].modTime_sec = 0x93400031;
487 states[1].modTime_nsec = 0xdeadbeef;
488 states[1].size = 0x88557766;
489 states[1].crc32 = 0x22334422;
490 states[1].nameLen = -1;
491 filenames[1] = String8("bytes_of_padding3");
492 snapshot.add(filenames[1], states[1]);
493
494 states[2].modTime_sec = 0x33221144;
495 states[2].modTime_nsec = 0xdeadbeef;
496 states[2].size = 0x11223344;
497 states[2].crc32 = 0x01122334;
498 states[2].nameLen = 0;
499 filenames[2] = String8("bytes_of_padding_2");
500 snapshot.add(filenames[2], states[2]);
501
502 states[3].modTime_sec = 0x33221144;
503 states[3].modTime_nsec = 0xdeadbeef;
504 states[3].size = 0x11223344;
505 states[3].crc32 = 0x01122334;
506 states[3].nameLen = 0;
507 filenames[3] = String8("bytes_of_padding__1");
508 snapshot.add(filenames[3], states[3]);
509
510 err = write_snapshot_file(fd, snapshot);
511
512 close(fd);
513
514 if (err != 0) {
515 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
516 return err;
517 }
518
519 static const unsigned char correct_data[] = {
520 // header
521 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
522 0x46, 0x69, 0x6c, 0x65, 0xac, 0x00, 0x00, 0x00,
523
524 // bytes_of_padding
525 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
526 0xbc, 0xbc, 0xab, 0xab, 0x78, 0x56, 0x34, 0x12,
527 0x10, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
528 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
529 0x64, 0x69, 0x6e, 0x67,
530
531 // bytes_of_padding3
532 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
533 0x66, 0x77, 0x55, 0x88, 0x22, 0x44, 0x33, 0x22,
534 0x11, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
535 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
536 0x64, 0x69, 0x6e, 0x67, 0x33, 0xab, 0xab, 0xab,
537
538 // bytes of padding2
539 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
540 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01,
541 0x12, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
542 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
543 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x32, 0xab, 0xab,
544
545 // bytes of padding3
546 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
547 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01,
548 0x13, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
549 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
550 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x5f, 0x31, 0xab
551 };
552
553 err = compare_file(filename, correct_data, sizeof(correct_data));
554 if (err != 0) {
555 return err;
556 }
557
558 // read
559 fd = open(filename, O_RDONLY);
560 if (fd == -1) {
561 fprintf(stderr, "error opening for read %s\n", filename);
562 return 1;
563 }
564
565
566 KeyedVector<String8,FileState> readSnapshot;
567 err = read_snapshot_file(fd, &readSnapshot);
568 if (err != 0) {
569 fprintf(stderr, "read_snapshot_file failed %d\n", err);
570 return err;
571 }
572
573 if (readSnapshot.size() != 4) {
574 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
575 return 1;
576 }
577
578 bool matched = true;
579 for (size_t i=0; i<readSnapshot.size(); i++) {
580 const String8& name = readSnapshot.keyAt(i);
581 const FileState state = readSnapshot.valueAt(i);
582
583 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
584 || states[i].modTime_nsec != state.modTime_nsec
585 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
586 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n"
587 " actual={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n", i,
588 states[i].modTime_sec, states[i].modTime_nsec, states[i].size, states[i].crc32,
589 name.length(), filenames[i].string(),
590 state.modTime_sec, state.modTime_nsec, state.size, state.crc32, state.nameLen,
591 name.string());
592 matched = false;
593 }
594 }
595
596 return matched ? 0 : 1;
597}
598
Joe Onorato4535e402009-05-15 09:07:06 -0400599// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
600const unsigned char DATA_GOLDEN_FILE[] = {
601 0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00,
Joe Onorato2e1da322009-05-15 18:20:19 -0400602 0xdd, 0xcc, 0xbb, 0xaa, 0x6e, 0x6f, 0x5f, 0x70,
Joe Onorato4535e402009-05-15 09:07:06 -0400603 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
Joe Onorato2e1da322009-05-15 18:20:19 -0400604 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
605 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
606 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
607 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
608 0x6e, 0x67, 0x5f, 0x00, 0x41, 0x70, 0x70, 0x31,
609 0x0c, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
Joe Onorato4535e402009-05-15 09:07:06 -0400610 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
611 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
612 0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00,
613 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
614 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
615 0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
616 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
617 0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
Joe Onorato2e1da322009-05-15 18:20:19 -0400618 0x0d, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
619 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
620 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
621 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
622 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -0400623 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -0400624 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
625 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
626 0x5f, 0x00, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
627 0x0a, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
Joe Onorato4535e402009-05-15 09:07:06 -0400628 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
629 0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61,
630 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
631 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
632 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
633 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc,
634 0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00,
Joe Onorato2e1da322009-05-15 18:20:19 -0400635 0x99, 0x99, 0x77, 0x77
Joe Onorato4535e402009-05-15 09:07:06 -0400636};
637const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
638
639static int
640test_write_header_and_entity(BackupDataWriter& writer, const char* str)
641{
642 int err;
643 String8 text(str);
644
Joe Onorato2e1da322009-05-15 18:20:19 -0400645 err = writer.WriteAppHeader(text, 0xaabbccdd);
Joe Onorato4535e402009-05-15 09:07:06 -0400646 if (err != 0) {
647 fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err));
648 return err;
649 }
650
651 err = writer.WriteEntityHeader(text, text.length()+1);
652 if (err != 0) {
653 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
654 return err;
655 }
656
657 err = writer.WriteEntityData(text.string(), text.length()+1);
658 if (err != 0) {
659 fprintf(stderr, "write failed for data '%s'\n", text.string());
660 return errno;
661 }
662
663 return err;
664}
665
666int
667backup_helper_test_data_writer()
668{
669 int err;
670 int fd;
671 const char* filename = SCRATCH_DIR "data_writer.data";
672
673 system("rm -r " SCRATCH_DIR);
674 mkdir(SCRATCH_DIR, 0777);
675 mkdir(SCRATCH_DIR "data", 0777);
676
677 fd = creat(filename, 0666);
678 if (fd == -1) {
679 fprintf(stderr, "error creating: %s\n", strerror(errno));
680 return errno;
681 }
682
683 BackupDataWriter writer(fd);
684
685 err = 0;
686 err |= test_write_header_and_entity(writer, "no_padding_");
687 err |= test_write_header_and_entity(writer, "padded_to__3");
688 err |= test_write_header_and_entity(writer, "padded_to_2__");
689 err |= test_write_header_and_entity(writer, "padded_to1");
690
Joe Onorato2e1da322009-05-15 18:20:19 -0400691 writer.WriteAppFooter(0x77779999);
Joe Onorato4535e402009-05-15 09:07:06 -0400692
693 close(fd);
694
695 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
696 if (err != 0) {
697 return err;
698 }
699
700 return err;
701}
702
Joe Onorato2e1da322009-05-15 18:20:19 -0400703int
704test_read_header_and_entity(BackupDataReader& reader, const char* str)
705{
706 int err;
707 int bufSize = strlen(str)+1;
708 char* buf = (char*)malloc(bufSize);
709 String8 string;
710 int cookie = 0x11111111;
711 size_t actualSize;
712
713 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
714
715 err = reader.ReadNextHeader();
716 if (err != 0) {
717 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
718 goto done;
719 }
720
721 err = reader.ReadAppHeader(&string, &cookie);
722 if (err != 0) {
723 fprintf(stderr, "ReadAppHeader failed with %s\n", strerror(err));
724 goto done;
725 }
726 if (string != str) {
727 fprintf(stderr, "ReadAppHeader expected packageName '%s' got '%s'\n", str, string.string());
728 err = EINVAL;
729 goto done;
730 }
731 if (cookie != (int)0xaabbccdd) {
732 fprintf(stderr, "ReadAppHeader expected cookie 0x%08x got 0x%08x\n", 0xaabbccdd, cookie);
733 err = EINVAL;
734 goto done;
735 }
736
737 err = reader.ReadNextHeader();
738 if (err != 0) {
739 fprintf(stderr, "ReadNextHeader (for entity header) failed with %s\n", strerror(err));
740 goto done;
741 }
742
743 err = reader.ReadEntityHeader(&string, &actualSize);
744 if (err != 0) {
745 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
746 goto done;
747 }
748 if (string != str) {
749 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
750 err = EINVAL;
751 goto done;
752 }
753 if ((int)actualSize != bufSize) {
754 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
755 actualSize);
756 err = EINVAL;
757 goto done;
758 }
759
760 err = reader.ReadEntityData(buf, bufSize);
761 if (err != NO_ERROR) {
762 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
763 goto done;
764 }
765
766 if (0 != memcmp(buf, str, bufSize)) {
767 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
768 "%02x %02x %02x %02x\n", str, buf[0], buf[1], buf[2], buf[3]);
769 err = EINVAL;
770 goto done;
771 }
772
773 // The next read will confirm whether it got the right amount of data.
774
775done:
776 if (err != NO_ERROR) {
777 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
778 }
779 free(buf);
780 return err;
781}
782
783int
784backup_helper_test_data_reader()
785{
786 int err;
787 int fd;
788 const char* filename = SCRATCH_DIR "data_reader.data";
789
790 system("rm -r " SCRATCH_DIR);
791 mkdir(SCRATCH_DIR, 0777);
792 mkdir(SCRATCH_DIR "data", 0777);
793
794 fd = creat(filename, 0666);
795 if (fd == -1) {
796 fprintf(stderr, "error creating: %s\n", strerror(errno));
797 return errno;
798 }
799
800 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
801 if (err != DATA_GOLDEN_FILE_SIZE) {
802 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
803 return errno;
804 }
805
806 close(fd);
807
808 fd = open(filename, O_RDONLY);
809 if (fd == -1) {
810 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
811 filename);
812 return errno;
813 }
814
815 {
816 BackupDataReader reader(fd);
817
818 err = 0;
819
820 if (err == NO_ERROR) {
821 err = test_read_header_and_entity(reader, "no_padding_");
822 }
823
824 if (err == NO_ERROR) {
825 err = test_read_header_and_entity(reader, "padded_to__3");
826 }
827
828 if (err == NO_ERROR) {
829 err = test_read_header_and_entity(reader, "padded_to_2__");
830 }
831
832 if (err == NO_ERROR) {
833 err = test_read_header_and_entity(reader, "padded_to1");
834 }
835
836 if (err == NO_ERROR) {
837 err = reader.ReadNextHeader();
838 if (err != 0) {
839 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
840 }
841
842 if (err == NO_ERROR) {
843 int cookie;
844 err |= reader.ReadAppFooter(&cookie);
845 if (cookie != 0x77779999) {
846 fprintf(stderr, "app footer cookie expected=0x%08x actual=0x%08x\n",
847 0x77779999, cookie);
848 err = EINVAL;
849 }
850 }
851 }
852 }
853
854 close(fd);
855
856 return err;
857}
858
Joe Onorato3ad977b2009-05-05 11:50:51 -0700859static int
860get_mod_time(const char* filename, struct timeval times[2])
861{
862 int err;
863 struct stat64 st;
864 err = stat64(filename, &st);
865 if (err != 0) {
866 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
867 return errno;
868 }
869 times[0].tv_sec = st.st_atime;
870 times[0].tv_usec = st.st_atime_nsec / 1000;
871 times[1].tv_sec = st.st_mtime;
872 times[1].tv_usec = st.st_mtime_nsec / 1000;
873 return 0;
874}
875
876int
877backup_helper_test_files()
878{
879 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700880 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -0400881 int dataStreamFD;
882 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700883
884 system("rm -r " SCRATCH_DIR);
885 mkdir(SCRATCH_DIR, 0777);
886 mkdir(SCRATCH_DIR "data", 0777);
887
888 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
889 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
890 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
891 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
892 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
893 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
894
895 char const* files_before[] = {
896 "data/b",
897 "data/c",
898 "data/d",
899 "data/e",
900 "data/f"
901 };
902
Joe Onorato4535e402009-05-15 09:07:06 -0400903 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
904 if (dataStreamFD == -1) {
905 fprintf(stderr, "error creating: %s\n", strerror(errno));
906 return errno;
907 }
908
Joe Onorato3ad977b2009-05-05 11:50:51 -0700909 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
910 if (newSnapshotFD == -1) {
911 fprintf(stderr, "error creating: %s\n", strerror(errno));
912 return errno;
913 }
Joe Onorato4535e402009-05-15 09:07:06 -0400914
915 err = back_up_files(-1, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_before, 5);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700916 if (err != 0) {
917 return err;
918 }
919
Joe Onorato4535e402009-05-15 09:07:06 -0400920 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700921 close(newSnapshotFD);
922
923 sleep(3);
924
925 struct timeval d_times[2];
926 struct timeval e_times[2];
927
928 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
929 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
930 if (err != 0) {
931 return err;
932 }
933
934 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
935 unlink(SCRATCH_DIR "data/c");
936 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
937 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
938 utimes(SCRATCH_DIR "data/d", d_times);
939 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
940 utimes(SCRATCH_DIR "data/e", e_times);
941 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
942 unlink(SCRATCH_DIR "data/f");
943
944 char const* files_after[] = {
945 "data/a", // added
946 "data/b", // same
947 "data/c", // different mod time
948 "data/d", // different size (same mod time)
949 "data/e", // different contents (same mod time, same size)
950 "data/g" // added
951 };
952
953 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
954 if (oldSnapshotFD == -1) {
955 fprintf(stderr, "error opening: %s\n", strerror(errno));
956 return errno;
957 }
958
Joe Onorato4535e402009-05-15 09:07:06 -0400959 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
960 if (dataStreamFD == -1) {
961 fprintf(stderr, "error creating: %s\n", strerror(errno));
962 return errno;
963 }
964
Joe Onorato3ad977b2009-05-05 11:50:51 -0700965 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
966 if (newSnapshotFD == -1) {
967 fprintf(stderr, "error creating: %s\n", strerror(errno));
968 return errno;
969 }
970
Joe Onorato4535e402009-05-15 09:07:06 -0400971 err = back_up_files(oldSnapshotFD, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_after, 6);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700972 if (err != 0) {
973 return err;
974 }
975
976 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -0400977 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700978 close(newSnapshotFD);
979
980 return 0;
981}
982
983#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -0400984
985}