BackupHelpers.cpp revision 2e1da32203b7f6df76023f25a7382a31fad6b19d
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/backup_helpers.h> 20 21#include <utils/KeyedVector.h> 22#include <utils/ByteOrder.h> 23#include <utils/String8.h> 24 25#include <errno.h> 26#include <sys/types.h> 27#include <sys/uio.h> 28#include <sys/stat.h> 29#include <stdio.h> 30#include <stdlib.h> 31#include <unistd.h> 32#include <utime.h> 33#include <fcntl.h> 34#include <zlib.h> 35 36#include <cutils/log.h> 37 38namespace android { 39 40#define MAGIC0 0x70616e53 // Snap 41#define MAGIC1 0x656c6946 // File 42 43#if TEST_BACKUP_HELPERS 44#define LOGP(x...) printf(x) 45#else 46#define LOGP(x...) LOGD(x) 47#endif 48 49struct SnapshotHeader { 50 int magic0; 51 int fileCount; 52 int magic1; 53 int totalSize; 54}; 55 56struct FileState { 57 int modTime_sec; 58 int modTime_nsec; 59 int size; 60 int crc32; 61 int nameLen; 62}; 63 64const static int ROUND_UP[4] = { 0, 3, 2, 1 }; 65 66static inline int 67round_up(int n) 68{ 69 return n + ROUND_UP[n % 4]; 70} 71 72static int 73read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot) 74{ 75 int bytesRead = 0; 76 int amt; 77 SnapshotHeader header; 78 79 amt = read(fd, &header, sizeof(header)); 80 if (amt != sizeof(header)) { 81 return errno; 82 } 83 bytesRead += amt; 84 85 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) { 86 LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1); 87 return 1; 88 } 89 90 for (int i=0; i<header.fileCount; i++) { 91 FileState file; 92 char filenameBuf[128]; 93 94 amt = read(fd, &file, sizeof(file)); 95 if (amt != sizeof(file)) { 96 LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead); 97 return 1; 98 } 99 bytesRead += amt; 100 101 // filename is not NULL terminated, but it is padded 102 int nameBufSize = round_up(file.nameLen); 103 char* filename = nameBufSize <= (int)sizeof(filenameBuf) 104 ? filenameBuf 105 : (char*)malloc(nameBufSize); 106 amt = read(fd, filename, nameBufSize); 107 if (amt == nameBufSize) { 108 snapshot->add(String8(filename, file.nameLen), file); 109 } 110 bytesRead += amt; 111 if (filename != filenameBuf) { 112 free(filename); 113 } 114 if (amt != nameBufSize) { 115 LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead); 116 return 1; 117 } 118 } 119 120 if (header.totalSize != bytesRead) { 121 LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n", 122 header.totalSize, bytesRead); 123 return 1; 124 } 125 126 return 0; 127} 128 129static int 130write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot) 131{ 132 int bytesWritten = sizeof(SnapshotHeader); 133 // preflight size 134 const int N = snapshot.size(); 135 for (int i=0; i<N; i++) { 136 const String8& name = snapshot.keyAt(i); 137 bytesWritten += sizeof(FileState) + round_up(name.length()); 138 } 139 140 LOGP("write_snapshot_file fd=%d\n", fd); 141 142 int amt; 143 SnapshotHeader header = { MAGIC0, N, MAGIC1, bytesWritten }; 144 145 amt = write(fd, &header, sizeof(header)); 146 if (amt != sizeof(header)) { 147 LOGW("write_snapshot_file error writing header %s", strerror(errno)); 148 return errno; 149 } 150 151 for (int i=0; i<header.fileCount; i++) { 152 const String8& name = snapshot.keyAt(i); 153 FileState file = snapshot.valueAt(i); 154 int nameLen = file.nameLen = name.length(); 155 156 amt = write(fd, &file, sizeof(file)); 157 if (amt != sizeof(file)) { 158 LOGW("write_snapshot_file error writing header %s", strerror(errno)); 159 return 1; 160 } 161 162 // filename is not NULL terminated, but it is padded 163 amt = write(fd, name.string(), nameLen); 164 if (amt != nameLen) { 165 LOGW("write_snapshot_file error writing filename %s", strerror(errno)); 166 return 1; 167 } 168 int paddingLen = ROUND_UP[nameLen % 4]; 169 if (paddingLen != 0) { 170 int padding = 0xabababab; 171 amt = write(fd, &padding, paddingLen); 172 if (amt != paddingLen) { 173 LOGW("write_snapshot_file error writing %d bytes of filename padding %s", 174 paddingLen, strerror(errno)); 175 return 1; 176 } 177 } 178 } 179 180 return 0; 181} 182 183static int 184write_delete_file(const String8& key) 185{ 186 LOGP("write_delete_file %s\n", key.string()); 187 return 0; 188} 189 190static int 191write_update_file(const String8& realFilename, const String8& key) 192{ 193 LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string()); 194 return 0; 195} 196 197static int 198compute_crc32(const String8& filename) 199{ 200 const int bufsize = 4*1024; 201 int amt; 202 203 int fd = open(filename.string(), O_RDONLY); 204 if (fd == -1) { 205 return -1; 206 } 207 208 char* buf = (char*)malloc(bufsize); 209 int crc = crc32(0L, Z_NULL, 0); 210 211 while ((amt = read(fd, buf, bufsize)) != 0) { 212 crc = crc32(crc, (Bytef*)buf, amt); 213 } 214 215 close(fd); 216 free(buf); 217 218 return crc; 219} 220 221int 222back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, 223 char const* fileBase, char const* const* files, int fileCount) 224{ 225 int err; 226 const String8 base(fileBase); 227 KeyedVector<String8,FileState> oldSnapshot; 228 KeyedVector<String8,FileState> newSnapshot; 229 230 if (oldSnapshotFD != -1) { 231 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot); 232 if (err != 0) { 233 // On an error, treat this as a full backup. 234 oldSnapshot.clear(); 235 } 236 } 237 238 for (int i=0; i<fileCount; i++) { 239 String8 name(files[i]); 240 FileState s; 241 struct stat st; 242 String8 realFilename(base); 243 realFilename.appendPath(name); 244 245 err = stat(realFilename.string(), &st); 246 if (err != 0) { 247 LOGW("Error stating file %s", realFilename.string()); 248 continue; 249 } 250 251 s.modTime_sec = st.st_mtime; 252 s.modTime_nsec = 0; // workaround sim breakage 253 //s.modTime_nsec = st.st_mtime_nsec; 254 s.size = st.st_size; 255 s.crc32 = compute_crc32(realFilename); 256 257 newSnapshot.add(name, s); 258 } 259 260 int n = 0; 261 int N = oldSnapshot.size(); 262 int m = 0; 263 264 while (n<N && m<fileCount) { 265 const String8& p = oldSnapshot.keyAt(n); 266 const String8& q = newSnapshot.keyAt(m); 267 int cmp = p.compare(q); 268 if (cmp > 0) { 269 // file added 270 String8 realFilename(base); 271 realFilename.appendPath(q); 272 LOGP("file added: %s\n", realFilename.string()); 273 write_update_file(realFilename, q); 274 m++; 275 } 276 else if (cmp < 0) { 277 // file removed 278 LOGP("file removed: %s\n", p.string()); 279 write_delete_file(p); 280 n++; 281 } 282 else { 283 // both files exist, check them 284 String8 realFilename(base); 285 realFilename.appendPath(q); 286 const FileState& f = oldSnapshot.valueAt(n); 287 const FileState& g = newSnapshot.valueAt(m); 288 289 LOGP("%s\n", q.string()); 290 LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n", 291 f.modTime_sec, f.modTime_nsec, f.size, f.crc32); 292 LOGP(" old: modTime=%d,%d size=%-3d crc32=0x%08x\n", 293 g.modTime_sec, g.modTime_nsec, g.size, g.crc32); 294 if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec 295 || f.size != g.size || f.crc32 != g.crc32) { 296 write_update_file(realFilename, p); 297 } 298 n++; 299 m++; 300 } 301 } 302 303 // these were deleted 304 while (n<N) { 305 write_delete_file(oldSnapshot.keyAt(n)); 306 n++; 307 } 308 309 // these were added 310 while (m<fileCount) { 311 const String8& q = newSnapshot.keyAt(m); 312 String8 realFilename(base); 313 realFilename.appendPath(q); 314 write_update_file(realFilename, q); 315 m++; 316 } 317 318 err = write_snapshot_file(newSnapshotFD, newSnapshot); 319 320 return 0; 321} 322 323#if TEST_BACKUP_HELPERS 324 325#define SCRATCH_DIR "/data/backup_helper_test/" 326 327static int 328write_text_file(const char* path, const char* data) 329{ 330 int amt; 331 int fd; 332 int len; 333 334 fd = creat(path, 0666); 335 if (fd == -1) { 336 fprintf(stderr, "creat %s failed\n", path); 337 return errno; 338 } 339 340 len = strlen(data); 341 amt = write(fd, data, len); 342 if (amt != len) { 343 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path); 344 return errno; 345 } 346 347 close(fd); 348 349 return 0; 350} 351 352static int 353compare_file(const char* path, const unsigned char* data, int len) 354{ 355 int fd; 356 int amt; 357 358 fd = open(path, O_RDONLY); 359 if (fd == -1) { 360 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path); 361 return errno; 362 } 363 364 unsigned char* contents = (unsigned char*)malloc(len); 365 if (contents == NULL) { 366 fprintf(stderr, "malloc(%d) failed\n", len); 367 return ENOMEM; 368 } 369 370 bool sizesMatch = true; 371 amt = lseek(fd, 0, SEEK_END); 372 if (amt != len) { 373 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt); 374 sizesMatch = false; 375 } 376 lseek(fd, 0, SEEK_SET); 377 378 int readLen = amt < len ? amt : len; 379 amt = read(fd, contents, readLen); 380 if (amt != readLen) { 381 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt); 382 } 383 384 bool contentsMatch = true; 385 for (int i=0; i<readLen; i++) { 386 if (data[i] != contents[i]) { 387 if (contentsMatch) { 388 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n"); 389 contentsMatch = false; 390 } 391 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]); 392 } 393 } 394 395 return contentsMatch && sizesMatch ? 0 : 1; 396} 397 398int 399backup_helper_test_empty() 400{ 401 int err; 402 int fd; 403 KeyedVector<String8,FileState> snapshot; 404 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap"; 405 406 system("rm -r " SCRATCH_DIR); 407 mkdir(SCRATCH_DIR, 0777); 408 409 // write 410 fd = creat(filename, 0666); 411 if (fd == -1) { 412 fprintf(stderr, "error creating %s\n", filename); 413 return 1; 414 } 415 416 err = write_snapshot_file(fd, snapshot); 417 418 close(fd); 419 420 if (err != 0) { 421 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err)); 422 return err; 423 } 424 425 static const unsigned char correct_data[] = { 426 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00, 427 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00 428 }; 429 430 err = compare_file(filename, correct_data, sizeof(correct_data)); 431 if (err != 0) { 432 return err; 433 } 434 435 // read 436 fd = open(filename, O_RDONLY); 437 if (fd == -1) { 438 fprintf(stderr, "error opening for read %s\n", filename); 439 return 1; 440 } 441 442 KeyedVector<String8,FileState> readSnapshot; 443 err = read_snapshot_file(fd, &readSnapshot); 444 if (err != 0) { 445 fprintf(stderr, "read_snapshot_file failed %d\n", err); 446 return err; 447 } 448 449 if (readSnapshot.size() != 0) { 450 fprintf(stderr, "readSnapshot should be length 0\n"); 451 return 1; 452 } 453 454 return 0; 455} 456 457int 458backup_helper_test_four() 459{ 460 int err; 461 int fd; 462 KeyedVector<String8,FileState> snapshot; 463 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap"; 464 465 system("rm -r " SCRATCH_DIR); 466 mkdir(SCRATCH_DIR, 0777); 467 468 // write 469 fd = creat(filename, 0666); 470 if (fd == -1) { 471 fprintf(stderr, "error opening %s\n", filename); 472 return 1; 473 } 474 475 String8 filenames[4]; 476 FileState states[4]; 477 478 states[0].modTime_sec = 0xfedcba98; 479 states[0].modTime_nsec = 0xdeadbeef; 480 states[0].size = 0xababbcbc; 481 states[0].crc32 = 0x12345678; 482 states[0].nameLen = -12; 483 filenames[0] = String8("bytes_of_padding"); 484 snapshot.add(filenames[0], states[0]); 485 486 states[1].modTime_sec = 0x93400031; 487 states[1].modTime_nsec = 0xdeadbeef; 488 states[1].size = 0x88557766; 489 states[1].crc32 = 0x22334422; 490 states[1].nameLen = -1; 491 filenames[1] = String8("bytes_of_padding3"); 492 snapshot.add(filenames[1], states[1]); 493 494 states[2].modTime_sec = 0x33221144; 495 states[2].modTime_nsec = 0xdeadbeef; 496 states[2].size = 0x11223344; 497 states[2].crc32 = 0x01122334; 498 states[2].nameLen = 0; 499 filenames[2] = String8("bytes_of_padding_2"); 500 snapshot.add(filenames[2], states[2]); 501 502 states[3].modTime_sec = 0x33221144; 503 states[3].modTime_nsec = 0xdeadbeef; 504 states[3].size = 0x11223344; 505 states[3].crc32 = 0x01122334; 506 states[3].nameLen = 0; 507 filenames[3] = String8("bytes_of_padding__1"); 508 snapshot.add(filenames[3], states[3]); 509 510 err = write_snapshot_file(fd, snapshot); 511 512 close(fd); 513 514 if (err != 0) { 515 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err)); 516 return err; 517 } 518 519 static const unsigned char correct_data[] = { 520 // header 521 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00, 522 0x46, 0x69, 0x6c, 0x65, 0xac, 0x00, 0x00, 0x00, 523 524 // bytes_of_padding 525 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde, 526 0xbc, 0xbc, 0xab, 0xab, 0x78, 0x56, 0x34, 0x12, 527 0x10, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65, 528 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64, 529 0x64, 0x69, 0x6e, 0x67, 530 531 // bytes_of_padding3 532 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde, 533 0x66, 0x77, 0x55, 0x88, 0x22, 0x44, 0x33, 0x22, 534 0x11, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65, 535 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64, 536 0x64, 0x69, 0x6e, 0x67, 0x33, 0xab, 0xab, 0xab, 537 538 // bytes of padding2 539 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde, 540 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01, 541 0x12, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65, 542 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64, 543 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x32, 0xab, 0xab, 544 545 // bytes of padding3 546 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde, 547 0x44, 0x33, 0x22, 0x11, 0x34, 0x23, 0x12, 0x01, 548 0x13, 0x00, 0x00, 0x00, 0x62, 0x79, 0x74, 0x65, 549 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x61, 0x64, 550 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x5f, 0x31, 0xab 551 }; 552 553 err = compare_file(filename, correct_data, sizeof(correct_data)); 554 if (err != 0) { 555 return err; 556 } 557 558 // read 559 fd = open(filename, O_RDONLY); 560 if (fd == -1) { 561 fprintf(stderr, "error opening for read %s\n", filename); 562 return 1; 563 } 564 565 566 KeyedVector<String8,FileState> readSnapshot; 567 err = read_snapshot_file(fd, &readSnapshot); 568 if (err != 0) { 569 fprintf(stderr, "read_snapshot_file failed %d\n", err); 570 return err; 571 } 572 573 if (readSnapshot.size() != 4) { 574 fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size()); 575 return 1; 576 } 577 578 bool matched = true; 579 for (size_t i=0; i<readSnapshot.size(); i++) { 580 const String8& name = readSnapshot.keyAt(i); 581 const FileState state = readSnapshot.valueAt(i); 582 583 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec 584 || states[i].modTime_nsec != state.modTime_nsec 585 || states[i].size != state.size || states[i].crc32 != states[i].crc32) { 586 fprintf(stderr, "state %d expected={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n" 587 " actual={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n", i, 588 states[i].modTime_sec, states[i].modTime_nsec, states[i].size, states[i].crc32, 589 name.length(), filenames[i].string(), 590 state.modTime_sec, state.modTime_nsec, state.size, state.crc32, state.nameLen, 591 name.string()); 592 matched = false; 593 } 594 } 595 596 return matched ? 0 : 1; 597} 598 599// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data 600const unsigned char DATA_GOLDEN_FILE[] = { 601 0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00, 602 0xdd, 0xcc, 0xbb, 0xaa, 0x6e, 0x6f, 0x5f, 0x70, 603 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00, 604 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00, 605 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70, 606 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00, 607 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 608 0x6e, 0x67, 0x5f, 0x00, 0x41, 0x70, 0x70, 0x31, 609 0x0c, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa, 610 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 611 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc, 612 0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00, 613 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64, 614 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33, 615 0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64, 616 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33, 617 0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31, 618 0x0d, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa, 619 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 620 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc, 621 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00, 622 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64, 623 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f, 624 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64, 625 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f, 626 0x5f, 0x00, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31, 627 0x0a, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa, 628 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 629 0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61, 630 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 631 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 632 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64, 633 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc, 634 0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00, 635 0x99, 0x99, 0x77, 0x77 636}; 637const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE); 638 639static int 640test_write_header_and_entity(BackupDataWriter& writer, const char* str) 641{ 642 int err; 643 String8 text(str); 644 645 err = writer.WriteAppHeader(text, 0xaabbccdd); 646 if (err != 0) { 647 fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err)); 648 return err; 649 } 650 651 err = writer.WriteEntityHeader(text, text.length()+1); 652 if (err != 0) { 653 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err)); 654 return err; 655 } 656 657 err = writer.WriteEntityData(text.string(), text.length()+1); 658 if (err != 0) { 659 fprintf(stderr, "write failed for data '%s'\n", text.string()); 660 return errno; 661 } 662 663 return err; 664} 665 666int 667backup_helper_test_data_writer() 668{ 669 int err; 670 int fd; 671 const char* filename = SCRATCH_DIR "data_writer.data"; 672 673 system("rm -r " SCRATCH_DIR); 674 mkdir(SCRATCH_DIR, 0777); 675 mkdir(SCRATCH_DIR "data", 0777); 676 677 fd = creat(filename, 0666); 678 if (fd == -1) { 679 fprintf(stderr, "error creating: %s\n", strerror(errno)); 680 return errno; 681 } 682 683 BackupDataWriter writer(fd); 684 685 err = 0; 686 err |= test_write_header_and_entity(writer, "no_padding_"); 687 err |= test_write_header_and_entity(writer, "padded_to__3"); 688 err |= test_write_header_and_entity(writer, "padded_to_2__"); 689 err |= test_write_header_and_entity(writer, "padded_to1"); 690 691 writer.WriteAppFooter(0x77779999); 692 693 close(fd); 694 695 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE); 696 if (err != 0) { 697 return err; 698 } 699 700 return err; 701} 702 703int 704test_read_header_and_entity(BackupDataReader& reader, const char* str) 705{ 706 int err; 707 int bufSize = strlen(str)+1; 708 char* buf = (char*)malloc(bufSize); 709 String8 string; 710 int cookie = 0x11111111; 711 size_t actualSize; 712 713 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str); 714 715 err = reader.ReadNextHeader(); 716 if (err != 0) { 717 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err)); 718 goto done; 719 } 720 721 err = reader.ReadAppHeader(&string, &cookie); 722 if (err != 0) { 723 fprintf(stderr, "ReadAppHeader failed with %s\n", strerror(err)); 724 goto done; 725 } 726 if (string != str) { 727 fprintf(stderr, "ReadAppHeader expected packageName '%s' got '%s'\n", str, string.string()); 728 err = EINVAL; 729 goto done; 730 } 731 if (cookie != (int)0xaabbccdd) { 732 fprintf(stderr, "ReadAppHeader expected cookie 0x%08x got 0x%08x\n", 0xaabbccdd, cookie); 733 err = EINVAL; 734 goto done; 735 } 736 737 err = reader.ReadNextHeader(); 738 if (err != 0) { 739 fprintf(stderr, "ReadNextHeader (for entity header) failed with %s\n", strerror(err)); 740 goto done; 741 } 742 743 err = reader.ReadEntityHeader(&string, &actualSize); 744 if (err != 0) { 745 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err)); 746 goto done; 747 } 748 if (string != str) { 749 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string()); 750 err = EINVAL; 751 goto done; 752 } 753 if ((int)actualSize != bufSize) { 754 fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize, 755 actualSize); 756 err = EINVAL; 757 goto done; 758 } 759 760 err = reader.ReadEntityData(buf, bufSize); 761 if (err != NO_ERROR) { 762 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err)); 763 goto done; 764 } 765 766 if (0 != memcmp(buf, str, bufSize)) { 767 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with " 768 "%02x %02x %02x %02x\n", str, buf[0], buf[1], buf[2], buf[3]); 769 err = EINVAL; 770 goto done; 771 } 772 773 // The next read will confirm whether it got the right amount of data. 774 775done: 776 if (err != NO_ERROR) { 777 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err)); 778 } 779 free(buf); 780 return err; 781} 782 783int 784backup_helper_test_data_reader() 785{ 786 int err; 787 int fd; 788 const char* filename = SCRATCH_DIR "data_reader.data"; 789 790 system("rm -r " SCRATCH_DIR); 791 mkdir(SCRATCH_DIR, 0777); 792 mkdir(SCRATCH_DIR "data", 0777); 793 794 fd = creat(filename, 0666); 795 if (fd == -1) { 796 fprintf(stderr, "error creating: %s\n", strerror(errno)); 797 return errno; 798 } 799 800 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE); 801 if (err != DATA_GOLDEN_FILE_SIZE) { 802 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename); 803 return errno; 804 } 805 806 close(fd); 807 808 fd = open(filename, O_RDONLY); 809 if (fd == -1) { 810 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno), 811 filename); 812 return errno; 813 } 814 815 { 816 BackupDataReader reader(fd); 817 818 err = 0; 819 820 if (err == NO_ERROR) { 821 err = test_read_header_and_entity(reader, "no_padding_"); 822 } 823 824 if (err == NO_ERROR) { 825 err = test_read_header_and_entity(reader, "padded_to__3"); 826 } 827 828 if (err == NO_ERROR) { 829 err = test_read_header_and_entity(reader, "padded_to_2__"); 830 } 831 832 if (err == NO_ERROR) { 833 err = test_read_header_and_entity(reader, "padded_to1"); 834 } 835 836 if (err == NO_ERROR) { 837 err = reader.ReadNextHeader(); 838 if (err != 0) { 839 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err)); 840 } 841 842 if (err == NO_ERROR) { 843 int cookie; 844 err |= reader.ReadAppFooter(&cookie); 845 if (cookie != 0x77779999) { 846 fprintf(stderr, "app footer cookie expected=0x%08x actual=0x%08x\n", 847 0x77779999, cookie); 848 err = EINVAL; 849 } 850 } 851 } 852 } 853 854 close(fd); 855 856 return err; 857} 858 859static int 860get_mod_time(const char* filename, struct timeval times[2]) 861{ 862 int err; 863 struct stat64 st; 864 err = stat64(filename, &st); 865 if (err != 0) { 866 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno)); 867 return errno; 868 } 869 times[0].tv_sec = st.st_atime; 870 times[0].tv_usec = st.st_atime_nsec / 1000; 871 times[1].tv_sec = st.st_mtime; 872 times[1].tv_usec = st.st_mtime_nsec / 1000; 873 return 0; 874} 875 876int 877backup_helper_test_files() 878{ 879 int err; 880 int oldSnapshotFD; 881 int dataStreamFD; 882 int newSnapshotFD; 883 884 system("rm -r " SCRATCH_DIR); 885 mkdir(SCRATCH_DIR, 0777); 886 mkdir(SCRATCH_DIR "data", 0777); 887 888 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n"); 889 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n"); 890 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n"); 891 write_text_file(SCRATCH_DIR "data/e", "e\nee\n"); 892 write_text_file(SCRATCH_DIR "data/f", "f\nff\n"); 893 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n"); 894 895 char const* files_before[] = { 896 "data/b", 897 "data/c", 898 "data/d", 899 "data/e", 900 "data/f" 901 }; 902 903 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666); 904 if (dataStreamFD == -1) { 905 fprintf(stderr, "error creating: %s\n", strerror(errno)); 906 return errno; 907 } 908 909 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666); 910 if (newSnapshotFD == -1) { 911 fprintf(stderr, "error creating: %s\n", strerror(errno)); 912 return errno; 913 } 914 915 err = back_up_files(-1, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_before, 5); 916 if (err != 0) { 917 return err; 918 } 919 920 close(dataStreamFD); 921 close(newSnapshotFD); 922 923 sleep(3); 924 925 struct timeval d_times[2]; 926 struct timeval e_times[2]; 927 928 err = get_mod_time(SCRATCH_DIR "data/d", d_times); 929 err |= get_mod_time(SCRATCH_DIR "data/e", e_times); 930 if (err != 0) { 931 return err; 932 } 933 934 write_text_file(SCRATCH_DIR "data/a", "a\naa\n"); 935 unlink(SCRATCH_DIR "data/c"); 936 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n"); 937 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n"); 938 utimes(SCRATCH_DIR "data/d", d_times); 939 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n"); 940 utimes(SCRATCH_DIR "data/e", e_times); 941 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n"); 942 unlink(SCRATCH_DIR "data/f"); 943 944 char const* files_after[] = { 945 "data/a", // added 946 "data/b", // same 947 "data/c", // different mod time 948 "data/d", // different size (same mod time) 949 "data/e", // different contents (same mod time, same size) 950 "data/g" // added 951 }; 952 953 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY); 954 if (oldSnapshotFD == -1) { 955 fprintf(stderr, "error opening: %s\n", strerror(errno)); 956 return errno; 957 } 958 959 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666); 960 if (dataStreamFD == -1) { 961 fprintf(stderr, "error creating: %s\n", strerror(errno)); 962 return errno; 963 } 964 965 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666); 966 if (newSnapshotFD == -1) { 967 fprintf(stderr, "error creating: %s\n", strerror(errno)); 968 return errno; 969 } 970 971 err = back_up_files(oldSnapshotFD, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_after, 6); 972 if (err != 0) { 973 return err; 974 } 975 976 close(oldSnapshotFD); 977 close(dataStreamFD); 978 close(newSnapshotFD); 979 980 return 0; 981} 982 983#endif // TEST_BACKUP_HELPERS 984 985} 986