BackupHelpers.cpp revision 4535e40544aeb957d44fad75fbe5676effe03689
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 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 603 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61, 604 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 605 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 606 0x6e, 0x67, 0x5f, 0x00, 0x6e, 0x6f, 0x5f, 0x70, 607 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00, 608 0x41, 0x70, 0x70, 0x31, 0x0c, 0x00, 0x00, 0x00, 609 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 610 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc, 611 0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00, 612 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64, 613 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33, 614 0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64, 615 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33, 616 0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31, 617 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64, 618 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f, 619 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61, 620 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 621 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 622 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc, 623 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 624 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc, 625 0x41, 0x70, 0x70, 0x31, 0x0a, 0x00, 0x00, 0x00, 626 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 627 0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61, 628 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 629 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 630 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64, 631 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc, 632 0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00, 633}; 634const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE); 635 636static int 637test_write_header_and_entity(BackupDataWriter& writer, const char* str) 638{ 639 int err; 640 String8 text(str); 641 642 err = writer.WriteAppHeader(text); 643 if (err != 0) { 644 fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err)); 645 return err; 646 } 647 648 err = writer.WriteEntityHeader(text, text.length()+1); 649 if (err != 0) { 650 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err)); 651 return err; 652 } 653 654 err = writer.WriteEntityData(text.string(), text.length()+1); 655 if (err != 0) { 656 fprintf(stderr, "write failed for data '%s'\n", text.string()); 657 return errno; 658 } 659 660 return err; 661} 662 663int 664backup_helper_test_data_writer() 665{ 666 int err; 667 int fd; 668 const char* filename = SCRATCH_DIR "data_writer.data"; 669 670 system("rm -r " SCRATCH_DIR); 671 mkdir(SCRATCH_DIR, 0777); 672 mkdir(SCRATCH_DIR "data", 0777); 673 674 fd = creat(filename, 0666); 675 if (fd == -1) { 676 fprintf(stderr, "error creating: %s\n", strerror(errno)); 677 return errno; 678 } 679 680 BackupDataWriter writer(fd); 681 682 err = 0; 683 err |= test_write_header_and_entity(writer, "no_padding_"); 684 err |= test_write_header_and_entity(writer, "padded_to__3"); 685 err |= test_write_header_and_entity(writer, "padded_to_2__"); 686 err |= test_write_header_and_entity(writer, "padded_to1"); 687 688 writer.WriteAppFooter(); 689 690 close(fd); 691 692 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE); 693 if (err != 0) { 694 return err; 695 } 696 697 return err; 698} 699 700static int 701get_mod_time(const char* filename, struct timeval times[2]) 702{ 703 int err; 704 struct stat64 st; 705 err = stat64(filename, &st); 706 if (err != 0) { 707 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno)); 708 return errno; 709 } 710 times[0].tv_sec = st.st_atime; 711 times[0].tv_usec = st.st_atime_nsec / 1000; 712 times[1].tv_sec = st.st_mtime; 713 times[1].tv_usec = st.st_mtime_nsec / 1000; 714 return 0; 715} 716 717int 718backup_helper_test_files() 719{ 720 int err; 721 int oldSnapshotFD; 722 int dataStreamFD; 723 int newSnapshotFD; 724 725 system("rm -r " SCRATCH_DIR); 726 mkdir(SCRATCH_DIR, 0777); 727 mkdir(SCRATCH_DIR "data", 0777); 728 729 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n"); 730 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n"); 731 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n"); 732 write_text_file(SCRATCH_DIR "data/e", "e\nee\n"); 733 write_text_file(SCRATCH_DIR "data/f", "f\nff\n"); 734 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n"); 735 736 char const* files_before[] = { 737 "data/b", 738 "data/c", 739 "data/d", 740 "data/e", 741 "data/f" 742 }; 743 744 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666); 745 if (dataStreamFD == -1) { 746 fprintf(stderr, "error creating: %s\n", strerror(errno)); 747 return errno; 748 } 749 750 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666); 751 if (newSnapshotFD == -1) { 752 fprintf(stderr, "error creating: %s\n", strerror(errno)); 753 return errno; 754 } 755 756 err = back_up_files(-1, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_before, 5); 757 if (err != 0) { 758 return err; 759 } 760 761 close(dataStreamFD); 762 close(newSnapshotFD); 763 764 sleep(3); 765 766 struct timeval d_times[2]; 767 struct timeval e_times[2]; 768 769 err = get_mod_time(SCRATCH_DIR "data/d", d_times); 770 err |= get_mod_time(SCRATCH_DIR "data/e", e_times); 771 if (err != 0) { 772 return err; 773 } 774 775 write_text_file(SCRATCH_DIR "data/a", "a\naa\n"); 776 unlink(SCRATCH_DIR "data/c"); 777 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n"); 778 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n"); 779 utimes(SCRATCH_DIR "data/d", d_times); 780 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n"); 781 utimes(SCRATCH_DIR "data/e", e_times); 782 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n"); 783 unlink(SCRATCH_DIR "data/f"); 784 785 char const* files_after[] = { 786 "data/a", // added 787 "data/b", // same 788 "data/c", // different mod time 789 "data/d", // different size (same mod time) 790 "data/e", // different contents (same mod time, same size) 791 "data/g" // added 792 }; 793 794 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY); 795 if (oldSnapshotFD == -1) { 796 fprintf(stderr, "error opening: %s\n", strerror(errno)); 797 return errno; 798 } 799 800 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666); 801 if (dataStreamFD == -1) { 802 fprintf(stderr, "error creating: %s\n", strerror(errno)); 803 return errno; 804 } 805 806 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666); 807 if (newSnapshotFD == -1) { 808 fprintf(stderr, "error creating: %s\n", strerror(errno)); 809 return errno; 810 } 811 812 err = back_up_files(oldSnapshotFD, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_after, 6); 813 if (err != 0) { 814 return err; 815 } 816 817 close(oldSnapshotFD); 818 close(dataStreamFD); 819 close(newSnapshotFD); 820 821 return 0; 822} 823 824#endif // TEST_BACKUP_HELPERS 825 826} 827