blob: 8efb3eb8b74dc8204abe472da35bb318522c852c [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 Onorato0c4863b2009-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 Onorato2a98fb92009-05-06 12:55:46 -040032#include <utime.h>
Joe Onorato0c4863b2009-05-05 11:50:51 -070033#include <fcntl.h>
34#include <zlib.h>
35
36#include <cutils/log.h>
37
Joe Onorato8d626d62009-05-15 09:07:06 -040038namespace android {
Joe Onorato0c4863b2009-05-05 11:50:51 -070039
40#define MAGIC0 0x70616e53 // Snap
41#define MAGIC1 0x656c6946 // File
42
Joe Onorato473b6e22009-05-19 13:41:21 -070043#if 0 // TEST_BACKUP_HELPERS
Joe Onorato8d626d62009-05-15 09:07:06 -040044#define LOGP(x...) printf(x)
45#else
Joe Onoratoc7bbc692009-05-13 18:57:29 -040046#define LOGP(x...) LOGD(x)
Joe Onorato8d626d62009-05-15 09:07:06 -040047#endif
Joe Onoratoc7bbc692009-05-13 18:57:29 -040048
Joe Onorato0c4863b2009-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 Onorato8d626d62009-05-15 09:07:06 -0400140 LOGP("write_snapshot_file fd=%d\n", fd);
141
Joe Onorato0c4863b2009-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
Joe Onorato473b6e22009-05-19 13:41:21 -0700184write_delete_file(BackupDataWriter* dataStream, const String8& key)
Joe Onorato0c4863b2009-05-05 11:50:51 -0700185{
Joe Onoratoc7bbc692009-05-13 18:57:29 -0400186 LOGP("write_delete_file %s\n", key.string());
Joe Onorato473b6e22009-05-19 13:41:21 -0700187 return dataStream->WriteEntityHeader(key, -1);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700188}
189
190static int
Joe Onorato473b6e22009-05-19 13:41:21 -0700191write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
192 const String8& realFilename)
Joe Onorato0c4863b2009-05-05 11:50:51 -0700193{
Joe Onoratoc7bbc692009-05-13 18:57:29 -0400194 LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string());
Joe Onorato473b6e22009-05-19 13:41:21 -0700195
196 const int bufsize = 4*1024;
197 int err;
198 int amt;
199 int fileSize;
200 int bytesLeft;
201
202 char* buf = (char*)malloc(bufsize);
203 int crc = crc32(0L, Z_NULL, 0);
204
205
206 bytesLeft = fileSize = lseek(fd, 0, SEEK_END);
207 lseek(fd, 0, SEEK_SET);
208
209 err = dataStream->WriteEntityHeader(key, bytesLeft);
210 if (err != 0) {
211 return err;
212 }
213
214 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
215 bytesLeft -= amt;
216 if (bytesLeft < 0) {
217 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised.
218 }
219 err = dataStream->WriteEntityData(buf, amt);
220 if (err != 0) {
221 return err;
222 }
223 }
224 if (bytesLeft != 0) {
225 if (bytesLeft > 0) {
226 // Pad out the space we promised in the buffer. We can't corrupt the buffer,
227 // even though the data we're sending is probably bad.
228 memset(buf, 0, bufsize);
229 while (bytesLeft > 0) {
230 amt = bytesLeft < bufsize ? bytesLeft : bufsize;
231 bytesLeft -= amt;
232 err = dataStream->WriteEntityData(buf, amt);
233 if (err != 0) {
234 return err;
235 }
236 }
237 }
238 LOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
239 " You aren't doing proper locking!",
240 realFilename.string(), fileSize, fileSize-bytesLeft);
241 }
242
243 free(buf);
244
245 return NO_ERROR;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700246}
247
248static int
Joe Onorato473b6e22009-05-19 13:41:21 -0700249write_update_file(BackupDataWriter* dataStream, const String8& key, const String8& realFilename)
250{
251 int err;
252 int fd = open(realFilename.string(), O_RDONLY);
253 if (fd == -1) {
254 return errno;
255 }
256 err = write_update_file(dataStream, fd, key, realFilename);
257 close(fd);
258 return err;
259}
260
261static int
262compute_crc32(int fd)
Joe Onorato0c4863b2009-05-05 11:50:51 -0700263{
264 const int bufsize = 4*1024;
265 int amt;
266
Joe Onorato0c4863b2009-05-05 11:50:51 -0700267 char* buf = (char*)malloc(bufsize);
268 int crc = crc32(0L, Z_NULL, 0);
269
Joe Onorato473b6e22009-05-19 13:41:21 -0700270 lseek(fd, 0, SEEK_SET);
271
Joe Onorato0c4863b2009-05-05 11:50:51 -0700272 while ((amt = read(fd, buf, bufsize)) != 0) {
273 crc = crc32(crc, (Bytef*)buf, amt);
274 }
275
Joe Onorato0c4863b2009-05-05 11:50:51 -0700276 free(buf);
277
278 return crc;
279}
280
281int
Joe Onorato473b6e22009-05-19 13:41:21 -0700282back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato0c4863b2009-05-05 11:50:51 -0700283 char const* fileBase, char const* const* files, int fileCount)
284{
285 int err;
286 const String8 base(fileBase);
287 KeyedVector<String8,FileState> oldSnapshot;
288 KeyedVector<String8,FileState> newSnapshot;
289
290 if (oldSnapshotFD != -1) {
291 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
292 if (err != 0) {
293 // On an error, treat this as a full backup.
294 oldSnapshot.clear();
295 }
296 }
297
298 for (int i=0; i<fileCount; i++) {
299 String8 name(files[i]);
300 FileState s;
301 struct stat st;
302 String8 realFilename(base);
303 realFilename.appendPath(name);
304
305 err = stat(realFilename.string(), &st);
306 if (err != 0) {
307 LOGW("Error stating file %s", realFilename.string());
308 continue;
309 }
310
311 s.modTime_sec = st.st_mtime;
Joe Onorato2a98fb92009-05-06 12:55:46 -0400312 s.modTime_nsec = 0; // workaround sim breakage
313 //s.modTime_nsec = st.st_mtime_nsec;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700314 s.size = st.st_size;
Joe Onorato473b6e22009-05-19 13:41:21 -0700315
316 // we compute the crc32 later down below, when we already have the file open.
Joe Onorato0c4863b2009-05-05 11:50:51 -0700317
318 newSnapshot.add(name, s);
319 }
320
321 int n = 0;
322 int N = oldSnapshot.size();
323 int m = 0;
324
325 while (n<N && m<fileCount) {
326 const String8& p = oldSnapshot.keyAt(n);
327 const String8& q = newSnapshot.keyAt(m);
328 int cmp = p.compare(q);
329 if (cmp > 0) {
330 // file added
331 String8 realFilename(base);
332 realFilename.appendPath(q);
Joe Onorato8d626d62009-05-15 09:07:06 -0400333 LOGP("file added: %s\n", realFilename.string());
Joe Onorato473b6e22009-05-19 13:41:21 -0700334 write_update_file(dataStream, q, realFilename);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700335 m++;
336 }
337 else if (cmp < 0) {
338 // file removed
Joe Onorato8d626d62009-05-15 09:07:06 -0400339 LOGP("file removed: %s\n", p.string());
Joe Onorato473b6e22009-05-19 13:41:21 -0700340 dataStream->WriteEntityHeader(p, -1);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700341 n++;
342 }
343 else {
Joe Onorato473b6e22009-05-19 13:41:21 -0700344
Joe Onorato0c4863b2009-05-05 11:50:51 -0700345 // both files exist, check them
346 String8 realFilename(base);
347 realFilename.appendPath(q);
348 const FileState& f = oldSnapshot.valueAt(n);
Joe Onorato473b6e22009-05-19 13:41:21 -0700349 FileState& g = newSnapshot.editValueAt(m);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700350
Joe Onorato473b6e22009-05-19 13:41:21 -0700351 int fd = open(realFilename.string(), O_RDONLY);
352 if (fd != -1) {
353 // We can't open the file. Don't report it as a delete either. Let the
354 // server keep the old version. Maybe they'll be able to deal with it
355 // on restore.
356 } else {
357 g.crc32 = compute_crc32(fd);
358
359 LOGP("%s\n", q.string());
360 LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n",
361 f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
362 LOGP(" old: modTime=%d,%d size=%-3d crc32=0x%08x\n",
363 g.modTime_sec, g.modTime_nsec, g.size, g.crc32);
364 if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec
365 || f.size != g.size || f.crc32 != g.crc32) {
366 write_update_file(dataStream, fd, p, realFilename);
367 }
368
369 close(fd);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700370 }
371 n++;
372 m++;
373 }
374 }
375
376 // these were deleted
377 while (n<N) {
Joe Onorato473b6e22009-05-19 13:41:21 -0700378 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700379 n++;
380 }
381
382 // these were added
383 while (m<fileCount) {
384 const String8& q = newSnapshot.keyAt(m);
385 String8 realFilename(base);
386 realFilename.appendPath(q);
Joe Onorato473b6e22009-05-19 13:41:21 -0700387 write_update_file(dataStream, q, realFilename);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700388 m++;
389 }
390
391 err = write_snapshot_file(newSnapshotFD, newSnapshot);
392
393 return 0;
394}
395
396#if TEST_BACKUP_HELPERS
397
398#define SCRATCH_DIR "/data/backup_helper_test/"
399
400static int
401write_text_file(const char* path, const char* data)
402{
403 int amt;
404 int fd;
405 int len;
406
407 fd = creat(path, 0666);
408 if (fd == -1) {
409 fprintf(stderr, "creat %s failed\n", path);
410 return errno;
411 }
412
413 len = strlen(data);
414 amt = write(fd, data, len);
415 if (amt != len) {
416 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
417 return errno;
418 }
419
420 close(fd);
421
422 return 0;
423}
424
425static int
426compare_file(const char* path, const unsigned char* data, int len)
427{
428 int fd;
429 int amt;
430
431 fd = open(path, O_RDONLY);
432 if (fd == -1) {
433 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
434 return errno;
435 }
436
437 unsigned char* contents = (unsigned char*)malloc(len);
438 if (contents == NULL) {
439 fprintf(stderr, "malloc(%d) failed\n", len);
440 return ENOMEM;
441 }
442
443 bool sizesMatch = true;
444 amt = lseek(fd, 0, SEEK_END);
445 if (amt != len) {
446 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
447 sizesMatch = false;
448 }
449 lseek(fd, 0, SEEK_SET);
450
451 int readLen = amt < len ? amt : len;
452 amt = read(fd, contents, readLen);
453 if (amt != readLen) {
454 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
455 }
456
457 bool contentsMatch = true;
458 for (int i=0; i<readLen; i++) {
459 if (data[i] != contents[i]) {
460 if (contentsMatch) {
461 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
462 contentsMatch = false;
463 }
464 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
465 }
466 }
467
468 return contentsMatch && sizesMatch ? 0 : 1;
469}
470
471int
472backup_helper_test_empty()
473{
474 int err;
475 int fd;
476 KeyedVector<String8,FileState> snapshot;
477 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
478
479 system("rm -r " SCRATCH_DIR);
480 mkdir(SCRATCH_DIR, 0777);
481
482 // write
483 fd = creat(filename, 0666);
484 if (fd == -1) {
485 fprintf(stderr, "error creating %s\n", filename);
486 return 1;
487 }
488
489 err = write_snapshot_file(fd, snapshot);
490
491 close(fd);
492
493 if (err != 0) {
494 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
495 return err;
496 }
497
498 static const unsigned char correct_data[] = {
499 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
500 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
501 };
502
503 err = compare_file(filename, correct_data, sizeof(correct_data));
504 if (err != 0) {
505 return err;
506 }
507
508 // read
509 fd = open(filename, O_RDONLY);
510 if (fd == -1) {
511 fprintf(stderr, "error opening for read %s\n", filename);
512 return 1;
513 }
514
515 KeyedVector<String8,FileState> readSnapshot;
516 err = read_snapshot_file(fd, &readSnapshot);
517 if (err != 0) {
518 fprintf(stderr, "read_snapshot_file failed %d\n", err);
519 return err;
520 }
521
522 if (readSnapshot.size() != 0) {
523 fprintf(stderr, "readSnapshot should be length 0\n");
524 return 1;
525 }
526
527 return 0;
528}
529
530int
531backup_helper_test_four()
532{
533 int err;
534 int fd;
535 KeyedVector<String8,FileState> snapshot;
536 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
537
538 system("rm -r " SCRATCH_DIR);
539 mkdir(SCRATCH_DIR, 0777);
540
541 // write
542 fd = creat(filename, 0666);
543 if (fd == -1) {
544 fprintf(stderr, "error opening %s\n", filename);
545 return 1;
546 }
547
548 String8 filenames[4];
549 FileState states[4];
550
551 states[0].modTime_sec = 0xfedcba98;
552 states[0].modTime_nsec = 0xdeadbeef;
553 states[0].size = 0xababbcbc;
554 states[0].crc32 = 0x12345678;
555 states[0].nameLen = -12;
556 filenames[0] = String8("bytes_of_padding");
557 snapshot.add(filenames[0], states[0]);
558
559 states[1].modTime_sec = 0x93400031;
560 states[1].modTime_nsec = 0xdeadbeef;
561 states[1].size = 0x88557766;
562 states[1].crc32 = 0x22334422;
563 states[1].nameLen = -1;
564 filenames[1] = String8("bytes_of_padding3");
565 snapshot.add(filenames[1], states[1]);
566
567 states[2].modTime_sec = 0x33221144;
568 states[2].modTime_nsec = 0xdeadbeef;
569 states[2].size = 0x11223344;
570 states[2].crc32 = 0x01122334;
571 states[2].nameLen = 0;
572 filenames[2] = String8("bytes_of_padding_2");
573 snapshot.add(filenames[2], states[2]);
574
575 states[3].modTime_sec = 0x33221144;
576 states[3].modTime_nsec = 0xdeadbeef;
577 states[3].size = 0x11223344;
578 states[3].crc32 = 0x01122334;
579 states[3].nameLen = 0;
580 filenames[3] = String8("bytes_of_padding__1");
581 snapshot.add(filenames[3], states[3]);
582
583 err = write_snapshot_file(fd, snapshot);
584
585 close(fd);
586
587 if (err != 0) {
588 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
589 return err;
590 }
591
592 static const unsigned char correct_data[] = {
593 // header
594 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
595 0x46, 0x69, 0x6c, 0x65, 0xac, 0x00, 0x00, 0x00,
596
597 // bytes_of_padding
598 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
599 0xbc, 0xbc, 0xab, 0xab, 0x78, 0x56, 0x34, 0x12,
600 0x10, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
601 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
602 0x64, 0x69, 0x6e, 0x67,
603
604 // bytes_of_padding3
605 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
606 0x66, 0x77, 0x55, 0x88, 0x22, 0x44, 0x33, 0x22,
607 0x11, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
608 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
609 0x64, 0x69, 0x6e, 0x67, 0x33, 0xab, 0xab, 0xab,
610
611 // bytes of padding2
612 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
613 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01,
614 0x12, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
615 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
616 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x32, 0xab, 0xab,
617
618 // bytes of padding3
619 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
620 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01,
621 0x13, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
622 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
623 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x5f, 0x31, 0xab
624 };
625
626 err = compare_file(filename, correct_data, sizeof(correct_data));
627 if (err != 0) {
628 return err;
629 }
630
631 // read
632 fd = open(filename, O_RDONLY);
633 if (fd == -1) {
634 fprintf(stderr, "error opening for read %s\n", filename);
635 return 1;
636 }
637
638
639 KeyedVector<String8,FileState> readSnapshot;
640 err = read_snapshot_file(fd, &readSnapshot);
641 if (err != 0) {
642 fprintf(stderr, "read_snapshot_file failed %d\n", err);
643 return err;
644 }
645
646 if (readSnapshot.size() != 4) {
647 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
648 return 1;
649 }
650
651 bool matched = true;
652 for (size_t i=0; i<readSnapshot.size(); i++) {
653 const String8& name = readSnapshot.keyAt(i);
654 const FileState state = readSnapshot.valueAt(i);
655
656 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
657 || states[i].modTime_nsec != state.modTime_nsec
658 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
659 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n"
660 " actual={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n", i,
661 states[i].modTime_sec, states[i].modTime_nsec, states[i].size, states[i].crc32,
662 name.length(), filenames[i].string(),
663 state.modTime_sec, state.modTime_nsec, state.size, state.crc32, state.nameLen,
664 name.string());
665 matched = false;
666 }
667 }
668
669 return matched ? 0 : 1;
670}
671
Joe Onorato8d626d62009-05-15 09:07:06 -0400672// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
673const unsigned char DATA_GOLDEN_FILE[] = {
674 0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00,
Joe Onoratod502f052009-05-15 18:20:19 -0400675 0xdd, 0xcc, 0xbb, 0xaa, 0x6e, 0x6f, 0x5f, 0x70,
Joe Onorato8d626d62009-05-15 09:07:06 -0400676 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
Joe Onoratod502f052009-05-15 18:20:19 -0400677 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
678 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
679 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
680 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
681 0x6e, 0x67, 0x5f, 0x00, 0x41, 0x70, 0x70, 0x31,
682 0x0c, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
Joe Onorato8d626d62009-05-15 09:07:06 -0400683 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
684 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
685 0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00,
686 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
687 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
688 0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
689 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
690 0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
Joe Onoratod502f052009-05-15 18:20:19 -0400691 0x0d, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
692 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
693 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
694 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
695 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato8d626d62009-05-15 09:07:06 -0400696 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onoratod502f052009-05-15 18:20:19 -0400697 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
698 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
699 0x5f, 0x00, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
700 0x0a, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
Joe Onorato8d626d62009-05-15 09:07:06 -0400701 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
702 0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61,
703 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
704 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
705 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
706 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc,
707 0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00,
Joe Onoratod502f052009-05-15 18:20:19 -0400708 0x99, 0x99, 0x77, 0x77
Joe Onorato8d626d62009-05-15 09:07:06 -0400709};
710const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
711
712static int
713test_write_header_and_entity(BackupDataWriter& writer, const char* str)
714{
715 int err;
716 String8 text(str);
717
Joe Onoratod502f052009-05-15 18:20:19 -0400718 err = writer.WriteAppHeader(text, 0xaabbccdd);
Joe Onorato8d626d62009-05-15 09:07:06 -0400719 if (err != 0) {
720 fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err));
721 return err;
722 }
723
724 err = writer.WriteEntityHeader(text, text.length()+1);
725 if (err != 0) {
726 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
727 return err;
728 }
729
730 err = writer.WriteEntityData(text.string(), text.length()+1);
731 if (err != 0) {
732 fprintf(stderr, "write failed for data '%s'\n", text.string());
733 return errno;
734 }
735
736 return err;
737}
738
739int
740backup_helper_test_data_writer()
741{
742 int err;
743 int fd;
744 const char* filename = SCRATCH_DIR "data_writer.data";
745
746 system("rm -r " SCRATCH_DIR);
747 mkdir(SCRATCH_DIR, 0777);
748 mkdir(SCRATCH_DIR "data", 0777);
749
750 fd = creat(filename, 0666);
751 if (fd == -1) {
752 fprintf(stderr, "error creating: %s\n", strerror(errno));
753 return errno;
754 }
755
756 BackupDataWriter writer(fd);
757
758 err = 0;
759 err |= test_write_header_and_entity(writer, "no_padding_");
760 err |= test_write_header_and_entity(writer, "padded_to__3");
761 err |= test_write_header_and_entity(writer, "padded_to_2__");
762 err |= test_write_header_and_entity(writer, "padded_to1");
763
Joe Onoratod502f052009-05-15 18:20:19 -0400764 writer.WriteAppFooter(0x77779999);
Joe Onorato8d626d62009-05-15 09:07:06 -0400765
766 close(fd);
767
768 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
769 if (err != 0) {
770 return err;
771 }
772
773 return err;
774}
775
Joe Onoratod502f052009-05-15 18:20:19 -0400776int
777test_read_header_and_entity(BackupDataReader& reader, const char* str)
778{
779 int err;
780 int bufSize = strlen(str)+1;
781 char* buf = (char*)malloc(bufSize);
782 String8 string;
783 int cookie = 0x11111111;
784 size_t actualSize;
785
786 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
787
788 err = reader.ReadNextHeader();
789 if (err != 0) {
790 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
791 goto done;
792 }
793
794 err = reader.ReadAppHeader(&string, &cookie);
795 if (err != 0) {
796 fprintf(stderr, "ReadAppHeader failed with %s\n", strerror(err));
797 goto done;
798 }
799 if (string != str) {
800 fprintf(stderr, "ReadAppHeader expected packageName '%s' got '%s'\n", str, string.string());
801 err = EINVAL;
802 goto done;
803 }
804 if (cookie != (int)0xaabbccdd) {
805 fprintf(stderr, "ReadAppHeader expected cookie 0x%08x got 0x%08x\n", 0xaabbccdd, cookie);
806 err = EINVAL;
807 goto done;
808 }
809
810 err = reader.ReadNextHeader();
811 if (err != 0) {
812 fprintf(stderr, "ReadNextHeader (for entity header) failed with %s\n", strerror(err));
813 goto done;
814 }
815
816 err = reader.ReadEntityHeader(&string, &actualSize);
817 if (err != 0) {
818 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
819 goto done;
820 }
821 if (string != str) {
822 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
823 err = EINVAL;
824 goto done;
825 }
826 if ((int)actualSize != bufSize) {
827 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
828 actualSize);
829 err = EINVAL;
830 goto done;
831 }
832
833 err = reader.ReadEntityData(buf, bufSize);
834 if (err != NO_ERROR) {
835 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
836 goto done;
837 }
838
839 if (0 != memcmp(buf, str, bufSize)) {
840 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
841 "%02x %02x %02x %02x\n", str, buf[0], buf[1], buf[2], buf[3]);
842 err = EINVAL;
843 goto done;
844 }
845
846 // The next read will confirm whether it got the right amount of data.
847
848done:
849 if (err != NO_ERROR) {
850 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
851 }
852 free(buf);
853 return err;
854}
855
856int
857backup_helper_test_data_reader()
858{
859 int err;
860 int fd;
861 const char* filename = SCRATCH_DIR "data_reader.data";
862
863 system("rm -r " SCRATCH_DIR);
864 mkdir(SCRATCH_DIR, 0777);
865 mkdir(SCRATCH_DIR "data", 0777);
866
867 fd = creat(filename, 0666);
868 if (fd == -1) {
869 fprintf(stderr, "error creating: %s\n", strerror(errno));
870 return errno;
871 }
872
873 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
874 if (err != DATA_GOLDEN_FILE_SIZE) {
875 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
876 return errno;
877 }
878
879 close(fd);
880
881 fd = open(filename, O_RDONLY);
882 if (fd == -1) {
883 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
884 filename);
885 return errno;
886 }
887
888 {
889 BackupDataReader reader(fd);
890
891 err = 0;
892
893 if (err == NO_ERROR) {
894 err = test_read_header_and_entity(reader, "no_padding_");
895 }
896
897 if (err == NO_ERROR) {
898 err = test_read_header_and_entity(reader, "padded_to__3");
899 }
900
901 if (err == NO_ERROR) {
902 err = test_read_header_and_entity(reader, "padded_to_2__");
903 }
904
905 if (err == NO_ERROR) {
906 err = test_read_header_and_entity(reader, "padded_to1");
907 }
908
909 if (err == NO_ERROR) {
910 err = reader.ReadNextHeader();
911 if (err != 0) {
912 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
913 }
914
915 if (err == NO_ERROR) {
916 int cookie;
917 err |= reader.ReadAppFooter(&cookie);
918 if (cookie != 0x77779999) {
919 fprintf(stderr, "app footer cookie expected=0x%08x actual=0x%08x\n",
920 0x77779999, cookie);
921 err = EINVAL;
922 }
923 }
924 }
925 }
926
927 close(fd);
928
929 return err;
930}
931
Joe Onorato0c4863b2009-05-05 11:50:51 -0700932static int
933get_mod_time(const char* filename, struct timeval times[2])
934{
935 int err;
936 struct stat64 st;
937 err = stat64(filename, &st);
938 if (err != 0) {
939 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
940 return errno;
941 }
942 times[0].tv_sec = st.st_atime;
943 times[0].tv_usec = st.st_atime_nsec / 1000;
944 times[1].tv_sec = st.st_mtime;
945 times[1].tv_usec = st.st_mtime_nsec / 1000;
946 return 0;
947}
948
949int
950backup_helper_test_files()
951{
952 int err;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700953 int oldSnapshotFD;
Joe Onorato8d626d62009-05-15 09:07:06 -0400954 int dataStreamFD;
955 int newSnapshotFD;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700956
957 system("rm -r " SCRATCH_DIR);
958 mkdir(SCRATCH_DIR, 0777);
959 mkdir(SCRATCH_DIR "data", 0777);
960
961 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
962 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
963 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
964 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
965 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
966 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
967
968 char const* files_before[] = {
969 "data/b",
970 "data/c",
971 "data/d",
972 "data/e",
973 "data/f"
974 };
975
Joe Onorato8d626d62009-05-15 09:07:06 -0400976 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
977 if (dataStreamFD == -1) {
978 fprintf(stderr, "error creating: %s\n", strerror(errno));
979 return errno;
980 }
981
Joe Onorato0c4863b2009-05-05 11:50:51 -0700982 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
983 if (newSnapshotFD == -1) {
984 fprintf(stderr, "error creating: %s\n", strerror(errno));
985 return errno;
986 }
Joe Onorato473b6e22009-05-19 13:41:21 -0700987
988 {
989 BackupDataWriter dataStream(dataStreamFD);
Joe Onorato8d626d62009-05-15 09:07:06 -0400990
Joe Onorato473b6e22009-05-19 13:41:21 -0700991 err = back_up_files(-1, &dataStream, newSnapshotFD, SCRATCH_DIR, files_before, 5);
992 if (err != 0) {
993 return err;
994 }
Joe Onorato0c4863b2009-05-05 11:50:51 -0700995 }
996
Joe Onorato8d626d62009-05-15 09:07:06 -0400997 close(dataStreamFD);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700998 close(newSnapshotFD);
999
1000 sleep(3);
1001
1002 struct timeval d_times[2];
1003 struct timeval e_times[2];
1004
1005 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1006 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1007 if (err != 0) {
1008 return err;
1009 }
1010
1011 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1012 unlink(SCRATCH_DIR "data/c");
1013 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1014 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1015 utimes(SCRATCH_DIR "data/d", d_times);
1016 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1017 utimes(SCRATCH_DIR "data/e", e_times);
1018 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1019 unlink(SCRATCH_DIR "data/f");
1020
1021 char const* files_after[] = {
1022 "data/a", // added
1023 "data/b", // same
1024 "data/c", // different mod time
1025 "data/d", // different size (same mod time)
1026 "data/e", // different contents (same mod time, same size)
1027 "data/g" // added
1028 };
1029
1030 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1031 if (oldSnapshotFD == -1) {
1032 fprintf(stderr, "error opening: %s\n", strerror(errno));
1033 return errno;
1034 }
1035
Joe Onorato8d626d62009-05-15 09:07:06 -04001036 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1037 if (dataStreamFD == -1) {
1038 fprintf(stderr, "error creating: %s\n", strerror(errno));
1039 return errno;
1040 }
1041
Joe Onorato0c4863b2009-05-05 11:50:51 -07001042 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1043 if (newSnapshotFD == -1) {
1044 fprintf(stderr, "error creating: %s\n", strerror(errno));
1045 return errno;
1046 }
1047
Joe Onorato473b6e22009-05-19 13:41:21 -07001048 {
1049 BackupDataWriter dataStream(dataStreamFD);
1050
1051 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, SCRATCH_DIR,
1052 files_after, 6);
1053 if (err != 0) {
1054 return err;
1055 }
1056}
Joe Onorato0c4863b2009-05-05 11:50:51 -07001057
1058 close(oldSnapshotFD);
Joe Onorato8d626d62009-05-15 09:07:06 -04001059 close(dataStreamFD);
Joe Onorato0c4863b2009-05-05 11:50:51 -07001060 close(newSnapshotFD);
1061
1062 return 0;
1063}
1064
1065#endif // TEST_BACKUP_HELPERS
Joe Onorato8d626d62009-05-15 09:07:06 -04001066
1067}