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 39 namespace android { 40 41 #define MAGIC0 0x70616e53 // Snap 42 #define MAGIC1 0x656c6946 // File 43 44 /* 45 * File entity data format (v1): 46 * 47 * - 4-byte version number of the metadata, little endian (0x00000001 for v1) 48 * - 12 bytes of metadata 49 * - the file data itself 50 * 51 * i.e. a 16-byte metadata header followed by the raw file data. If the 52 * restore code does not recognize the metadata version, it can still 53 * interpret the file data itself correctly. 54 * 55 * file_metadata_v1: 56 * 57 * - 4 byte version number === 0x00000001 (little endian) 58 * - 4-byte access mode (little-endian) 59 * - undefined (8 bytes) 60 */ 61 62 struct file_metadata_v1 { 63 int version; 64 int mode; 65 int undefined_1; 66 int undefined_2; 67 }; 68 69 const static int CURRENT_METADATA_VERSION = 1; 70 71 #if 1 72 #define LOGP(f, x...) 73 #else 74 #if TEST_BACKUP_HELPERS 75 #define LOGP(f, x...) printf(f "\n", x) 76 #else 77 #define LOGP(x...) LOGD(x) 78 #endif 79 #endif 80 81 const static int ROUND_UP[4] = { 0, 3, 2, 1 }; 82 83 static inline int 84 round_up(int n) 85 { 86 return n + ROUND_UP[n % 4]; 87 } 88 89 static int 90 read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot) 91 { 92 int bytesRead = 0; 93 int amt; 94 SnapshotHeader header; 95 96 amt = read(fd, &header, sizeof(header)); 97 if (amt != sizeof(header)) { 98 return errno; 99 } 100 bytesRead += amt; 101 102 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) { 103 LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1); 104 return 1; 105 } 106 107 for (int i=0; i<header.fileCount; i++) { 108 FileState file; 109 char filenameBuf[128]; 110 111 amt = read(fd, &file, sizeof(FileState)); 112 if (amt != sizeof(FileState)) { 113 LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead); 114 return 1; 115 } 116 bytesRead += amt; 117 118 // filename is not NULL terminated, but it is padded 119 int nameBufSize = round_up(file.nameLen); 120 char* filename = nameBufSize <= (int)sizeof(filenameBuf) 121 ? filenameBuf 122 : (char*)malloc(nameBufSize); 123 amt = read(fd, filename, nameBufSize); 124 if (amt == nameBufSize) { 125 snapshot->add(String8(filename, file.nameLen), file); 126 } 127 bytesRead += amt; 128 if (filename != filenameBuf) { 129 free(filename); 130 } 131 if (amt != nameBufSize) { 132 LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead); 133 return 1; 134 } 135 } 136 137 if (header.totalSize != bytesRead) { 138 LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n", 139 header.totalSize, bytesRead); 140 return 1; 141 } 142 143 return 0; 144 } 145 146 static int 147 write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot) 148 { 149 int fileCount = 0; 150 int bytesWritten = sizeof(SnapshotHeader); 151 // preflight size 152 const int N = snapshot.size(); 153 for (int i=0; i<N; i++) { 154 const FileRec& g = snapshot.valueAt(i); 155 if (!g.deleted) { 156 const String8& name = snapshot.keyAt(i); 157 bytesWritten += sizeof(FileState) + round_up(name.length()); 158 fileCount++; 159 } 160 } 161 162 LOGP("write_snapshot_file fd=%d\n", fd); 163 164 int amt; 165 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten }; 166 167 amt = write(fd, &header, sizeof(header)); 168 if (amt != sizeof(header)) { 169 LOGW("write_snapshot_file error writing header %s", strerror(errno)); 170 return errno; 171 } 172 173 for (int i=0; i<N; i++) { 174 FileRec r = snapshot.valueAt(i); 175 if (!r.deleted) { 176 const String8& name = snapshot.keyAt(i); 177 int nameLen = r.s.nameLen = name.length(); 178 179 amt = write(fd, &r.s, sizeof(FileState)); 180 if (amt != sizeof(FileState)) { 181 LOGW("write_snapshot_file error writing header %s", strerror(errno)); 182 return 1; 183 } 184 185 // filename is not NULL terminated, but it is padded 186 amt = write(fd, name.string(), nameLen); 187 if (amt != nameLen) { 188 LOGW("write_snapshot_file error writing filename %s", strerror(errno)); 189 return 1; 190 } 191 int paddingLen = ROUND_UP[nameLen % 4]; 192 if (paddingLen != 0) { 193 int padding = 0xabababab; 194 amt = write(fd, &padding, paddingLen); 195 if (amt != paddingLen) { 196 LOGW("write_snapshot_file error writing %d bytes of filename padding %s", 197 paddingLen, strerror(errno)); 198 return 1; 199 } 200 } 201 } 202 } 203 204 return 0; 205 } 206 207 static int 208 write_delete_file(BackupDataWriter* dataStream, const String8& key) 209 { 210 LOGP("write_delete_file %s\n", key.string()); 211 return dataStream->WriteEntityHeader(key, -1); 212 } 213 214 static int 215 write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key, 216 char const* realFilename) 217 { 218 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode); 219 220 const int bufsize = 4*1024; 221 int err; 222 int amt; 223 int fileSize; 224 int bytesLeft; 225 file_metadata_v1 metadata; 226 227 char* buf = (char*)malloc(bufsize); 228 int crc = crc32(0L, Z_NULL, 0); 229 230 231 fileSize = lseek(fd, 0, SEEK_END); 232 lseek(fd, 0, SEEK_SET); 233 234 if (sizeof(metadata) != 16) { 235 LOGE("ERROR: metadata block is the wrong size!"); 236 } 237 238 bytesLeft = fileSize + sizeof(metadata); 239 err = dataStream->WriteEntityHeader(key, bytesLeft); 240 if (err != 0) { 241 free(buf); 242 return err; 243 } 244 245 // store the file metadata first 246 metadata.version = tolel(CURRENT_METADATA_VERSION); 247 metadata.mode = tolel(mode); 248 metadata.undefined_1 = metadata.undefined_2 = 0; 249 err = dataStream->WriteEntityData(&metadata, sizeof(metadata)); 250 if (err != 0) { 251 free(buf); 252 return err; 253 } 254 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now 255 256 // now store the file content 257 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) { 258 bytesLeft -= amt; 259 if (bytesLeft < 0) { 260 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised. 261 } 262 err = dataStream->WriteEntityData(buf, amt); 263 if (err != 0) { 264 free(buf); 265 return err; 266 } 267 } 268 if (bytesLeft != 0) { 269 if (bytesLeft > 0) { 270 // Pad out the space we promised in the buffer. We can't corrupt the buffer, 271 // even though the data we're sending is probably bad. 272 memset(buf, 0, bufsize); 273 while (bytesLeft > 0) { 274 amt = bytesLeft < bufsize ? bytesLeft : bufsize; 275 bytesLeft -= amt; 276 err = dataStream->WriteEntityData(buf, amt); 277 if (err != 0) { 278 free(buf); 279 return err; 280 } 281 } 282 } 283 LOGE("write_update_file size mismatch for %s. expected=%d actual=%d." 284 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft); 285 } 286 287 free(buf); 288 return NO_ERROR; 289 } 290 291 static int 292 write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename) 293 { 294 int err; 295 struct stat st; 296 297 err = stat(realFilename, &st); 298 if (err < 0) { 299 return errno; 300 } 301 302 int fd = open(realFilename, O_RDONLY); 303 if (fd == -1) { 304 return errno; 305 } 306 307 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename); 308 close(fd); 309 return err; 310 } 311 312 static int 313 compute_crc32(int fd) 314 { 315 const int bufsize = 4*1024; 316 int amt; 317 318 char* buf = (char*)malloc(bufsize); 319 int crc = crc32(0L, Z_NULL, 0); 320 321 lseek(fd, 0, SEEK_SET); 322 323 while ((amt = read(fd, buf, bufsize)) != 0) { 324 crc = crc32(crc, (Bytef*)buf, amt); 325 } 326 327 free(buf); 328 return crc; 329 } 330 331 int 332 back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD, 333 char const* const* files, char const* const* keys, int fileCount) 334 { 335 int err; 336 KeyedVector<String8,FileState> oldSnapshot; 337 KeyedVector<String8,FileRec> newSnapshot; 338 339 if (oldSnapshotFD != -1) { 340 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot); 341 if (err != 0) { 342 // On an error, treat this as a full backup. 343 oldSnapshot.clear(); 344 } 345 } 346 347 for (int i=0; i<fileCount; i++) { 348 String8 key(keys[i]); 349 FileRec r; 350 char const* file = files[i]; 351 r.file = file; 352 struct stat st; 353 354 err = stat(file, &st); 355 if (err != 0) { 356 r.deleted = true; 357 } else { 358 r.deleted = false; 359 r.s.modTime_sec = st.st_mtime; 360 r.s.modTime_nsec = 0; // workaround sim breakage 361 //r.s.modTime_nsec = st.st_mtime_nsec; 362 r.s.mode = st.st_mode; 363 r.s.size = st.st_size; 364 // we compute the crc32 later down below, when we already have the file open. 365 366 if (newSnapshot.indexOfKey(key) >= 0) { 367 LOGP("back_up_files key already in use '%s'", key.string()); 368 return -1; 369 } 370 } 371 newSnapshot.add(key, r); 372 } 373 374 int n = 0; 375 int N = oldSnapshot.size(); 376 int m = 0; 377 378 while (n<N && m<fileCount) { 379 const String8& p = oldSnapshot.keyAt(n); 380 const String8& q = newSnapshot.keyAt(m); 381 FileRec& g = newSnapshot.editValueAt(m); 382 int cmp = p.compare(q); 383 if (g.deleted || cmp < 0) { 384 // file removed 385 LOGP("file removed: %s", p.string()); 386 g.deleted = true; // They didn't mention the file, but we noticed that it's gone. 387 dataStream->WriteEntityHeader(p, -1); 388 n++; 389 } 390 else if (cmp > 0) { 391 // file added 392 LOGP("file added: %s", g.file.string()); 393 write_update_file(dataStream, q, g.file.string()); 394 m++; 395 } 396 else { 397 // both files exist, check them 398 const FileState& f = oldSnapshot.valueAt(n); 399 400 int fd = open(g.file.string(), O_RDONLY); 401 if (fd < 0) { 402 // We can't open the file. Don't report it as a delete either. Let the 403 // server keep the old version. Maybe they'll be able to deal with it 404 // on restore. 405 LOGP("Unable to open file %s - skipping", g.file.string()); 406 } else { 407 g.s.crc32 = compute_crc32(fd); 408 409 LOGP("%s", q.string()); 410 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x", 411 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32); 412 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x", 413 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32); 414 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec 415 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) { 416 write_update_file(dataStream, fd, g.s.mode, p, g.file.string()); 417 } 418 419 close(fd); 420 } 421 n++; 422 m++; 423 } 424 } 425 426 // these were deleted 427 while (n<N) { 428 dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1); 429 n++; 430 } 431 432 // these were added 433 while (m<fileCount) { 434 const String8& q = newSnapshot.keyAt(m); 435 FileRec& g = newSnapshot.editValueAt(m); 436 write_update_file(dataStream, q, g.file.string()); 437 m++; 438 } 439 440 err = write_snapshot_file(newSnapshotFD, newSnapshot); 441 442 return 0; 443 } 444 445 #define RESTORE_BUF_SIZE (8*1024) 446 447 RestoreHelperBase::RestoreHelperBase() 448 { 449 m_buf = malloc(RESTORE_BUF_SIZE); 450 m_loggedUnknownMetadata = false; 451 } 452 453 RestoreHelperBase::~RestoreHelperBase() 454 { 455 free(m_buf); 456 } 457 458 status_t 459 RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in) 460 { 461 ssize_t err; 462 size_t dataSize; 463 String8 key; 464 int fd; 465 void* buf = m_buf; 466 ssize_t amt; 467 int mode; 468 int crc; 469 struct stat st; 470 FileRec r; 471 472 err = in->ReadEntityHeader(&key, &dataSize); 473 if (err != NO_ERROR) { 474 return err; 475 } 476 477 // Get the metadata block off the head of the file entity and use that to 478 // set up the output file 479 file_metadata_v1 metadata; 480 amt = in->ReadEntityData(&metadata, sizeof(metadata)); 481 if (amt != sizeof(metadata)) { 482 LOGW("Could not read metadata for %s -- %ld / %s", filename.string(), 483 (long)amt, strerror(errno)); 484 return EIO; 485 } 486 metadata.version = fromlel(metadata.version); 487 metadata.mode = fromlel(metadata.mode); 488 if (metadata.version > CURRENT_METADATA_VERSION) { 489 if (!m_loggedUnknownMetadata) { 490 m_loggedUnknownMetadata = true; 491 LOGW("Restoring file with unsupported metadata version %d (currently %d)", 492 metadata.version, CURRENT_METADATA_VERSION); 493 } 494 } 495 mode = metadata.mode; 496 497 // Write the file and compute the crc 498 crc = crc32(0L, Z_NULL, 0); 499 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode); 500 if (fd == -1) { 501 LOGW("Could not open file %s -- %s", filename.string(), strerror(errno)); 502 return errno; 503 } 504 505 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) { 506 err = write(fd, buf, amt); 507 if (err != amt) { 508 close(fd); 509 LOGW("Error '%s' writing '%s'", strerror(errno), filename.string()); 510 return errno; 511 } 512 crc = crc32(crc, (Bytef*)buf, amt); 513 } 514 515 close(fd); 516 517 // Record for the snapshot 518 err = stat(filename.string(), &st); 519 if (err != 0) { 520 LOGW("Error stating file that we just created %s", filename.string()); 521 return errno; 522 } 523 524 r.file = filename; 525 r.deleted = false; 526 r.s.modTime_sec = st.st_mtime; 527 r.s.modTime_nsec = 0; // workaround sim breakage 528 //r.s.modTime_nsec = st.st_mtime_nsec; 529 r.s.mode = st.st_mode; 530 r.s.size = st.st_size; 531 r.s.crc32 = crc; 532 533 m_files.add(key, r); 534 535 return NO_ERROR; 536 } 537 538 status_t 539 RestoreHelperBase::WriteSnapshot(int fd) 540 { 541 return write_snapshot_file(fd, m_files);; 542 } 543 544 #if TEST_BACKUP_HELPERS 545 546 #define SCRATCH_DIR "/data/backup_helper_test/" 547 548 static int 549 write_text_file(const char* path, const char* data) 550 { 551 int amt; 552 int fd; 553 int len; 554 555 fd = creat(path, 0666); 556 if (fd == -1) { 557 fprintf(stderr, "creat %s failed\n", path); 558 return errno; 559 } 560 561 len = strlen(data); 562 amt = write(fd, data, len); 563 if (amt != len) { 564 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path); 565 return errno; 566 } 567 568 close(fd); 569 570 return 0; 571 } 572 573 static int 574 compare_file(const char* path, const unsigned char* data, int len) 575 { 576 int fd; 577 int amt; 578 579 fd = open(path, O_RDONLY); 580 if (fd == -1) { 581 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path); 582 return errno; 583 } 584 585 unsigned char* contents = (unsigned char*)malloc(len); 586 if (contents == NULL) { 587 fprintf(stderr, "malloc(%d) failed\n", len); 588 return ENOMEM; 589 } 590 591 bool sizesMatch = true; 592 amt = lseek(fd, 0, SEEK_END); 593 if (amt != len) { 594 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt); 595 sizesMatch = false; 596 } 597 lseek(fd, 0, SEEK_SET); 598 599 int readLen = amt < len ? amt : len; 600 amt = read(fd, contents, readLen); 601 if (amt != readLen) { 602 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt); 603 } 604 605 bool contentsMatch = true; 606 for (int i=0; i<readLen; i++) { 607 if (data[i] != contents[i]) { 608 if (contentsMatch) { 609 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n"); 610 contentsMatch = false; 611 } 612 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]); 613 } 614 } 615 616 free(contents); 617 return contentsMatch && sizesMatch ? 0 : 1; 618 } 619 620 int 621 backup_helper_test_empty() 622 { 623 int err; 624 int fd; 625 KeyedVector<String8,FileRec> snapshot; 626 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap"; 627 628 system("rm -r " SCRATCH_DIR); 629 mkdir(SCRATCH_DIR, 0777); 630 631 // write 632 fd = creat(filename, 0666); 633 if (fd == -1) { 634 fprintf(stderr, "error creating %s\n", filename); 635 return 1; 636 } 637 638 err = write_snapshot_file(fd, snapshot); 639 640 close(fd); 641 642 if (err != 0) { 643 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err)); 644 return err; 645 } 646 647 static const unsigned char correct_data[] = { 648 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00, 649 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00 650 }; 651 652 err = compare_file(filename, correct_data, sizeof(correct_data)); 653 if (err != 0) { 654 return err; 655 } 656 657 // read 658 fd = open(filename, O_RDONLY); 659 if (fd == -1) { 660 fprintf(stderr, "error opening for read %s\n", filename); 661 return 1; 662 } 663 664 KeyedVector<String8,FileState> readSnapshot; 665 err = read_snapshot_file(fd, &readSnapshot); 666 if (err != 0) { 667 fprintf(stderr, "read_snapshot_file failed %d\n", err); 668 return err; 669 } 670 671 if (readSnapshot.size() != 0) { 672 fprintf(stderr, "readSnapshot should be length 0\n"); 673 return 1; 674 } 675 676 return 0; 677 } 678 679 int 680 backup_helper_test_four() 681 { 682 int err; 683 int fd; 684 KeyedVector<String8,FileRec> snapshot; 685 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap"; 686 687 system("rm -r " SCRATCH_DIR); 688 mkdir(SCRATCH_DIR, 0777); 689 690 // write 691 fd = creat(filename, 0666); 692 if (fd == -1) { 693 fprintf(stderr, "error opening %s\n", filename); 694 return 1; 695 } 696 697 String8 filenames[4]; 698 FileState states[4]; 699 FileRec r; 700 r.deleted = false; 701 702 states[0].modTime_sec = 0xfedcba98; 703 states[0].modTime_nsec = 0xdeadbeef; 704 states[0].mode = 0777; // decimal 511, hex 0x000001ff 705 states[0].size = 0xababbcbc; 706 states[0].crc32 = 0x12345678; 707 states[0].nameLen = -12; 708 r.s = states[0]; 709 filenames[0] = String8("bytes_of_padding"); 710 snapshot.add(filenames[0], r); 711 712 states[1].modTime_sec = 0x93400031; 713 states[1].modTime_nsec = 0xdeadbeef; 714 states[1].mode = 0666; // decimal 438, hex 0x000001b6 715 states[1].size = 0x88557766; 716 states[1].crc32 = 0x22334422; 717 states[1].nameLen = -1; 718 r.s = states[1]; 719 filenames[1] = String8("bytes_of_padding3"); 720 snapshot.add(filenames[1], r); 721 722 states[2].modTime_sec = 0x33221144; 723 states[2].modTime_nsec = 0xdeadbeef; 724 states[2].mode = 0744; // decimal 484, hex 0x000001e4 725 states[2].size = 0x11223344; 726 states[2].crc32 = 0x01122334; 727 states[2].nameLen = 0; 728 r.s = states[2]; 729 filenames[2] = String8("bytes_of_padding_2"); 730 snapshot.add(filenames[2], r); 731 732 states[3].modTime_sec = 0x33221144; 733 states[3].modTime_nsec = 0xdeadbeef; 734 states[3].mode = 0755; // decimal 493, hex 0x000001ed 735 states[3].size = 0x11223344; 736 states[3].crc32 = 0x01122334; 737 states[3].nameLen = 0; 738 r.s = states[3]; 739 filenames[3] = String8("bytes_of_padding__1"); 740 snapshot.add(filenames[3], r); 741 742 err = write_snapshot_file(fd, snapshot); 743 744 close(fd); 745 746 if (err != 0) { 747 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err)); 748 return err; 749 } 750 751 static const unsigned char correct_data[] = { 752 // header 753 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00, 754 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00, 755 756 // bytes_of_padding 757 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde, 758 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab, 759 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00, 760 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, 761 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 762 763 // bytes_of_padding3 764 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde, 765 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88, 766 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 767 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, 768 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 769 0x33, 0xab, 0xab, 0xab, 770 771 // bytes of padding2 772 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde, 773 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11, 774 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00, 775 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, 776 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 777 0x5f, 0x32, 0xab, 0xab, 778 779 // bytes of padding3 780 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde, 781 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11, 782 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00, 783 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, 784 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 785 0x5f, 0x5f, 0x31, 0xab 786 }; 787 788 err = compare_file(filename, correct_data, sizeof(correct_data)); 789 if (err != 0) { 790 return err; 791 } 792 793 // read 794 fd = open(filename, O_RDONLY); 795 if (fd == -1) { 796 fprintf(stderr, "error opening for read %s\n", filename); 797 return 1; 798 } 799 800 801 KeyedVector<String8,FileState> readSnapshot; 802 err = read_snapshot_file(fd, &readSnapshot); 803 if (err != 0) { 804 fprintf(stderr, "read_snapshot_file failed %d\n", err); 805 return err; 806 } 807 808 if (readSnapshot.size() != 4) { 809 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size()); 810 return 1; 811 } 812 813 bool matched = true; 814 for (size_t i=0; i<readSnapshot.size(); i++) { 815 const String8& name = readSnapshot.keyAt(i); 816 const FileState state = readSnapshot.valueAt(i); 817 818 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec 819 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode 820 || states[i].size != state.size || states[i].crc32 != states[i].crc32) { 821 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n" 822 " actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i, 823 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size, 824 states[i].crc32, name.length(), filenames[i].string(), 825 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32, 826 state.nameLen, name.string()); 827 matched = false; 828 } 829 } 830 831 return matched ? 0 : 1; 832 } 833 834 // hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data 835 const unsigned char DATA_GOLDEN_FILE[] = { 836 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00, 837 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70, 838 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00, 839 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 840 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61, 841 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 842 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 843 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc, 844 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 845 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc, 846 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00, 847 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64, 848 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f, 849 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64, 850 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f, 851 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61, 852 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 853 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 854 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64, 855 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00 856 857 }; 858 const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE); 859 860 static int 861 test_write_header_and_entity(BackupDataWriter& writer, const char* str) 862 { 863 int err; 864 String8 text(str); 865 866 err = writer.WriteEntityHeader(text, text.length()+1); 867 if (err != 0) { 868 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err)); 869 return err; 870 } 871 872 err = writer.WriteEntityData(text.string(), text.length()+1); 873 if (err != 0) { 874 fprintf(stderr, "write failed for data '%s'\n", text.string()); 875 return errno; 876 } 877 878 return err; 879 } 880 881 int 882 backup_helper_test_data_writer() 883 { 884 int err; 885 int fd; 886 const char* filename = SCRATCH_DIR "data_writer.data"; 887 888 system("rm -r " SCRATCH_DIR); 889 mkdir(SCRATCH_DIR, 0777); 890 mkdir(SCRATCH_DIR "data", 0777); 891 892 fd = creat(filename, 0666); 893 if (fd == -1) { 894 fprintf(stderr, "error creating: %s\n", strerror(errno)); 895 return errno; 896 } 897 898 BackupDataWriter writer(fd); 899 900 err = 0; 901 err |= test_write_header_and_entity(writer, "no_padding_"); 902 err |= test_write_header_and_entity(writer, "padded_to__3"); 903 err |= test_write_header_and_entity(writer, "padded_to_2__"); 904 err |= test_write_header_and_entity(writer, "padded_to1"); 905 906 close(fd); 907 908 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE); 909 if (err != 0) { 910 return err; 911 } 912 913 return err; 914 } 915 916 int 917 test_read_header_and_entity(BackupDataReader& reader, const char* str) 918 { 919 int err; 920 int bufSize = strlen(str)+1; 921 char* buf = (char*)malloc(bufSize); 922 String8 string; 923 int cookie = 0x11111111; 924 size_t actualSize; 925 bool done; 926 int type; 927 ssize_t nRead; 928 929 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str); 930 931 err = reader.ReadNextHeader(&done, &type); 932 if (done) { 933 fprintf(stderr, "should not be done yet\n"); 934 goto finished; 935 } 936 if (err != 0) { 937 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err)); 938 goto finished; 939 } 940 if (type != BACKUP_HEADER_ENTITY_V1) { 941 err = EINVAL; 942 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1); 943 } 944 945 err = reader.ReadEntityHeader(&string, &actualSize); 946 if (err != 0) { 947 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err)); 948 goto finished; 949 } 950 if (string != str) { 951 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string()); 952 err = EINVAL; 953 goto finished; 954 } 955 if ((int)actualSize != bufSize) { 956 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize, 957 actualSize); 958 err = EINVAL; 959 goto finished; 960 } 961 962 nRead = reader.ReadEntityData(buf, bufSize); 963 if (nRead < 0) { 964 err = reader.Status(); 965 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err)); 966 goto finished; 967 } 968 969 if (0 != memcmp(buf, str, bufSize)) { 970 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with " 971 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3], 972 buf[0], buf[1], buf[2], buf[3]); 973 err = EINVAL; 974 goto finished; 975 } 976 977 // The next read will confirm whether it got the right amount of data. 978 979 finished: 980 if (err != NO_ERROR) { 981 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err)); 982 } 983 free(buf); 984 return err; 985 } 986 987 int 988 backup_helper_test_data_reader() 989 { 990 int err; 991 int fd; 992 const char* filename = SCRATCH_DIR "data_reader.data"; 993 994 system("rm -r " SCRATCH_DIR); 995 mkdir(SCRATCH_DIR, 0777); 996 mkdir(SCRATCH_DIR "data", 0777); 997 998 fd = creat(filename, 0666); 999 if (fd == -1) { 1000 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1001 return errno; 1002 } 1003 1004 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE); 1005 if (err != DATA_GOLDEN_FILE_SIZE) { 1006 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename); 1007 return errno; 1008 } 1009 1010 close(fd); 1011 1012 fd = open(filename, O_RDONLY); 1013 if (fd == -1) { 1014 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno), 1015 filename); 1016 return errno; 1017 } 1018 1019 { 1020 BackupDataReader reader(fd); 1021 1022 err = 0; 1023 1024 if (err == NO_ERROR) { 1025 err = test_read_header_and_entity(reader, "no_padding_"); 1026 } 1027 1028 if (err == NO_ERROR) { 1029 err = test_read_header_and_entity(reader, "padded_to__3"); 1030 } 1031 1032 if (err == NO_ERROR) { 1033 err = test_read_header_and_entity(reader, "padded_to_2__"); 1034 } 1035 1036 if (err == NO_ERROR) { 1037 err = test_read_header_and_entity(reader, "padded_to1"); 1038 } 1039 } 1040 1041 close(fd); 1042 1043 return err; 1044 } 1045 1046 static int 1047 get_mod_time(const char* filename, struct timeval times[2]) 1048 { 1049 int err; 1050 struct stat64 st; 1051 err = stat64(filename, &st); 1052 if (err != 0) { 1053 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno)); 1054 return errno; 1055 } 1056 times[0].tv_sec = st.st_atime; 1057 times[1].tv_sec = st.st_mtime; 1058 1059 // If st_atime is a macro then struct stat64 uses struct timespec 1060 // to store the access and modif time values and typically 1061 // st_*time_nsec is not defined. In glibc, this is controlled by 1062 // __USE_MISC. 1063 #ifdef __USE_MISC 1064 #if !defined(st_atime) || defined(st_atime_nsec) 1065 #error "Check if this __USE_MISC conditional is still needed." 1066 #endif 1067 times[0].tv_usec = st.st_atim.tv_nsec / 1000; 1068 times[1].tv_usec = st.st_mtim.tv_nsec / 1000; 1069 #else 1070 times[0].tv_usec = st.st_atime_nsec / 1000; 1071 times[1].tv_usec = st.st_mtime_nsec / 1000; 1072 #endif 1073 1074 return 0; 1075 } 1076 1077 int 1078 backup_helper_test_files() 1079 { 1080 int err; 1081 int oldSnapshotFD; 1082 int dataStreamFD; 1083 int newSnapshotFD; 1084 1085 system("rm -r " SCRATCH_DIR); 1086 mkdir(SCRATCH_DIR, 0777); 1087 mkdir(SCRATCH_DIR "data", 0777); 1088 1089 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n"); 1090 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n"); 1091 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n"); 1092 write_text_file(SCRATCH_DIR "data/e", "e\nee\n"); 1093 write_text_file(SCRATCH_DIR "data/f", "f\nff\n"); 1094 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n"); 1095 1096 char const* files_before[] = { 1097 SCRATCH_DIR "data/b", 1098 SCRATCH_DIR "data/c", 1099 SCRATCH_DIR "data/d", 1100 SCRATCH_DIR "data/e", 1101 SCRATCH_DIR "data/f" 1102 }; 1103 1104 char const* keys_before[] = { 1105 "data/b", 1106 "data/c", 1107 "data/d", 1108 "data/e", 1109 "data/f" 1110 }; 1111 1112 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666); 1113 if (dataStreamFD == -1) { 1114 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1115 return errno; 1116 } 1117 1118 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666); 1119 if (newSnapshotFD == -1) { 1120 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1121 return errno; 1122 } 1123 1124 { 1125 BackupDataWriter dataStream(dataStreamFD); 1126 1127 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5); 1128 if (err != 0) { 1129 return err; 1130 } 1131 } 1132 1133 close(dataStreamFD); 1134 close(newSnapshotFD); 1135 1136 sleep(3); 1137 1138 struct timeval d_times[2]; 1139 struct timeval e_times[2]; 1140 1141 err = get_mod_time(SCRATCH_DIR "data/d", d_times); 1142 err |= get_mod_time(SCRATCH_DIR "data/e", e_times); 1143 if (err != 0) { 1144 return err; 1145 } 1146 1147 write_text_file(SCRATCH_DIR "data/a", "a\naa\n"); 1148 unlink(SCRATCH_DIR "data/c"); 1149 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n"); 1150 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n"); 1151 utimes(SCRATCH_DIR "data/d", d_times); 1152 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n"); 1153 utimes(SCRATCH_DIR "data/e", e_times); 1154 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n"); 1155 unlink(SCRATCH_DIR "data/f"); 1156 1157 char const* files_after[] = { 1158 SCRATCH_DIR "data/a", // added 1159 SCRATCH_DIR "data/b", // same 1160 SCRATCH_DIR "data/c", // different mod time 1161 SCRATCH_DIR "data/d", // different size (same mod time) 1162 SCRATCH_DIR "data/e", // different contents (same mod time, same size) 1163 SCRATCH_DIR "data/g" // added 1164 }; 1165 1166 char const* keys_after[] = { 1167 "data/a", // added 1168 "data/b", // same 1169 "data/c", // different mod time 1170 "data/d", // different size (same mod time) 1171 "data/e", // different contents (same mod time, same size) 1172 "data/g" // added 1173 }; 1174 1175 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY); 1176 if (oldSnapshotFD == -1) { 1177 fprintf(stderr, "error opening: %s\n", strerror(errno)); 1178 return errno; 1179 } 1180 1181 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666); 1182 if (dataStreamFD == -1) { 1183 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1184 return errno; 1185 } 1186 1187 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666); 1188 if (newSnapshotFD == -1) { 1189 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1190 return errno; 1191 } 1192 1193 { 1194 BackupDataWriter dataStream(dataStreamFD); 1195 1196 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6); 1197 if (err != 0) { 1198 return err; 1199 } 1200 } 1201 1202 close(oldSnapshotFD); 1203 close(dataStreamFD); 1204 close(newSnapshotFD); 1205 1206 return 0; 1207 } 1208 1209 int 1210 backup_helper_test_null_base() 1211 { 1212 int err; 1213 int oldSnapshotFD; 1214 int dataStreamFD; 1215 int newSnapshotFD; 1216 1217 system("rm -r " SCRATCH_DIR); 1218 mkdir(SCRATCH_DIR, 0777); 1219 mkdir(SCRATCH_DIR "data", 0777); 1220 1221 write_text_file(SCRATCH_DIR "data/a", "a\naa\n"); 1222 1223 char const* files[] = { 1224 SCRATCH_DIR "data/a", 1225 }; 1226 1227 char const* keys[] = { 1228 "a", 1229 }; 1230 1231 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666); 1232 if (dataStreamFD == -1) { 1233 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1234 return errno; 1235 } 1236 1237 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666); 1238 if (newSnapshotFD == -1) { 1239 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1240 return errno; 1241 } 1242 1243 { 1244 BackupDataWriter dataStream(dataStreamFD); 1245 1246 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1); 1247 if (err != 0) { 1248 return err; 1249 } 1250 } 1251 1252 close(dataStreamFD); 1253 close(newSnapshotFD); 1254 1255 return 0; 1256 } 1257 1258 int 1259 backup_helper_test_missing_file() 1260 { 1261 int err; 1262 int oldSnapshotFD; 1263 int dataStreamFD; 1264 int newSnapshotFD; 1265 1266 system("rm -r " SCRATCH_DIR); 1267 mkdir(SCRATCH_DIR, 0777); 1268 mkdir(SCRATCH_DIR "data", 0777); 1269 1270 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n"); 1271 1272 char const* files[] = { 1273 SCRATCH_DIR "data/a", 1274 SCRATCH_DIR "data/b", 1275 SCRATCH_DIR "data/c", 1276 }; 1277 1278 char const* keys[] = { 1279 "a", 1280 "b", 1281 "c", 1282 }; 1283 1284 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666); 1285 if (dataStreamFD == -1) { 1286 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1287 return errno; 1288 } 1289 1290 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666); 1291 if (newSnapshotFD == -1) { 1292 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1293 return errno; 1294 } 1295 1296 { 1297 BackupDataWriter dataStream(dataStreamFD); 1298 1299 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1); 1300 if (err != 0) { 1301 return err; 1302 } 1303 } 1304 1305 close(dataStreamFD); 1306 close(newSnapshotFD); 1307 1308 return 0; 1309 } 1310 1311 1312 #endif // TEST_BACKUP_HELPERS 1313 1314 } 1315