BackupHelpers.cpp revision 0032ce80ac127e6bfb25d727162eee4af208dc77
1/* 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 17#define LOG_TAG "file_backup_helper" 18 19#include <utils/BackupHelpers.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 <sys/time.h> // for utimes 30#include <stdio.h> 31#include <stdlib.h> 32#include <unistd.h> 33#include <utime.h> 34#include <fcntl.h> 35#include <zlib.h> 36 37#include <cutils/log.h> 38 39namespace android { 40 41#define MAGIC0 0x70616e53 // Snap 42#define MAGIC1 0x656c6946 // File 43 44#if 0 // TEST_BACKUP_HELPERS 45#define LOGP(x...) printf(x) 46#else 47#define LOGP(x...) LOGD(x) 48#endif 49 50struct 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 141 LOGP("write_snapshot_file fd=%d\n", fd); 142 143 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 185write_delete_file(BackupDataWriter* dataStream, const String8& key) 186{ 187 LOGP("write_delete_file %s\n", key.string()); 188 return dataStream->WriteEntityHeader(key, -1); 189} 190 191static int 192write_update_file(BackupDataWriter* dataStream, int fd, const String8& key, 193 const String8& realFilename) 194{ 195 LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string()); 196 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; 247} 248 249static int 250write_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) 264{ 265 const int bufsize = 4*1024; 266 int amt; 267 268 char* buf = (char*)malloc(bufsize); 269 int crc = crc32(0L, Z_NULL, 0); 270 271 lseek(fd, 0, SEEK_SET); 272 273 while ((amt = read(fd, buf, bufsize)) != 0) { 274 crc = crc32(crc, (Bytef*)buf, amt); 275 } 276 277 free(buf); 278 279 return crc; 280} 281 282int 283back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD, 284 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; 313 s.modTime_nsec = 0; // workaround sim breakage 314 //s.modTime_nsec = st.st_mtime_nsec; 315 s.size = st.st_size; 316 317 // we compute the crc32 later down below, when we already have the file open. 318 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); 334 LOGP("file added: %s\n", realFilename.string()); 335 write_update_file(dataStream, q, realFilename); 336 m++; 337 } 338 else if (cmp < 0) { 339 // file removed 340 LOGP("file removed: %s\n", p.string()); 341 dataStream->WriteEntityHeader(p, -1); 342 n++; 343 } 344 else { 345 346 // both files exist, check them 347 String8 realFilename(base); 348 realFilename.appendPath(q); 349 const FileState& f = oldSnapshot.valueAt(n); 350 FileState& g = newSnapshot.editValueAt(m); 351 352 int fd = open(realFilename.string(), O_RDONLY); 353 if (fd < 0) { 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 LOGP("Unable to open file %s - skipping", realFilename.string()); 358 } 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); 372 } 373 n++; 374 m++; 375 } 376 } 377 378 // these were deleted 379 while (n<N) { 380 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1); 381 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); 389 write_update_file(dataStream, q, realFilename); 390 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, 612 613 // 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, 619 620 // 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 } 632 633 // 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 } 670 671 return matched ? 0 : 1; 672} 673 674// 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, 677 0xdd, 0xcc, 0xbb, 0xaa, 0x6e, 0x6f, 0x5f, 0x70, 678 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00, 679 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, 685 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, 693 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, 698 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f, 699 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, 703 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, 710 0x99, 0x99, 0x77, 0x77 711}; 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 720 err = writer.WriteAppHeader(text, 0xaabbccdd); 721 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); 751 752 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 766 writer.WriteAppFooter(0x77779999); 767 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 778int 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); 868 869 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 934static 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; 945 times[1].tv_sec = st.st_mtime; 946 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; 959 times[1].tv_usec = st.st_mtime_nsec / 1000; 960#endif 961 962 return 0; 963} 964 965int 966backup_helper_test_files() 967{ 968 int err; 969 int oldSnapshotFD; 970 int dataStreamFD; 971 int newSnapshotFD; 972 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 992 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 998 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666); 999 if (newSnapshotFD == -1) { 1000 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1001 return errno; 1002 } 1003 1004 { 1005 BackupDataWriter dataStream(dataStreamFD); 1006 1007 err = back_up_files(-1, &dataStream, newSnapshotFD, SCRATCH_DIR, files_before, 5); 1008 if (err != 0) { 1009 return err; 1010 } 1011 } 1012 1013 close(dataStreamFD); 1014 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"); 1036 1037 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 1052 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 1058 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 1064 { 1065 BackupDataWriter dataStream(dataStreamFD); 1066 1067 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, SCRATCH_DIR, 1068 files_after, 6); 1069 if (err != 0) { 1070 return err; 1071 } 1072} 1073 1074 close(oldSnapshotFD); 1075 close(dataStreamFD); 1076 close(newSnapshotFD); 1077 1078 return 0; 1079} 1080 1081#endif // TEST_BACKUP_HELPERS 1082 1083} 1084