blob: 7ec2ce8653d949564a3a49d5df83cb40987e3aa6 [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>
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
Joe Onoratod2110db2009-05-19 13:41:21 -070044#if 0 // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -040045#define LOGP(x...) printf(x)
46#else
Joe Onorato290bb012009-05-13 18:57:29 -040047#define LOGP(x...) LOGD(x)
Joe Onorato4535e402009-05-15 09:07:06 -040048#endif
Joe Onorato290bb012009-05-13 18:57:29 -040049
Joe Onorato3ad977b2009-05-05 11:50:51 -070050struct SnapshotHeader {
51 int magic0;
52 int fileCount;
53 int magic1;
54 int totalSize;
55};
56
57struct FileState {
58 int modTime_sec;
59 int modTime_nsec;
60 int size;
61 int crc32;
62 int nameLen;
63};
64
65const static int ROUND_UP[4] = { 0, 3, 2, 1 };
66
67static inline int
68round_up(int n)
69{
70 return n + ROUND_UP[n % 4];
71}
72
73static int
74read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
75{
76 int bytesRead = 0;
77 int amt;
78 SnapshotHeader header;
79
80 amt = read(fd, &header, sizeof(header));
81 if (amt != sizeof(header)) {
82 return errno;
83 }
84 bytesRead += amt;
85
86 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
87 LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
88 return 1;
89 }
90
91 for (int i=0; i<header.fileCount; i++) {
92 FileState file;
93 char filenameBuf[128];
94
95 amt = read(fd, &file, sizeof(file));
96 if (amt != sizeof(file)) {
97 LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
98 return 1;
99 }
100 bytesRead += amt;
101
102 // filename is not NULL terminated, but it is padded
103 int nameBufSize = round_up(file.nameLen);
104 char* filename = nameBufSize <= (int)sizeof(filenameBuf)
105 ? filenameBuf
106 : (char*)malloc(nameBufSize);
107 amt = read(fd, filename, nameBufSize);
108 if (amt == nameBufSize) {
109 snapshot->add(String8(filename, file.nameLen), file);
110 }
111 bytesRead += amt;
112 if (filename != filenameBuf) {
113 free(filename);
114 }
115 if (amt != nameBufSize) {
116 LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
117 return 1;
118 }
119 }
120
121 if (header.totalSize != bytesRead) {
122 LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
123 header.totalSize, bytesRead);
124 return 1;
125 }
126
127 return 0;
128}
129
130static int
131write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot)
132{
133 int bytesWritten = sizeof(SnapshotHeader);
134 // preflight size
135 const int N = snapshot.size();
136 for (int i=0; i<N; i++) {
137 const String8& name = snapshot.keyAt(i);
138 bytesWritten += sizeof(FileState) + round_up(name.length());
139 }
140
Joe Onorato4535e402009-05-15 09:07:06 -0400141 LOGP("write_snapshot_file fd=%d\n", fd);
142
Joe Onorato3ad977b2009-05-05 11:50:51 -0700143 int amt;
144 SnapshotHeader header = { MAGIC0, N, MAGIC1, bytesWritten };
145
146 amt = write(fd, &header, sizeof(header));
147 if (amt != sizeof(header)) {
148 LOGW("write_snapshot_file error writing header %s", strerror(errno));
149 return errno;
150 }
151
152 for (int i=0; i<header.fileCount; i++) {
153 const String8& name = snapshot.keyAt(i);
154 FileState file = snapshot.valueAt(i);
155 int nameLen = file.nameLen = name.length();
156
157 amt = write(fd, &file, sizeof(file));
158 if (amt != sizeof(file)) {
159 LOGW("write_snapshot_file error writing header %s", strerror(errno));
160 return 1;
161 }
162
163 // filename is not NULL terminated, but it is padded
164 amt = write(fd, name.string(), nameLen);
165 if (amt != nameLen) {
166 LOGW("write_snapshot_file error writing filename %s", strerror(errno));
167 return 1;
168 }
169 int paddingLen = ROUND_UP[nameLen % 4];
170 if (paddingLen != 0) {
171 int padding = 0xabababab;
172 amt = write(fd, &padding, paddingLen);
173 if (amt != paddingLen) {
174 LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
175 paddingLen, strerror(errno));
176 return 1;
177 }
178 }
179 }
180
181 return 0;
182}
183
184static int
Joe Onoratod2110db2009-05-19 13:41:21 -0700185write_delete_file(BackupDataWriter* dataStream, const String8& key)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700186{
Joe Onorato290bb012009-05-13 18:57:29 -0400187 LOGP("write_delete_file %s\n", key.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700188 return dataStream->WriteEntityHeader(key, -1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700189}
190
191static int
Joe Onoratod2110db2009-05-19 13:41:21 -0700192write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
193 const String8& realFilename)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700194{
Joe Onorato290bb012009-05-13 18:57:29 -0400195 LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700196
197 const int bufsize = 4*1024;
198 int err;
199 int amt;
200 int fileSize;
201 int bytesLeft;
202
203 char* buf = (char*)malloc(bufsize);
204 int crc = crc32(0L, Z_NULL, 0);
205
206
207 bytesLeft = fileSize = lseek(fd, 0, SEEK_END);
208 lseek(fd, 0, SEEK_SET);
209
210 err = dataStream->WriteEntityHeader(key, bytesLeft);
211 if (err != 0) {
212 return err;
213 }
214
215 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
216 bytesLeft -= amt;
217 if (bytesLeft < 0) {
218 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised.
219 }
220 err = dataStream->WriteEntityData(buf, amt);
221 if (err != 0) {
222 return err;
223 }
224 }
225 if (bytesLeft != 0) {
226 if (bytesLeft > 0) {
227 // Pad out the space we promised in the buffer. We can't corrupt the buffer,
228 // even though the data we're sending is probably bad.
229 memset(buf, 0, bufsize);
230 while (bytesLeft > 0) {
231 amt = bytesLeft < bufsize ? bytesLeft : bufsize;
232 bytesLeft -= amt;
233 err = dataStream->WriteEntityData(buf, amt);
234 if (err != 0) {
235 return err;
236 }
237 }
238 }
239 LOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
240 " You aren't doing proper locking!",
241 realFilename.string(), fileSize, fileSize-bytesLeft);
242 }
243
244 free(buf);
245
246 return NO_ERROR;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700247}
248
249static int
Joe Onoratod2110db2009-05-19 13:41:21 -0700250write_update_file(BackupDataWriter* dataStream, const String8& key, const String8& realFilename)
251{
252 int err;
253 int fd = open(realFilename.string(), O_RDONLY);
254 if (fd == -1) {
255 return errno;
256 }
257 err = write_update_file(dataStream, fd, key, realFilename);
258 close(fd);
259 return err;
260}
261
262static int
263compute_crc32(int fd)
Joe Onorato3ad977b2009-05-05 11:50:51 -0700264{
265 const int bufsize = 4*1024;
266 int amt;
267
Joe Onorato3ad977b2009-05-05 11:50:51 -0700268 char* buf = (char*)malloc(bufsize);
269 int crc = crc32(0L, Z_NULL, 0);
270
Joe Onoratod2110db2009-05-19 13:41:21 -0700271 lseek(fd, 0, SEEK_SET);
272
Joe Onorato3ad977b2009-05-05 11:50:51 -0700273 while ((amt = read(fd, buf, bufsize)) != 0) {
274 crc = crc32(crc, (Bytef*)buf, amt);
275 }
276
Joe Onorato3ad977b2009-05-05 11:50:51 -0700277 free(buf);
278
279 return crc;
280}
281
282int
Joe Onoratod2110db2009-05-19 13:41:21 -0700283back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato3ad977b2009-05-05 11:50:51 -0700284 char const* fileBase, char const* const* files, int fileCount)
285{
286 int err;
287 const String8 base(fileBase);
288 KeyedVector<String8,FileState> oldSnapshot;
289 KeyedVector<String8,FileState> newSnapshot;
290
291 if (oldSnapshotFD != -1) {
292 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
293 if (err != 0) {
294 // On an error, treat this as a full backup.
295 oldSnapshot.clear();
296 }
297 }
298
299 for (int i=0; i<fileCount; i++) {
300 String8 name(files[i]);
301 FileState s;
302 struct stat st;
303 String8 realFilename(base);
304 realFilename.appendPath(name);
305
306 err = stat(realFilename.string(), &st);
307 if (err != 0) {
308 LOGW("Error stating file %s", realFilename.string());
309 continue;
310 }
311
312 s.modTime_sec = st.st_mtime;
Joe Onoratoc825d3e2009-05-06 12:55:46 -0400313 s.modTime_nsec = 0; // workaround sim breakage
314 //s.modTime_nsec = st.st_mtime_nsec;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700315 s.size = st.st_size;
Joe Onoratod2110db2009-05-19 13:41:21 -0700316
317 // we compute the crc32 later down below, when we already have the file open.
Joe Onorato3ad977b2009-05-05 11:50:51 -0700318
319 newSnapshot.add(name, s);
320 }
321
322 int n = 0;
323 int N = oldSnapshot.size();
324 int m = 0;
325
326 while (n<N && m<fileCount) {
327 const String8& p = oldSnapshot.keyAt(n);
328 const String8& q = newSnapshot.keyAt(m);
329 int cmp = p.compare(q);
330 if (cmp > 0) {
331 // file added
332 String8 realFilename(base);
333 realFilename.appendPath(q);
Joe Onorato4535e402009-05-15 09:07:06 -0400334 LOGP("file added: %s\n", realFilename.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700335 write_update_file(dataStream, q, realFilename);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700336 m++;
337 }
338 else if (cmp < 0) {
339 // file removed
Joe Onorato4535e402009-05-15 09:07:06 -0400340 LOGP("file removed: %s\n", p.string());
Joe Onoratod2110db2009-05-19 13:41:21 -0700341 dataStream->WriteEntityHeader(p, -1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700342 n++;
343 }
344 else {
Joe Onoratod2110db2009-05-19 13:41:21 -0700345
Joe Onorato3ad977b2009-05-05 11:50:51 -0700346 // both files exist, check them
347 String8 realFilename(base);
348 realFilename.appendPath(q);
349 const FileState& f = oldSnapshot.valueAt(n);
Joe Onoratod2110db2009-05-19 13:41:21 -0700350 FileState& g = newSnapshot.editValueAt(m);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700351
Joe Onoratod2110db2009-05-19 13:41:21 -0700352 int fd = open(realFilename.string(), O_RDONLY);
353 if (fd != -1) {
354 // We can't open the file. Don't report it as a delete either. Let the
355 // server keep the old version. Maybe they'll be able to deal with it
356 // on restore.
357 } else {
358 g.crc32 = compute_crc32(fd);
359
360 LOGP("%s\n", q.string());
361 LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n",
362 f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
363 LOGP(" old: modTime=%d,%d size=%-3d crc32=0x%08x\n",
364 g.modTime_sec, g.modTime_nsec, g.size, g.crc32);
365 if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec
366 || f.size != g.size || f.crc32 != g.crc32) {
367 write_update_file(dataStream, fd, p, realFilename);
368 }
369
370 close(fd);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700371 }
372 n++;
373 m++;
374 }
375 }
376
377 // these were deleted
378 while (n<N) {
Joe Onoratod2110db2009-05-19 13:41:21 -0700379 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700380 n++;
381 }
382
383 // these were added
384 while (m<fileCount) {
385 const String8& q = newSnapshot.keyAt(m);
386 String8 realFilename(base);
387 realFilename.appendPath(q);
Joe Onoratod2110db2009-05-19 13:41:21 -0700388 write_update_file(dataStream, q, realFilename);
Joe Onorato3ad977b2009-05-05 11:50:51 -0700389 m++;
390 }
391
392 err = write_snapshot_file(newSnapshotFD, newSnapshot);
393
394 return 0;
395}
396
397#if TEST_BACKUP_HELPERS
398
399#define SCRATCH_DIR "/data/backup_helper_test/"
400
401static int
402write_text_file(const char* path, const char* data)
403{
404 int amt;
405 int fd;
406 int len;
407
408 fd = creat(path, 0666);
409 if (fd == -1) {
410 fprintf(stderr, "creat %s failed\n", path);
411 return errno;
412 }
413
414 len = strlen(data);
415 amt = write(fd, data, len);
416 if (amt != len) {
417 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
418 return errno;
419 }
420
421 close(fd);
422
423 return 0;
424}
425
426static int
427compare_file(const char* path, const unsigned char* data, int len)
428{
429 int fd;
430 int amt;
431
432 fd = open(path, O_RDONLY);
433 if (fd == -1) {
434 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
435 return errno;
436 }
437
438 unsigned char* contents = (unsigned char*)malloc(len);
439 if (contents == NULL) {
440 fprintf(stderr, "malloc(%d) failed\n", len);
441 return ENOMEM;
442 }
443
444 bool sizesMatch = true;
445 amt = lseek(fd, 0, SEEK_END);
446 if (amt != len) {
447 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
448 sizesMatch = false;
449 }
450 lseek(fd, 0, SEEK_SET);
451
452 int readLen = amt < len ? amt : len;
453 amt = read(fd, contents, readLen);
454 if (amt != readLen) {
455 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
456 }
457
458 bool contentsMatch = true;
459 for (int i=0; i<readLen; i++) {
460 if (data[i] != contents[i]) {
461 if (contentsMatch) {
462 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
463 contentsMatch = false;
464 }
465 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
466 }
467 }
468
469 return contentsMatch && sizesMatch ? 0 : 1;
470}
471
472int
473backup_helper_test_empty()
474{
475 int err;
476 int fd;
477 KeyedVector<String8,FileState> snapshot;
478 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
479
480 system("rm -r " SCRATCH_DIR);
481 mkdir(SCRATCH_DIR, 0777);
482
483 // write
484 fd = creat(filename, 0666);
485 if (fd == -1) {
486 fprintf(stderr, "error creating %s\n", filename);
487 return 1;
488 }
489
490 err = write_snapshot_file(fd, snapshot);
491
492 close(fd);
493
494 if (err != 0) {
495 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
496 return err;
497 }
498
499 static const unsigned char correct_data[] = {
500 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
501 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
502 };
503
504 err = compare_file(filename, correct_data, sizeof(correct_data));
505 if (err != 0) {
506 return err;
507 }
508
509 // read
510 fd = open(filename, O_RDONLY);
511 if (fd == -1) {
512 fprintf(stderr, "error opening for read %s\n", filename);
513 return 1;
514 }
515
516 KeyedVector<String8,FileState> readSnapshot;
517 err = read_snapshot_file(fd, &readSnapshot);
518 if (err != 0) {
519 fprintf(stderr, "read_snapshot_file failed %d\n", err);
520 return err;
521 }
522
523 if (readSnapshot.size() != 0) {
524 fprintf(stderr, "readSnapshot should be length 0\n");
525 return 1;
526 }
527
528 return 0;
529}
530
531int
532backup_helper_test_four()
533{
534 int err;
535 int fd;
536 KeyedVector<String8,FileState> snapshot;
537 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
538
539 system("rm -r " SCRATCH_DIR);
540 mkdir(SCRATCH_DIR, 0777);
541
542 // write
543 fd = creat(filename, 0666);
544 if (fd == -1) {
545 fprintf(stderr, "error opening %s\n", filename);
546 return 1;
547 }
548
549 String8 filenames[4];
550 FileState states[4];
551
552 states[0].modTime_sec = 0xfedcba98;
553 states[0].modTime_nsec = 0xdeadbeef;
554 states[0].size = 0xababbcbc;
555 states[0].crc32 = 0x12345678;
556 states[0].nameLen = -12;
557 filenames[0] = String8("bytes_of_padding");
558 snapshot.add(filenames[0], states[0]);
559
560 states[1].modTime_sec = 0x93400031;
561 states[1].modTime_nsec = 0xdeadbeef;
562 states[1].size = 0x88557766;
563 states[1].crc32 = 0x22334422;
564 states[1].nameLen = -1;
565 filenames[1] = String8("bytes_of_padding3");
566 snapshot.add(filenames[1], states[1]);
567
568 states[2].modTime_sec = 0x33221144;
569 states[2].modTime_nsec = 0xdeadbeef;
570 states[2].size = 0x11223344;
571 states[2].crc32 = 0x01122334;
572 states[2].nameLen = 0;
573 filenames[2] = String8("bytes_of_padding_2");
574 snapshot.add(filenames[2], states[2]);
575
576 states[3].modTime_sec = 0x33221144;
577 states[3].modTime_nsec = 0xdeadbeef;
578 states[3].size = 0x11223344;
579 states[3].crc32 = 0x01122334;
580 states[3].nameLen = 0;
581 filenames[3] = String8("bytes_of_padding__1");
582 snapshot.add(filenames[3], states[3]);
583
584 err = write_snapshot_file(fd, snapshot);
585
586 close(fd);
587
588 if (err != 0) {
589 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
590 return err;
591 }
592
593 static const unsigned char correct_data[] = {
594 // header
595 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
596 0x46, 0x69, 0x6c, 0x65, 0xac, 0x00, 0x00, 0x00,
597
598 // bytes_of_padding
599 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
600 0xbc, 0xbc, 0xab, 0xab, 0x78, 0x56, 0x34, 0x12,
601 0x10, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
602 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
603 0x64, 0x69, 0x6e, 0x67,
604
605 // bytes_of_padding3
606 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
607 0x66, 0x77, 0x55, 0x88, 0x22, 0x44, 0x33, 0x22,
608 0x11, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
609 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
610 0x64, 0x69, 0x6e, 0x67, 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -0700611
Joe Onorato3ad977b2009-05-05 11:50:51 -0700612 // bytes of padding2
613 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
614 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01,
615 0x12, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
616 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
617 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -0700618
Joe Onorato3ad977b2009-05-05 11:50:51 -0700619 // bytes of padding3
620 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
621 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01,
622 0x13, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
623 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
624 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x5f, 0x31, 0xab
625 };
626
627 err = compare_file(filename, correct_data, sizeof(correct_data));
628 if (err != 0) {
629 return err;
630 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -0700631
Joe Onorato3ad977b2009-05-05 11:50:51 -0700632 // read
633 fd = open(filename, O_RDONLY);
634 if (fd == -1) {
635 fprintf(stderr, "error opening for read %s\n", filename);
636 return 1;
637 }
638
639
640 KeyedVector<String8,FileState> readSnapshot;
641 err = read_snapshot_file(fd, &readSnapshot);
642 if (err != 0) {
643 fprintf(stderr, "read_snapshot_file failed %d\n", err);
644 return err;
645 }
646
647 if (readSnapshot.size() != 4) {
648 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
649 return 1;
650 }
651
652 bool matched = true;
653 for (size_t i=0; i<readSnapshot.size(); i++) {
654 const String8& name = readSnapshot.keyAt(i);
655 const FileState state = readSnapshot.valueAt(i);
656
657 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
658 || states[i].modTime_nsec != state.modTime_nsec
659 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
660 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n"
661 " actual={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n", i,
662 states[i].modTime_sec, states[i].modTime_nsec, states[i].size, states[i].crc32,
663 name.length(), filenames[i].string(),
664 state.modTime_sec, state.modTime_nsec, state.size, state.crc32, state.nameLen,
665 name.string());
666 matched = false;
667 }
668 }
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -0700669
Joe Onorato3ad977b2009-05-05 11:50:51 -0700670 return matched ? 0 : 1;
671}
672
Joe Onorato4535e402009-05-15 09:07:06 -0400673// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
674const unsigned char DATA_GOLDEN_FILE[] = {
675 0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00,
Joe Onorato2e1da322009-05-15 18:20:19 -0400676 0xdd, 0xcc, 0xbb, 0xaa, 0x6e, 0x6f, 0x5f, 0x70,
Joe Onorato4535e402009-05-15 09:07:06 -0400677 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
Joe Onorato2e1da322009-05-15 18:20:19 -0400678 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
679 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
680 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
681 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
682 0x6e, 0x67, 0x5f, 0x00, 0x41, 0x70, 0x70, 0x31,
683 0x0c, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
Joe Onorato4535e402009-05-15 09:07:06 -0400684 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
685 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
686 0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00,
687 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
688 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
689 0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
690 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
691 0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
Joe Onorato2e1da322009-05-15 18:20:19 -0400692 0x0d, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
693 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
694 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
695 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
696 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato4535e402009-05-15 09:07:06 -0400697 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onorato2e1da322009-05-15 18:20:19 -0400698 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
699 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
700 0x5f, 0x00, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
701 0x0a, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
Joe Onorato4535e402009-05-15 09:07:06 -0400702 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
703 0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61,
704 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
705 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
706 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
707 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc,
708 0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00,
Joe Onorato2e1da322009-05-15 18:20:19 -0400709 0x99, 0x99, 0x77, 0x77
Joe Onorato4535e402009-05-15 09:07:06 -0400710};
711const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
712
713static int
714test_write_header_and_entity(BackupDataWriter& writer, const char* str)
715{
716 int err;
717 String8 text(str);
718
Joe Onorato2e1da322009-05-15 18:20:19 -0400719 err = writer.WriteAppHeader(text, 0xaabbccdd);
Joe Onorato4535e402009-05-15 09:07:06 -0400720 if (err != 0) {
721 fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err));
722 return err;
723 }
724
725 err = writer.WriteEntityHeader(text, text.length()+1);
726 if (err != 0) {
727 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
728 return err;
729 }
730
731 err = writer.WriteEntityData(text.string(), text.length()+1);
732 if (err != 0) {
733 fprintf(stderr, "write failed for data '%s'\n", text.string());
734 return errno;
735 }
736
737 return err;
738}
739
740int
741backup_helper_test_data_writer()
742{
743 int err;
744 int fd;
745 const char* filename = SCRATCH_DIR "data_writer.data";
746
747 system("rm -r " SCRATCH_DIR);
748 mkdir(SCRATCH_DIR, 0777);
749 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -0700750
Joe Onorato4535e402009-05-15 09:07:06 -0400751 fd = creat(filename, 0666);
752 if (fd == -1) {
753 fprintf(stderr, "error creating: %s\n", strerror(errno));
754 return errno;
755 }
756
757 BackupDataWriter writer(fd);
758
759 err = 0;
760 err |= test_write_header_and_entity(writer, "no_padding_");
761 err |= test_write_header_and_entity(writer, "padded_to__3");
762 err |= test_write_header_and_entity(writer, "padded_to_2__");
763 err |= test_write_header_and_entity(writer, "padded_to1");
764
Joe Onorato2e1da322009-05-15 18:20:19 -0400765 writer.WriteAppFooter(0x77779999);
Joe Onorato4535e402009-05-15 09:07:06 -0400766
767 close(fd);
768
769 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
770 if (err != 0) {
771 return err;
772 }
773
774 return err;
775}
776
Joe Onorato2e1da322009-05-15 18:20:19 -0400777int
778test_read_header_and_entity(BackupDataReader& reader, const char* str)
779{
780 int err;
781 int bufSize = strlen(str)+1;
782 char* buf = (char*)malloc(bufSize);
783 String8 string;
784 int cookie = 0x11111111;
785 size_t actualSize;
786
787 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
788
789 err = reader.ReadNextHeader();
790 if (err != 0) {
791 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
792 goto done;
793 }
794
795 err = reader.ReadAppHeader(&string, &cookie);
796 if (err != 0) {
797 fprintf(stderr, "ReadAppHeader failed with %s\n", strerror(err));
798 goto done;
799 }
800 if (string != str) {
801 fprintf(stderr, "ReadAppHeader expected packageName '%s' got '%s'\n", str, string.string());
802 err = EINVAL;
803 goto done;
804 }
805 if (cookie != (int)0xaabbccdd) {
806 fprintf(stderr, "ReadAppHeader expected cookie 0x%08x got 0x%08x\n", 0xaabbccdd, cookie);
807 err = EINVAL;
808 goto done;
809 }
810
811 err = reader.ReadNextHeader();
812 if (err != 0) {
813 fprintf(stderr, "ReadNextHeader (for entity header) failed with %s\n", strerror(err));
814 goto done;
815 }
816
817 err = reader.ReadEntityHeader(&string, &actualSize);
818 if (err != 0) {
819 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
820 goto done;
821 }
822 if (string != str) {
823 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
824 err = EINVAL;
825 goto done;
826 }
827 if ((int)actualSize != bufSize) {
828 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
829 actualSize);
830 err = EINVAL;
831 goto done;
832 }
833
834 err = reader.ReadEntityData(buf, bufSize);
835 if (err != NO_ERROR) {
836 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
837 goto done;
838 }
839
840 if (0 != memcmp(buf, str, bufSize)) {
841 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
842 "%02x %02x %02x %02x\n", str, buf[0], buf[1], buf[2], buf[3]);
843 err = EINVAL;
844 goto done;
845 }
846
847 // The next read will confirm whether it got the right amount of data.
848
849done:
850 if (err != NO_ERROR) {
851 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
852 }
853 free(buf);
854 return err;
855}
856
857int
858backup_helper_test_data_reader()
859{
860 int err;
861 int fd;
862 const char* filename = SCRATCH_DIR "data_reader.data";
863
864 system("rm -r " SCRATCH_DIR);
865 mkdir(SCRATCH_DIR, 0777);
866 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -0700867
Joe Onorato2e1da322009-05-15 18:20:19 -0400868 fd = creat(filename, 0666);
869 if (fd == -1) {
870 fprintf(stderr, "error creating: %s\n", strerror(errno));
871 return errno;
872 }
873
874 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
875 if (err != DATA_GOLDEN_FILE_SIZE) {
876 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
877 return errno;
878 }
879
880 close(fd);
881
882 fd = open(filename, O_RDONLY);
883 if (fd == -1) {
884 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
885 filename);
886 return errno;
887 }
888
889 {
890 BackupDataReader reader(fd);
891
892 err = 0;
893
894 if (err == NO_ERROR) {
895 err = test_read_header_and_entity(reader, "no_padding_");
896 }
897
898 if (err == NO_ERROR) {
899 err = test_read_header_and_entity(reader, "padded_to__3");
900 }
901
902 if (err == NO_ERROR) {
903 err = test_read_header_and_entity(reader, "padded_to_2__");
904 }
905
906 if (err == NO_ERROR) {
907 err = test_read_header_and_entity(reader, "padded_to1");
908 }
909
910 if (err == NO_ERROR) {
911 err = reader.ReadNextHeader();
912 if (err != 0) {
913 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
914 }
915
916 if (err == NO_ERROR) {
917 int cookie;
918 err |= reader.ReadAppFooter(&cookie);
919 if (cookie != 0x77779999) {
920 fprintf(stderr, "app footer cookie expected=0x%08x actual=0x%08x\n",
921 0x77779999, cookie);
922 err = EINVAL;
923 }
924 }
925 }
926 }
927
928 close(fd);
929
930 return err;
931}
932
Joe Onorato3ad977b2009-05-05 11:50:51 -0700933static int
934get_mod_time(const char* filename, struct timeval times[2])
935{
936 int err;
937 struct stat64 st;
938 err = stat64(filename, &st);
939 if (err != 0) {
940 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
941 return errno;
942 }
943 times[0].tv_sec = st.st_atime;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700944 times[1].tv_sec = st.st_mtime;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -0700945
946 // If st_atime is a macro then struct stat64 uses struct timespec
947 // to store the access and modif time values and typically
948 // st_*time_nsec is not defined. In glibc, this is controlled by
949 // __USE_MISC.
950#ifdef __USE_MISC
951#if !defined(st_atime) || defined(st_atime_nsec)
952#error "Check if this __USE_MISC conditional is still needed."
953#endif
954 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
955 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
956#else
957 times[0].tv_usec = st.st_atime_nsec / 1000;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700958 times[1].tv_usec = st.st_mtime_nsec / 1000;
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -0700959#endif
960
Joe Onorato3ad977b2009-05-05 11:50:51 -0700961 return 0;
962}
963
964int
965backup_helper_test_files()
966{
967 int err;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700968 int oldSnapshotFD;
Joe Onorato4535e402009-05-15 09:07:06 -0400969 int dataStreamFD;
970 int newSnapshotFD;
Joe Onorato3ad977b2009-05-05 11:50:51 -0700971
972 system("rm -r " SCRATCH_DIR);
973 mkdir(SCRATCH_DIR, 0777);
974 mkdir(SCRATCH_DIR "data", 0777);
975
976 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
977 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
978 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
979 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
980 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
981 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
982
983 char const* files_before[] = {
984 "data/b",
985 "data/c",
986 "data/d",
987 "data/e",
988 "data/f"
989 };
990
Joe Onorato4535e402009-05-15 09:07:06 -0400991 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
992 if (dataStreamFD == -1) {
993 fprintf(stderr, "error creating: %s\n", strerror(errno));
994 return errno;
995 }
996
Joe Onorato3ad977b2009-05-05 11:50:51 -0700997 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
998 if (newSnapshotFD == -1) {
999 fprintf(stderr, "error creating: %s\n", strerror(errno));
1000 return errno;
1001 }
Joe Onoratod2110db2009-05-19 13:41:21 -07001002
1003 {
1004 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001005
Joe Onoratod2110db2009-05-19 13:41:21 -07001006 err = back_up_files(-1, &dataStream, newSnapshotFD, SCRATCH_DIR, files_before, 5);
1007 if (err != 0) {
1008 return err;
1009 }
Joe Onorato3ad977b2009-05-05 11:50:51 -07001010 }
1011
Joe Onorato4535e402009-05-15 09:07:06 -04001012 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001013 close(newSnapshotFD);
1014
1015 sleep(3);
1016
1017 struct timeval d_times[2];
1018 struct timeval e_times[2];
1019
1020 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1021 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1022 if (err != 0) {
1023 return err;
1024 }
1025
1026 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1027 unlink(SCRATCH_DIR "data/c");
1028 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1029 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1030 utimes(SCRATCH_DIR "data/d", d_times);
1031 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1032 utimes(SCRATCH_DIR "data/e", e_times);
1033 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1034 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001035
Joe Onorato3ad977b2009-05-05 11:50:51 -07001036 char const* files_after[] = {
1037 "data/a", // added
1038 "data/b", // same
1039 "data/c", // different mod time
1040 "data/d", // different size (same mod time)
1041 "data/e", // different contents (same mod time, same size)
1042 "data/g" // added
1043 };
1044
1045 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1046 if (oldSnapshotFD == -1) {
1047 fprintf(stderr, "error opening: %s\n", strerror(errno));
1048 return errno;
1049 }
1050
Joe Onorato4535e402009-05-15 09:07:06 -04001051 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1052 if (dataStreamFD == -1) {
1053 fprintf(stderr, "error creating: %s\n", strerror(errno));
1054 return errno;
1055 }
1056
Joe Onorato3ad977b2009-05-05 11:50:51 -07001057 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1058 if (newSnapshotFD == -1) {
1059 fprintf(stderr, "error creating: %s\n", strerror(errno));
1060 return errno;
1061 }
1062
Joe Onoratod2110db2009-05-19 13:41:21 -07001063 {
1064 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001065
Joe Onoratod2110db2009-05-19 13:41:21 -07001066 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, SCRATCH_DIR,
1067 files_after, 6);
1068 if (err != 0) {
1069 return err;
1070 }
1071}
Joe Onorato3ad977b2009-05-05 11:50:51 -07001072
1073 close(oldSnapshotFD);
Joe Onorato4535e402009-05-15 09:07:06 -04001074 close(dataStreamFD);
Joe Onorato3ad977b2009-05-05 11:50:51 -07001075 close(newSnapshotFD);
Nicolas Cataniaf4c46b92009-05-22 13:41:38 -07001076
Joe Onorato3ad977b2009-05-05 11:50:51 -07001077 return 0;
1078}
1079
1080#endif // TEST_BACKUP_HELPERS
Joe Onorato4535e402009-05-15 09:07:06 -04001081
1082}