blob: 7f423a8e8e9bf083a6a1c608a3bcc24a3f1cd873 [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
Mathias Agopianf446ba92009-06-04 13:53:57 -070019#include <utils/BackupHelpers.h>
Joe Onorato0c4863b2009-05-05 11:50:51 -070020
21#include <utils/KeyedVector.h>
22#include <utils/ByteOrder.h>
23#include <utils/String8.h>
24
25#include <errno.h>
26#include <sys/types.h>
27#include <sys/uio.h>
28#include <sys/stat.h>
Nicolas Cataniab4c42652009-05-22 13:41:38 -070029#include <sys/time.h> // for utimes
Joe Onorato0c4863b2009-05-05 11:50:51 -070030#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
Joe Onorato2a98fb92009-05-06 12:55:46 -040033#include <utime.h>
Joe Onorato0c4863b2009-05-05 11:50:51 -070034#include <fcntl.h>
35#include <zlib.h>
36
37#include <cutils/log.h>
38
Joe Onorato8d626d62009-05-15 09:07:06 -040039namespace android {
Joe Onorato0c4863b2009-05-05 11:50:51 -070040
41#define MAGIC0 0x70616e53 // Snap
42#define MAGIC1 0x656c6946 // File
43
Joe Onorato473b6e22009-05-19 13:41:21 -070044#if 0 // TEST_BACKUP_HELPERS
Joe Onorato8d626d62009-05-15 09:07:06 -040045#define LOGP(x...) printf(x)
46#else
Joe Onoratoc7bbc692009-05-13 18:57:29 -040047#define LOGP(x...) LOGD(x)
Joe Onorato8d626d62009-05-15 09:07:06 -040048#endif
Joe Onoratoc7bbc692009-05-13 18:57:29 -040049
Joe Onorato0c4863b2009-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 Onorato8d626d62009-05-15 09:07:06 -0400141 LOGP("write_snapshot_file fd=%d\n", fd);
142
Joe Onorato0c4863b2009-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 Onorato473b6e22009-05-19 13:41:21 -0700185write_delete_file(BackupDataWriter* dataStream, const String8& key)
Joe Onorato0c4863b2009-05-05 11:50:51 -0700186{
Joe Onoratoc7bbc692009-05-13 18:57:29 -0400187 LOGP("write_delete_file %s\n", key.string());
Joe Onorato473b6e22009-05-19 13:41:21 -0700188 return dataStream->WriteEntityHeader(key, -1);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700189}
190
191static int
Joe Onorato473b6e22009-05-19 13:41:21 -0700192write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
193 const String8& realFilename)
Joe Onorato0c4863b2009-05-05 11:50:51 -0700194{
Joe Onoratoc7bbc692009-05-13 18:57:29 -0400195 LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string());
Joe Onorato473b6e22009-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 Onorato0c4863b2009-05-05 11:50:51 -0700247}
248
249static int
Joe Onorato473b6e22009-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 Onorato0c4863b2009-05-05 11:50:51 -0700264{
265 const int bufsize = 4*1024;
266 int amt;
267
Joe Onorato0c4863b2009-05-05 11:50:51 -0700268 char* buf = (char*)malloc(bufsize);
269 int crc = crc32(0L, Z_NULL, 0);
270
Joe Onorato473b6e22009-05-19 13:41:21 -0700271 lseek(fd, 0, SEEK_SET);
272
Joe Onorato0c4863b2009-05-05 11:50:51 -0700273 while ((amt = read(fd, buf, bufsize)) != 0) {
274 crc = crc32(crc, (Bytef*)buf, amt);
275 }
276
Joe Onorato0c4863b2009-05-05 11:50:51 -0700277 free(buf);
278
279 return crc;
280}
281
282int
Joe Onorato473b6e22009-05-19 13:41:21 -0700283back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
Joe Onorato0c4863b2009-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 Onorato2a98fb92009-05-06 12:55:46 -0400313 s.modTime_nsec = 0; // workaround sim breakage
314 //s.modTime_nsec = st.st_mtime_nsec;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700315 s.size = st.st_size;
Joe Onorato473b6e22009-05-19 13:41:21 -0700316
317 // we compute the crc32 later down below, when we already have the file open.
Joe Onorato0c4863b2009-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 Onorato8d626d62009-05-15 09:07:06 -0400334 LOGP("file added: %s\n", realFilename.string());
Joe Onorato473b6e22009-05-19 13:41:21 -0700335 write_update_file(dataStream, q, realFilename);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700336 m++;
337 }
338 else if (cmp < 0) {
339 // file removed
Joe Onorato8d626d62009-05-15 09:07:06 -0400340 LOGP("file removed: %s\n", p.string());
Joe Onorato473b6e22009-05-19 13:41:21 -0700341 dataStream->WriteEntityHeader(p, -1);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700342 n++;
343 }
344 else {
Joe Onorato473b6e22009-05-19 13:41:21 -0700345
Joe Onorato0c4863b2009-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 Onorato473b6e22009-05-19 13:41:21 -0700350 FileState& g = newSnapshot.editValueAt(m);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700351
Joe Onorato473b6e22009-05-19 13:41:21 -0700352 int fd = open(realFilename.string(), O_RDONLY);
Christopher Tate173e38d2009-06-04 17:01:06 -0700353 if (fd < 0) {
Joe Onorato473b6e22009-05-19 13:41:21 -0700354 // 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.
Christopher Tate173e38d2009-06-04 17:01:06 -0700357 LOGP("Unable to open file %s - skipping", realFilename.string());
Joe Onorato473b6e22009-05-19 13:41:21 -0700358 } else {
359 g.crc32 = compute_crc32(fd);
360
361 LOGP("%s\n", q.string());
362 LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n",
363 f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
364 LOGP(" old: modTime=%d,%d size=%-3d crc32=0x%08x\n",
365 g.modTime_sec, g.modTime_nsec, g.size, g.crc32);
366 if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec
367 || f.size != g.size || f.crc32 != g.crc32) {
368 write_update_file(dataStream, fd, p, realFilename);
369 }
370
371 close(fd);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700372 }
373 n++;
374 m++;
375 }
376 }
377
378 // these were deleted
379 while (n<N) {
Joe Onorato473b6e22009-05-19 13:41:21 -0700380 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700381 n++;
382 }
383
384 // these were added
385 while (m<fileCount) {
386 const String8& q = newSnapshot.keyAt(m);
387 String8 realFilename(base);
388 realFilename.appendPath(q);
Joe Onorato473b6e22009-05-19 13:41:21 -0700389 write_update_file(dataStream, q, realFilename);
Joe Onorato0c4863b2009-05-05 11:50:51 -0700390 m++;
391 }
392
393 err = write_snapshot_file(newSnapshotFD, newSnapshot);
394
395 return 0;
396}
397
398#if TEST_BACKUP_HELPERS
399
400#define SCRATCH_DIR "/data/backup_helper_test/"
401
402static int
403write_text_file(const char* path, const char* data)
404{
405 int amt;
406 int fd;
407 int len;
408
409 fd = creat(path, 0666);
410 if (fd == -1) {
411 fprintf(stderr, "creat %s failed\n", path);
412 return errno;
413 }
414
415 len = strlen(data);
416 amt = write(fd, data, len);
417 if (amt != len) {
418 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
419 return errno;
420 }
421
422 close(fd);
423
424 return 0;
425}
426
427static int
428compare_file(const char* path, const unsigned char* data, int len)
429{
430 int fd;
431 int amt;
432
433 fd = open(path, O_RDONLY);
434 if (fd == -1) {
435 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
436 return errno;
437 }
438
439 unsigned char* contents = (unsigned char*)malloc(len);
440 if (contents == NULL) {
441 fprintf(stderr, "malloc(%d) failed\n", len);
442 return ENOMEM;
443 }
444
445 bool sizesMatch = true;
446 amt = lseek(fd, 0, SEEK_END);
447 if (amt != len) {
448 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
449 sizesMatch = false;
450 }
451 lseek(fd, 0, SEEK_SET);
452
453 int readLen = amt < len ? amt : len;
454 amt = read(fd, contents, readLen);
455 if (amt != readLen) {
456 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
457 }
458
459 bool contentsMatch = true;
460 for (int i=0; i<readLen; i++) {
461 if (data[i] != contents[i]) {
462 if (contentsMatch) {
463 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
464 contentsMatch = false;
465 }
466 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]);
467 }
468 }
469
470 return contentsMatch && sizesMatch ? 0 : 1;
471}
472
473int
474backup_helper_test_empty()
475{
476 int err;
477 int fd;
478 KeyedVector<String8,FileState> snapshot;
479 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
480
481 system("rm -r " SCRATCH_DIR);
482 mkdir(SCRATCH_DIR, 0777);
483
484 // write
485 fd = creat(filename, 0666);
486 if (fd == -1) {
487 fprintf(stderr, "error creating %s\n", filename);
488 return 1;
489 }
490
491 err = write_snapshot_file(fd, snapshot);
492
493 close(fd);
494
495 if (err != 0) {
496 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
497 return err;
498 }
499
500 static const unsigned char correct_data[] = {
501 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00,
502 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00
503 };
504
505 err = compare_file(filename, correct_data, sizeof(correct_data));
506 if (err != 0) {
507 return err;
508 }
509
510 // read
511 fd = open(filename, O_RDONLY);
512 if (fd == -1) {
513 fprintf(stderr, "error opening for read %s\n", filename);
514 return 1;
515 }
516
517 KeyedVector<String8,FileState> readSnapshot;
518 err = read_snapshot_file(fd, &readSnapshot);
519 if (err != 0) {
520 fprintf(stderr, "read_snapshot_file failed %d\n", err);
521 return err;
522 }
523
524 if (readSnapshot.size() != 0) {
525 fprintf(stderr, "readSnapshot should be length 0\n");
526 return 1;
527 }
528
529 return 0;
530}
531
532int
533backup_helper_test_four()
534{
535 int err;
536 int fd;
537 KeyedVector<String8,FileState> snapshot;
538 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
539
540 system("rm -r " SCRATCH_DIR);
541 mkdir(SCRATCH_DIR, 0777);
542
543 // write
544 fd = creat(filename, 0666);
545 if (fd == -1) {
546 fprintf(stderr, "error opening %s\n", filename);
547 return 1;
548 }
549
550 String8 filenames[4];
551 FileState states[4];
552
553 states[0].modTime_sec = 0xfedcba98;
554 states[0].modTime_nsec = 0xdeadbeef;
555 states[0].size = 0xababbcbc;
556 states[0].crc32 = 0x12345678;
557 states[0].nameLen = -12;
558 filenames[0] = String8("bytes_of_padding");
559 snapshot.add(filenames[0], states[0]);
560
561 states[1].modTime_sec = 0x93400031;
562 states[1].modTime_nsec = 0xdeadbeef;
563 states[1].size = 0x88557766;
564 states[1].crc32 = 0x22334422;
565 states[1].nameLen = -1;
566 filenames[1] = String8("bytes_of_padding3");
567 snapshot.add(filenames[1], states[1]);
568
569 states[2].modTime_sec = 0x33221144;
570 states[2].modTime_nsec = 0xdeadbeef;
571 states[2].size = 0x11223344;
572 states[2].crc32 = 0x01122334;
573 states[2].nameLen = 0;
574 filenames[2] = String8("bytes_of_padding_2");
575 snapshot.add(filenames[2], states[2]);
576
577 states[3].modTime_sec = 0x33221144;
578 states[3].modTime_nsec = 0xdeadbeef;
579 states[3].size = 0x11223344;
580 states[3].crc32 = 0x01122334;
581 states[3].nameLen = 0;
582 filenames[3] = String8("bytes_of_padding__1");
583 snapshot.add(filenames[3], states[3]);
584
585 err = write_snapshot_file(fd, snapshot);
586
587 close(fd);
588
589 if (err != 0) {
590 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
591 return err;
592 }
593
594 static const unsigned char correct_data[] = {
595 // header
596 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00,
597 0x46, 0x69, 0x6c, 0x65, 0xac, 0x00, 0x00, 0x00,
598
599 // bytes_of_padding
600 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde,
601 0xbc, 0xbc, 0xab, 0xab, 0x78, 0x56, 0x34, 0x12,
602 0x10, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
603 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
604 0x64, 0x69, 0x6e, 0x67,
605
606 // bytes_of_padding3
607 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde,
608 0x66, 0x77, 0x55, 0x88, 0x22, 0x44, 0x33, 0x22,
609 0x11, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
610 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
611 0x64, 0x69, 0x6e, 0x67, 0x33, 0xab, 0xab, 0xab,
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700612
Joe Onorato0c4863b2009-05-05 11:50:51 -0700613 // bytes of padding2
614 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
615 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01,
616 0x12, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
617 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
618 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x32, 0xab, 0xab,
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700619
Joe Onorato0c4863b2009-05-05 11:50:51 -0700620 // bytes of padding3
621 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde,
622 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01,
623 0x13, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65,
624 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64,
625 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x5f, 0x31, 0xab
626 };
627
628 err = compare_file(filename, correct_data, sizeof(correct_data));
629 if (err != 0) {
630 return err;
631 }
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700632
Joe Onorato0c4863b2009-05-05 11:50:51 -0700633 // read
634 fd = open(filename, O_RDONLY);
635 if (fd == -1) {
636 fprintf(stderr, "error opening for read %s\n", filename);
637 return 1;
638 }
639
640
641 KeyedVector<String8,FileState> readSnapshot;
642 err = read_snapshot_file(fd, &readSnapshot);
643 if (err != 0) {
644 fprintf(stderr, "read_snapshot_file failed %d\n", err);
645 return err;
646 }
647
648 if (readSnapshot.size() != 4) {
649 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
650 return 1;
651 }
652
653 bool matched = true;
654 for (size_t i=0; i<readSnapshot.size(); i++) {
655 const String8& name = readSnapshot.keyAt(i);
656 const FileState state = readSnapshot.valueAt(i);
657
658 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
659 || states[i].modTime_nsec != state.modTime_nsec
660 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
661 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n"
662 " actual={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n", i,
663 states[i].modTime_sec, states[i].modTime_nsec, states[i].size, states[i].crc32,
664 name.length(), filenames[i].string(),
665 state.modTime_sec, state.modTime_nsec, state.size, state.crc32, state.nameLen,
666 name.string());
667 matched = false;
668 }
669 }
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700670
Joe Onorato0c4863b2009-05-05 11:50:51 -0700671 return matched ? 0 : 1;
672}
673
Joe Onorato8d626d62009-05-15 09:07:06 -0400674// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
675const unsigned char DATA_GOLDEN_FILE[] = {
676 0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00,
Joe Onoratod502f052009-05-15 18:20:19 -0400677 0xdd, 0xcc, 0xbb, 0xaa, 0x6e, 0x6f, 0x5f, 0x70,
Joe Onorato8d626d62009-05-15 09:07:06 -0400678 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
Joe Onoratod502f052009-05-15 18:20:19 -0400679 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
680 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
681 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
682 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
683 0x6e, 0x67, 0x5f, 0x00, 0x41, 0x70, 0x70, 0x31,
684 0x0c, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
Joe Onorato8d626d62009-05-15 09:07:06 -0400685 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
686 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
687 0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00,
688 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
689 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
690 0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
691 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
692 0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
Joe Onoratod502f052009-05-15 18:20:19 -0400693 0x0d, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
694 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
695 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
696 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
697 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
Joe Onorato8d626d62009-05-15 09:07:06 -0400698 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
Joe Onoratod502f052009-05-15 18:20:19 -0400699 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
700 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
701 0x5f, 0x00, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
702 0x0a, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
Joe Onorato8d626d62009-05-15 09:07:06 -0400703 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
704 0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61,
705 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
706 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
707 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
708 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc,
709 0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00,
Joe Onoratod502f052009-05-15 18:20:19 -0400710 0x99, 0x99, 0x77, 0x77
Joe Onorato8d626d62009-05-15 09:07:06 -0400711};
712const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
713
714static int
715test_write_header_and_entity(BackupDataWriter& writer, const char* str)
716{
717 int err;
718 String8 text(str);
719
Joe Onoratod502f052009-05-15 18:20:19 -0400720 err = writer.WriteAppHeader(text, 0xaabbccdd);
Joe Onorato8d626d62009-05-15 09:07:06 -0400721 if (err != 0) {
722 fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err));
723 return err;
724 }
725
726 err = writer.WriteEntityHeader(text, text.length()+1);
727 if (err != 0) {
728 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
729 return err;
730 }
731
732 err = writer.WriteEntityData(text.string(), text.length()+1);
733 if (err != 0) {
734 fprintf(stderr, "write failed for data '%s'\n", text.string());
735 return errno;
736 }
737
738 return err;
739}
740
741int
742backup_helper_test_data_writer()
743{
744 int err;
745 int fd;
746 const char* filename = SCRATCH_DIR "data_writer.data";
747
748 system("rm -r " SCRATCH_DIR);
749 mkdir(SCRATCH_DIR, 0777);
750 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700751
Joe Onorato8d626d62009-05-15 09:07:06 -0400752 fd = creat(filename, 0666);
753 if (fd == -1) {
754 fprintf(stderr, "error creating: %s\n", strerror(errno));
755 return errno;
756 }
757
758 BackupDataWriter writer(fd);
759
760 err = 0;
761 err |= test_write_header_and_entity(writer, "no_padding_");
762 err |= test_write_header_and_entity(writer, "padded_to__3");
763 err |= test_write_header_and_entity(writer, "padded_to_2__");
764 err |= test_write_header_and_entity(writer, "padded_to1");
765
Joe Onoratod502f052009-05-15 18:20:19 -0400766 writer.WriteAppFooter(0x77779999);
Joe Onorato8d626d62009-05-15 09:07:06 -0400767
768 close(fd);
769
770 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
771 if (err != 0) {
772 return err;
773 }
774
775 return err;
776}
777
Joe Onoratod502f052009-05-15 18:20:19 -0400778int
779test_read_header_and_entity(BackupDataReader& reader, const char* str)
780{
781 int err;
782 int bufSize = strlen(str)+1;
783 char* buf = (char*)malloc(bufSize);
784 String8 string;
785 int cookie = 0x11111111;
786 size_t actualSize;
787
788 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
789
790 err = reader.ReadNextHeader();
791 if (err != 0) {
792 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
793 goto done;
794 }
795
796 err = reader.ReadAppHeader(&string, &cookie);
797 if (err != 0) {
798 fprintf(stderr, "ReadAppHeader failed with %s\n", strerror(err));
799 goto done;
800 }
801 if (string != str) {
802 fprintf(stderr, "ReadAppHeader expected packageName '%s' got '%s'\n", str, string.string());
803 err = EINVAL;
804 goto done;
805 }
806 if (cookie != (int)0xaabbccdd) {
807 fprintf(stderr, "ReadAppHeader expected cookie 0x%08x got 0x%08x\n", 0xaabbccdd, cookie);
808 err = EINVAL;
809 goto done;
810 }
811
812 err = reader.ReadNextHeader();
813 if (err != 0) {
814 fprintf(stderr, "ReadNextHeader (for entity header) failed with %s\n", strerror(err));
815 goto done;
816 }
817
818 err = reader.ReadEntityHeader(&string, &actualSize);
819 if (err != 0) {
820 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
821 goto done;
822 }
823 if (string != str) {
824 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
825 err = EINVAL;
826 goto done;
827 }
828 if ((int)actualSize != bufSize) {
829 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
830 actualSize);
831 err = EINVAL;
832 goto done;
833 }
834
835 err = reader.ReadEntityData(buf, bufSize);
836 if (err != NO_ERROR) {
837 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
838 goto done;
839 }
840
841 if (0 != memcmp(buf, str, bufSize)) {
842 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
843 "%02x %02x %02x %02x\n", str, buf[0], buf[1], buf[2], buf[3]);
844 err = EINVAL;
845 goto done;
846 }
847
848 // The next read will confirm whether it got the right amount of data.
849
850done:
851 if (err != NO_ERROR) {
852 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
853 }
854 free(buf);
855 return err;
856}
857
858int
859backup_helper_test_data_reader()
860{
861 int err;
862 int fd;
863 const char* filename = SCRATCH_DIR "data_reader.data";
864
865 system("rm -r " SCRATCH_DIR);
866 mkdir(SCRATCH_DIR, 0777);
867 mkdir(SCRATCH_DIR "data", 0777);
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700868
Joe Onoratod502f052009-05-15 18:20:19 -0400869 fd = creat(filename, 0666);
870 if (fd == -1) {
871 fprintf(stderr, "error creating: %s\n", strerror(errno));
872 return errno;
873 }
874
875 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
876 if (err != DATA_GOLDEN_FILE_SIZE) {
877 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
878 return errno;
879 }
880
881 close(fd);
882
883 fd = open(filename, O_RDONLY);
884 if (fd == -1) {
885 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
886 filename);
887 return errno;
888 }
889
890 {
891 BackupDataReader reader(fd);
892
893 err = 0;
894
895 if (err == NO_ERROR) {
896 err = test_read_header_and_entity(reader, "no_padding_");
897 }
898
899 if (err == NO_ERROR) {
900 err = test_read_header_and_entity(reader, "padded_to__3");
901 }
902
903 if (err == NO_ERROR) {
904 err = test_read_header_and_entity(reader, "padded_to_2__");
905 }
906
907 if (err == NO_ERROR) {
908 err = test_read_header_and_entity(reader, "padded_to1");
909 }
910
911 if (err == NO_ERROR) {
912 err = reader.ReadNextHeader();
913 if (err != 0) {
914 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
915 }
916
917 if (err == NO_ERROR) {
918 int cookie;
919 err |= reader.ReadAppFooter(&cookie);
920 if (cookie != 0x77779999) {
921 fprintf(stderr, "app footer cookie expected=0x%08x actual=0x%08x\n",
922 0x77779999, cookie);
923 err = EINVAL;
924 }
925 }
926 }
927 }
928
929 close(fd);
930
931 return err;
932}
933
Joe Onorato0c4863b2009-05-05 11:50:51 -0700934static int
935get_mod_time(const char* filename, struct timeval times[2])
936{
937 int err;
938 struct stat64 st;
939 err = stat64(filename, &st);
940 if (err != 0) {
941 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
942 return errno;
943 }
944 times[0].tv_sec = st.st_atime;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700945 times[1].tv_sec = st.st_mtime;
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700946
947 // If st_atime is a macro then struct stat64 uses struct timespec
948 // to store the access and modif time values and typically
949 // st_*time_nsec is not defined. In glibc, this is controlled by
950 // __USE_MISC.
951#ifdef __USE_MISC
952#if !defined(st_atime) || defined(st_atime_nsec)
953#error "Check if this __USE_MISC conditional is still needed."
954#endif
955 times[0].tv_usec = st.st_atim.tv_nsec / 1000;
956 times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
957#else
958 times[0].tv_usec = st.st_atime_nsec / 1000;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700959 times[1].tv_usec = st.st_mtime_nsec / 1000;
Nicolas Cataniab4c42652009-05-22 13:41:38 -0700960#endif
961
Joe Onorato0c4863b2009-05-05 11:50:51 -0700962 return 0;
963}
964
965int
966backup_helper_test_files()
967{
968 int err;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700969 int oldSnapshotFD;
Joe Onorato8d626d62009-05-15 09:07:06 -0400970 int dataStreamFD;
971 int newSnapshotFD;
Joe Onorato0c4863b2009-05-05 11:50:51 -0700972
973 system("rm -r " SCRATCH_DIR);
974 mkdir(SCRATCH_DIR, 0777);
975 mkdir(SCRATCH_DIR "data", 0777);
976
977 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
978 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
979 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
980 write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
981 write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
982 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
983
984 char const* files_before[] = {
985 "data/b",
986 "data/c",
987 "data/d",
988 "data/e",
989 "data/f"
990 };
991
Joe Onorato8d626d62009-05-15 09:07:06 -0400992 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
993 if (dataStreamFD == -1) {
994 fprintf(stderr, "error creating: %s\n", strerror(errno));
995 return errno;
996 }
997
Joe Onorato0c4863b2009-05-05 11:50:51 -0700998 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
999 if (newSnapshotFD == -1) {
1000 fprintf(stderr, "error creating: %s\n", strerror(errno));
1001 return errno;
1002 }
Joe Onorato473b6e22009-05-19 13:41:21 -07001003
1004 {
1005 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniab4c42652009-05-22 13:41:38 -07001006
Joe Onorato473b6e22009-05-19 13:41:21 -07001007 err = back_up_files(-1, &dataStream, newSnapshotFD, SCRATCH_DIR, files_before, 5);
1008 if (err != 0) {
1009 return err;
1010 }
Joe Onorato0c4863b2009-05-05 11:50:51 -07001011 }
1012
Joe Onorato8d626d62009-05-15 09:07:06 -04001013 close(dataStreamFD);
Joe Onorato0c4863b2009-05-05 11:50:51 -07001014 close(newSnapshotFD);
1015
1016 sleep(3);
1017
1018 struct timeval d_times[2];
1019 struct timeval e_times[2];
1020
1021 err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1022 err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1023 if (err != 0) {
1024 return err;
1025 }
1026
1027 write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1028 unlink(SCRATCH_DIR "data/c");
1029 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1030 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1031 utimes(SCRATCH_DIR "data/d", d_times);
1032 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1033 utimes(SCRATCH_DIR "data/e", e_times);
1034 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1035 unlink(SCRATCH_DIR "data/f");
Nicolas Cataniab4c42652009-05-22 13:41:38 -07001036
Joe Onorato0c4863b2009-05-05 11:50:51 -07001037 char const* files_after[] = {
1038 "data/a", // added
1039 "data/b", // same
1040 "data/c", // different mod time
1041 "data/d", // different size (same mod time)
1042 "data/e", // different contents (same mod time, same size)
1043 "data/g" // added
1044 };
1045
1046 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1047 if (oldSnapshotFD == -1) {
1048 fprintf(stderr, "error opening: %s\n", strerror(errno));
1049 return errno;
1050 }
1051
Joe Onorato8d626d62009-05-15 09:07:06 -04001052 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1053 if (dataStreamFD == -1) {
1054 fprintf(stderr, "error creating: %s\n", strerror(errno));
1055 return errno;
1056 }
1057
Joe Onorato0c4863b2009-05-05 11:50:51 -07001058 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1059 if (newSnapshotFD == -1) {
1060 fprintf(stderr, "error creating: %s\n", strerror(errno));
1061 return errno;
1062 }
1063
Joe Onorato473b6e22009-05-19 13:41:21 -07001064 {
1065 BackupDataWriter dataStream(dataStreamFD);
Nicolas Cataniab4c42652009-05-22 13:41:38 -07001066
Joe Onorato473b6e22009-05-19 13:41:21 -07001067 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, SCRATCH_DIR,
1068 files_after, 6);
1069 if (err != 0) {
1070 return err;
1071 }
1072}
Joe Onorato0c4863b2009-05-05 11:50:51 -07001073
1074 close(oldSnapshotFD);
Joe Onorato8d626d62009-05-15 09:07:06 -04001075 close(dataStreamFD);
Joe Onorato0c4863b2009-05-05 11:50:51 -07001076 close(newSnapshotFD);
Nicolas Cataniab4c42652009-05-22 13:41:38 -07001077
Joe Onorato0c4863b2009-05-05 11:50:51 -07001078 return 0;
1079}
1080
1081#endif // TEST_BACKUP_HELPERS
Joe Onorato8d626d62009-05-15 09:07:06 -04001082
1083}