BackupHelpers.cpp revision 33d0392d3e4c42a7d48e8bd1210a1525aca8c2d3
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 <androidfw/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/* 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 62struct file_metadata_v1 { 63 int version; 64 int mode; 65 int undefined_1; 66 int undefined_2; 67}; 68 69const static int CURRENT_METADATA_VERSION = 1; 70 71static const bool kIsDebug = false; 72#if TEST_BACKUP_HELPERS 73#define LOGP(f, x...) if (kIsDebug) printf(f "\n", x) 74#else 75#define LOGP(x...) if (kIsDebug) ALOGD(x) 76#endif 77 78const static int ROUND_UP[4] = { 0, 3, 2, 1 }; 79 80static inline int 81round_up(int n) 82{ 83 return n + ROUND_UP[n % 4]; 84} 85 86static int 87read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot) 88{ 89 int bytesRead = 0; 90 int amt; 91 SnapshotHeader header; 92 93 amt = read(fd, &header, sizeof(header)); 94 if (amt != sizeof(header)) { 95 return errno; 96 } 97 bytesRead += amt; 98 99 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) { 100 ALOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1); 101 return 1; 102 } 103 104 for (int i=0; i<header.fileCount; i++) { 105 FileState file; 106 char filenameBuf[128]; 107 108 amt = read(fd, &file, sizeof(FileState)); 109 if (amt != sizeof(FileState)) { 110 ALOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead); 111 return 1; 112 } 113 bytesRead += amt; 114 115 // filename is not NULL terminated, but it is padded 116 int nameBufSize = round_up(file.nameLen); 117 char* filename = nameBufSize <= (int)sizeof(filenameBuf) 118 ? filenameBuf 119 : (char*)malloc(nameBufSize); 120 amt = read(fd, filename, nameBufSize); 121 if (amt == nameBufSize) { 122 snapshot->add(String8(filename, file.nameLen), file); 123 } 124 bytesRead += amt; 125 if (filename != filenameBuf) { 126 free(filename); 127 } 128 if (amt != nameBufSize) { 129 ALOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead); 130 return 1; 131 } 132 } 133 134 if (header.totalSize != bytesRead) { 135 ALOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n", 136 header.totalSize, bytesRead); 137 return 1; 138 } 139 140 return 0; 141} 142 143static int 144write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot) 145{ 146 int fileCount = 0; 147 int bytesWritten = sizeof(SnapshotHeader); 148 // preflight size 149 const int N = snapshot.size(); 150 for (int i=0; i<N; i++) { 151 const FileRec& g = snapshot.valueAt(i); 152 if (!g.deleted) { 153 const String8& name = snapshot.keyAt(i); 154 bytesWritten += sizeof(FileState) + round_up(name.length()); 155 fileCount++; 156 } 157 } 158 159 LOGP("write_snapshot_file fd=%d\n", fd); 160 161 int amt; 162 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten }; 163 164 amt = write(fd, &header, sizeof(header)); 165 if (amt != sizeof(header)) { 166 ALOGW("write_snapshot_file error writing header %s", strerror(errno)); 167 return errno; 168 } 169 170 for (int i=0; i<N; i++) { 171 FileRec r = snapshot.valueAt(i); 172 if (!r.deleted) { 173 const String8& name = snapshot.keyAt(i); 174 int nameLen = r.s.nameLen = name.length(); 175 176 amt = write(fd, &r.s, sizeof(FileState)); 177 if (amt != sizeof(FileState)) { 178 ALOGW("write_snapshot_file error writing header %s", strerror(errno)); 179 return 1; 180 } 181 182 // filename is not NULL terminated, but it is padded 183 amt = write(fd, name.string(), nameLen); 184 if (amt != nameLen) { 185 ALOGW("write_snapshot_file error writing filename %s", strerror(errno)); 186 return 1; 187 } 188 int paddingLen = ROUND_UP[nameLen % 4]; 189 if (paddingLen != 0) { 190 int padding = 0xabababab; 191 amt = write(fd, &padding, paddingLen); 192 if (amt != paddingLen) { 193 ALOGW("write_snapshot_file error writing %d bytes of filename padding %s", 194 paddingLen, strerror(errno)); 195 return 1; 196 } 197 } 198 } 199 } 200 201 return 0; 202} 203 204static int 205write_delete_file(BackupDataWriter* dataStream, const String8& key) 206{ 207 LOGP("write_delete_file %s\n", key.string()); 208 return dataStream->WriteEntityHeader(key, -1); 209} 210 211static int 212write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key, 213 char const* realFilename) 214{ 215 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode); 216 217 const int bufsize = 4*1024; 218 int err; 219 int amt; 220 int fileSize; 221 int bytesLeft; 222 file_metadata_v1 metadata; 223 224 char* buf = (char*)malloc(bufsize); 225 226 fileSize = lseek(fd, 0, SEEK_END); 227 lseek(fd, 0, SEEK_SET); 228 229 if (sizeof(metadata) != 16) { 230 ALOGE("ERROR: metadata block is the wrong size!"); 231 } 232 233 bytesLeft = fileSize + sizeof(metadata); 234 err = dataStream->WriteEntityHeader(key, bytesLeft); 235 if (err != 0) { 236 free(buf); 237 return err; 238 } 239 240 // store the file metadata first 241 metadata.version = tolel(CURRENT_METADATA_VERSION); 242 metadata.mode = tolel(mode); 243 metadata.undefined_1 = metadata.undefined_2 = 0; 244 err = dataStream->WriteEntityData(&metadata, sizeof(metadata)); 245 if (err != 0) { 246 free(buf); 247 return err; 248 } 249 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now 250 251 // now store the file content 252 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) { 253 bytesLeft -= amt; 254 if (bytesLeft < 0) { 255 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised. 256 } 257 err = dataStream->WriteEntityData(buf, amt); 258 if (err != 0) { 259 free(buf); 260 return err; 261 } 262 } 263 if (bytesLeft != 0) { 264 if (bytesLeft > 0) { 265 // Pad out the space we promised in the buffer. We can't corrupt the buffer, 266 // even though the data we're sending is probably bad. 267 memset(buf, 0, bufsize); 268 while (bytesLeft > 0) { 269 amt = bytesLeft < bufsize ? bytesLeft : bufsize; 270 bytesLeft -= amt; 271 err = dataStream->WriteEntityData(buf, amt); 272 if (err != 0) { 273 free(buf); 274 return err; 275 } 276 } 277 } 278 ALOGE("write_update_file size mismatch for %s. expected=%d actual=%d." 279 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft); 280 } 281 282 free(buf); 283 return NO_ERROR; 284} 285 286static int 287write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename) 288{ 289 int err; 290 struct stat st; 291 292 err = stat(realFilename, &st); 293 if (err < 0) { 294 return errno; 295 } 296 297 int fd = open(realFilename, O_RDONLY); 298 if (fd == -1) { 299 return errno; 300 } 301 302 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename); 303 close(fd); 304 return err; 305} 306 307static int 308compute_crc32(const char* file, FileRec* out) { 309 int fd = open(file, O_RDONLY); 310 if (fd < 0) { 311 return -1; 312 } 313 314 const int bufsize = 4*1024; 315 int amt; 316 317 char* buf = (char*)malloc(bufsize); 318 int crc = crc32(0L, Z_NULL, 0); 319 320 lseek(fd, 0, SEEK_SET); 321 322 while ((amt = read(fd, buf, bufsize)) != 0) { 323 crc = crc32(crc, (Bytef*)buf, amt); 324 } 325 326 close(fd); 327 free(buf); 328 329 out->s.crc32 = crc; 330 return NO_ERROR; 331} 332 333int 334back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD, 335 char const* const* files, char const* const* keys, int fileCount) 336{ 337 int err; 338 KeyedVector<String8,FileState> oldSnapshot; 339 KeyedVector<String8,FileRec> newSnapshot; 340 341 if (oldSnapshotFD != -1) { 342 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot); 343 if (err != 0) { 344 // On an error, treat this as a full backup. 345 oldSnapshot.clear(); 346 } 347 } 348 349 for (int i=0; i<fileCount; i++) { 350 String8 key(keys[i]); 351 FileRec r; 352 char const* file = files[i]; 353 r.file = file; 354 struct stat st; 355 356 err = stat(file, &st); 357 if (err != 0) { 358 // not found => treat as deleted 359 continue; 360 } else { 361 r.deleted = false; 362 r.s.modTime_sec = st.st_mtime; 363 r.s.modTime_nsec = 0; // workaround sim breakage 364 //r.s.modTime_nsec = st.st_mtime_nsec; 365 r.s.mode = st.st_mode; 366 r.s.size = st.st_size; 367 368 if (newSnapshot.indexOfKey(key) >= 0) { 369 LOGP("back_up_files key already in use '%s'", key.string()); 370 return -1; 371 } 372 373 // compute the CRC 374 if (compute_crc32(file, &r) != NO_ERROR) { 375 ALOGW("Unable to open file %s", file); 376 continue; 377 } 378 } 379 newSnapshot.add(key, r); 380 } 381 382 int n = 0; 383 int N = oldSnapshot.size(); 384 int m = 0; 385 int M = newSnapshot.size(); 386 387 while (n<N && m<M) { 388 const String8& p = oldSnapshot.keyAt(n); 389 const String8& q = newSnapshot.keyAt(m); 390 FileRec& g = newSnapshot.editValueAt(m); 391 int cmp = p.compare(q); 392 if (cmp < 0) { 393 // file present in oldSnapshot, but not present in newSnapshot 394 LOGP("file removed: %s", p.string()); 395 write_delete_file(dataStream, p); 396 n++; 397 } else if (cmp > 0) { 398 // file added 399 LOGP("file added: %s crc=0x%08x", g.file.string(), g.s.crc32); 400 write_update_file(dataStream, q, g.file.string()); 401 m++; 402 } else { 403 // same file exists in both old and new; check whether to update 404 const FileState& f = oldSnapshot.valueAt(n); 405 406 LOGP("%s", q.string()); 407 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x", 408 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32); 409 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x", 410 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32); 411 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec 412 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) { 413 int fd = open(g.file.string(), O_RDONLY); 414 if (fd < 0) { 415 ALOGE("Unable to read file for backup: %s", g.file.string()); 416 } else { 417 write_update_file(dataStream, fd, g.s.mode, p, g.file.string()); 418 close(fd); 419 } 420 } 421 n++; 422 m++; 423 } 424 } 425 426 // these were deleted 427 while (n<N) { 428 write_delete_file(dataStream, oldSnapshot.keyAt(n)); 429 n++; 430 } 431 432 // these were added 433 while (m<M) { 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 445static void calc_tar_checksum(char* buf) { 446 // [ 148 : 8 ] checksum -- to be calculated with this field as space chars 447 memset(buf + 148, ' ', 8); 448 449 uint16_t sum = 0; 450 for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) { 451 sum += *p; 452 } 453 454 // Now write the real checksum value: 455 // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC 456 sprintf(buf + 148, "%06o", sum); // the trailing space is already in place 457} 458 459// Returns number of bytes written 460static int write_pax_header_entry(char* buf, const char* key, const char* value) { 461 // start with the size of "1 key=value\n" 462 int len = strlen(key) + strlen(value) + 4; 463 if (len > 9) len++; 464 if (len > 99) len++; 465 if (len > 999) len++; 466 // since PATH_MAX is 4096 we don't expect to have to generate any single 467 // header entry longer than 9999 characters 468 469 return sprintf(buf, "%d %s=%s\n", len, key, value); 470} 471 472// Wire format to the backup manager service is chunked: each chunk is prefixed by 473// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD. 474void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) { 475 uint32_t chunk_size_no = htonl(size); 476 writer->WriteEntityData(&chunk_size_no, 4); 477 if (size != 0) writer->WriteEntityData(buffer, size); 478} 479 480int write_tarfile(const String8& packageName, const String8& domain, 481 const String8& rootpath, const String8& filepath, BackupDataWriter* writer) 482{ 483 // In the output stream everything is stored relative to the root 484 const char* relstart = filepath.string() + rootpath.length(); 485 if (*relstart == '/') relstart++; // won't be true when path == rootpath 486 String8 relpath(relstart); 487 488 // If relpath is empty, it means this is the top of one of the standard named 489 // domain directories, so we should just skip it 490 if (relpath.length() == 0) { 491 return 0; 492 } 493 494 // Too long a name for the ustar format? 495 // "apps/" + packagename + '/' + domainpath < 155 chars 496 // relpath < 100 chars 497 bool needExtended = false; 498 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) { 499 needExtended = true; 500 } 501 502 // Non-7bit-clean path also means needing pax extended format 503 if (!needExtended) { 504 for (size_t i = 0; i < filepath.length(); i++) { 505 if ((filepath[i] & 0x80) != 0) { 506 needExtended = true; 507 break; 508 } 509 } 510 } 511 512 int err = 0; 513 struct stat64 s; 514 if (lstat64(filepath.string(), &s) != 0) { 515 err = errno; 516 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string()); 517 return err; 518 } 519 520 String8 fullname; // for pax later on 521 String8 prefix; 522 523 const int isdir = S_ISDIR(s.st_mode); 524 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream 525 526 // !!! TODO: use mmap when possible to avoid churning the buffer cache 527 // !!! TODO: this will break with symlinks; need to use readlink(2) 528 int fd = open(filepath.string(), O_RDONLY); 529 if (fd < 0) { 530 err = errno; 531 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string()); 532 return err; 533 } 534 535 // read/write up to this much at a time. 536 const size_t BUFSIZE = 32 * 1024; 537 char* buf = (char *)calloc(1,BUFSIZE); 538 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch 539 char* paxData = buf + 1024; 540 541 if (buf == NULL) { 542 ALOGE("Out of mem allocating transfer buffer"); 543 err = ENOMEM; 544 goto done; 545 } 546 547 // Magic fields for the ustar file format 548 strcat(buf + 257, "ustar"); 549 strcat(buf + 263, "00"); 550 551 // [ 265 : 32 ] user name, ignored on restore 552 // [ 297 : 32 ] group name, ignored on restore 553 554 // [ 100 : 8 ] file mode 555 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT); 556 557 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time 558 // [ 116 : 8 ] gid -- ignored in Android format 559 snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid); 560 snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid); 561 562 // [ 124 : 12 ] file size in bytes 563 if (s.st_size > 077777777777LL) { 564 // very large files need a pax extended size header 565 needExtended = true; 566 } 567 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size); 568 569 // [ 136 : 12 ] last mod time as a UTC time_t 570 snprintf(buf + 136, 12, "%0lo", (unsigned long)s.st_mtime); 571 572 // [ 156 : 1 ] link/file type 573 uint8_t type; 574 if (isdir) { 575 type = '5'; // tar magic: '5' == directory 576 } else if (S_ISREG(s.st_mode)) { 577 type = '0'; // tar magic: '0' == normal file 578 } else { 579 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string()); 580 goto cleanup; 581 } 582 buf[156] = type; 583 584 // [ 157 : 100 ] name of linked file [not implemented] 585 586 { 587 // Prefix and main relative path. Path lengths have been preflighted. 588 if (packageName.length() > 0) { 589 prefix = "apps/"; 590 prefix += packageName; 591 } 592 if (domain.length() > 0) { 593 prefix.appendPath(domain); 594 } 595 596 // pax extended means we don't put in a prefix field, and put a different 597 // string in the basic name field. We can also construct the full path name 598 // out of the substrings we've now built. 599 fullname = prefix; 600 fullname.appendPath(relpath); 601 602 // ustar: 603 // [ 0 : 100 ]; file name/path 604 // [ 345 : 155 ] filename path prefix 605 // We only use the prefix area if fullname won't fit in the path 606 if (fullname.length() > 100) { 607 strncpy(buf, relpath.string(), 100); 608 strncpy(buf + 345, prefix.string(), 155); 609 } else { 610 strncpy(buf, fullname.string(), 100); 611 } 612 } 613 614 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used 615 616 ALOGI(" Name: %s", fullname.string()); 617 618 // If we're using a pax extended header, build & write that here; lengths are 619 // already preflighted 620 if (needExtended) { 621 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal 622 char* p = paxData; 623 624 // construct the pax extended header data block 625 memset(paxData, 0, BUFSIZE - (paxData - buf)); 626 627 // size header -- calc len in digits by actually rendering the number 628 // to a string - brute force but simple 629 snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size); 630 p += write_pax_header_entry(p, "size", sizeStr); 631 632 // fullname was generated above with the ustar paths 633 p += write_pax_header_entry(p, "path", fullname.string()); 634 635 // Now we know how big the pax data is 636 int paxLen = p - paxData; 637 638 // Now build the pax *header* templated on the ustar header 639 memcpy(paxHeader, buf, 512); 640 641 String8 leaf = fullname.getPathLeaf(); 642 memset(paxHeader, 0, 100); // rewrite the name area 643 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string()); 644 memset(paxHeader + 345, 0, 155); // rewrite the prefix area 645 strncpy(paxHeader + 345, prefix.string(), 155); 646 647 paxHeader[156] = 'x'; // mark it as a pax extended header 648 649 // [ 124 : 12 ] size of pax extended header data 650 memset(paxHeader + 124, 0, 12); 651 snprintf(paxHeader + 124, 12, "%011o", (unsigned int)(p - paxData)); 652 653 // Checksum and write the pax block header 654 calc_tar_checksum(paxHeader); 655 send_tarfile_chunk(writer, paxHeader, 512); 656 657 // Now write the pax data itself 658 int paxblocks = (paxLen + 511) / 512; 659 send_tarfile_chunk(writer, paxData, 512 * paxblocks); 660 } 661 662 // Checksum and write the 512-byte ustar file header block to the output 663 calc_tar_checksum(buf); 664 send_tarfile_chunk(writer, buf, 512); 665 666 // Now write the file data itself, for real files. We honor tar's convention that 667 // only full 512-byte blocks are sent to write(). 668 if (!isdir) { 669 off64_t toWrite = s.st_size; 670 while (toWrite > 0) { 671 size_t toRead = toWrite; 672 if (toRead > BUFSIZE) { 673 toRead = BUFSIZE; 674 } 675 ssize_t nRead = read(fd, buf, toRead); 676 if (nRead < 0) { 677 err = errno; 678 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(), 679 err, strerror(err)); 680 break; 681 } else if (nRead == 0) { 682 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite, 683 filepath.string()); 684 err = EIO; 685 break; 686 } 687 688 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This 689 // depends on the OS guarantee that for ordinary files, read() will never return 690 // less than the number of bytes requested. 691 ssize_t partial = (nRead+512) % 512; 692 if (partial > 0) { 693 ssize_t remainder = 512 - partial; 694 memset(buf + nRead, 0, remainder); 695 nRead += remainder; 696 } 697 send_tarfile_chunk(writer, buf, nRead); 698 toWrite -= nRead; 699 } 700 } 701 702cleanup: 703 free(buf); 704done: 705 close(fd); 706 return err; 707} 708// end tarfile 709 710 711 712#define RESTORE_BUF_SIZE (8*1024) 713 714RestoreHelperBase::RestoreHelperBase() 715{ 716 m_buf = malloc(RESTORE_BUF_SIZE); 717 m_loggedUnknownMetadata = false; 718} 719 720RestoreHelperBase::~RestoreHelperBase() 721{ 722 free(m_buf); 723} 724 725status_t 726RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in) 727{ 728 ssize_t err; 729 size_t dataSize; 730 String8 key; 731 int fd; 732 void* buf = m_buf; 733 ssize_t amt; 734 int mode; 735 int crc; 736 struct stat st; 737 FileRec r; 738 739 err = in->ReadEntityHeader(&key, &dataSize); 740 if (err != NO_ERROR) { 741 return err; 742 } 743 744 // Get the metadata block off the head of the file entity and use that to 745 // set up the output file 746 file_metadata_v1 metadata; 747 amt = in->ReadEntityData(&metadata, sizeof(metadata)); 748 if (amt != sizeof(metadata)) { 749 ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(), 750 (long)amt, strerror(errno)); 751 return EIO; 752 } 753 metadata.version = fromlel(metadata.version); 754 metadata.mode = fromlel(metadata.mode); 755 if (metadata.version > CURRENT_METADATA_VERSION) { 756 if (!m_loggedUnknownMetadata) { 757 m_loggedUnknownMetadata = true; 758 ALOGW("Restoring file with unsupported metadata version %d (currently %d)", 759 metadata.version, CURRENT_METADATA_VERSION); 760 } 761 } 762 mode = metadata.mode; 763 764 // Write the file and compute the crc 765 crc = crc32(0L, Z_NULL, 0); 766 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode); 767 if (fd == -1) { 768 ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno)); 769 return errno; 770 } 771 772 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) { 773 err = write(fd, buf, amt); 774 if (err != amt) { 775 close(fd); 776 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string()); 777 return errno; 778 } 779 crc = crc32(crc, (Bytef*)buf, amt); 780 } 781 782 close(fd); 783 784 // Record for the snapshot 785 err = stat(filename.string(), &st); 786 if (err != 0) { 787 ALOGW("Error stating file that we just created %s", filename.string()); 788 return errno; 789 } 790 791 r.file = filename; 792 r.deleted = false; 793 r.s.modTime_sec = st.st_mtime; 794 r.s.modTime_nsec = 0; // workaround sim breakage 795 //r.s.modTime_nsec = st.st_mtime_nsec; 796 r.s.mode = st.st_mode; 797 r.s.size = st.st_size; 798 r.s.crc32 = crc; 799 800 m_files.add(key, r); 801 802 return NO_ERROR; 803} 804 805status_t 806RestoreHelperBase::WriteSnapshot(int fd) 807{ 808 return write_snapshot_file(fd, m_files);; 809} 810 811#if TEST_BACKUP_HELPERS 812 813#define SCRATCH_DIR "/data/backup_helper_test/" 814 815static int 816write_text_file(const char* path, const char* data) 817{ 818 int amt; 819 int fd; 820 int len; 821 822 fd = creat(path, 0666); 823 if (fd == -1) { 824 fprintf(stderr, "creat %s failed\n", path); 825 return errno; 826 } 827 828 len = strlen(data); 829 amt = write(fd, data, len); 830 if (amt != len) { 831 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path); 832 return errno; 833 } 834 835 close(fd); 836 837 return 0; 838} 839 840static int 841compare_file(const char* path, const unsigned char* data, int len) 842{ 843 int fd; 844 int amt; 845 846 fd = open(path, O_RDONLY); 847 if (fd == -1) { 848 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path); 849 return errno; 850 } 851 852 unsigned char* contents = (unsigned char*)malloc(len); 853 if (contents == NULL) { 854 fprintf(stderr, "malloc(%d) failed\n", len); 855 return ENOMEM; 856 } 857 858 bool sizesMatch = true; 859 amt = lseek(fd, 0, SEEK_END); 860 if (amt != len) { 861 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt); 862 sizesMatch = false; 863 } 864 lseek(fd, 0, SEEK_SET); 865 866 int readLen = amt < len ? amt : len; 867 amt = read(fd, contents, readLen); 868 if (amt != readLen) { 869 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt); 870 } 871 872 bool contentsMatch = true; 873 for (int i=0; i<readLen; i++) { 874 if (data[i] != contents[i]) { 875 if (contentsMatch) { 876 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n"); 877 contentsMatch = false; 878 } 879 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]); 880 } 881 } 882 883 free(contents); 884 return contentsMatch && sizesMatch ? 0 : 1; 885} 886 887int 888backup_helper_test_empty() 889{ 890 int err; 891 int fd; 892 KeyedVector<String8,FileRec> snapshot; 893 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap"; 894 895 system("rm -r " SCRATCH_DIR); 896 mkdir(SCRATCH_DIR, 0777); 897 898 // write 899 fd = creat(filename, 0666); 900 if (fd == -1) { 901 fprintf(stderr, "error creating %s\n", filename); 902 return 1; 903 } 904 905 err = write_snapshot_file(fd, snapshot); 906 907 close(fd); 908 909 if (err != 0) { 910 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err)); 911 return err; 912 } 913 914 static const unsigned char correct_data[] = { 915 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00, 916 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00 917 }; 918 919 err = compare_file(filename, correct_data, sizeof(correct_data)); 920 if (err != 0) { 921 return err; 922 } 923 924 // read 925 fd = open(filename, O_RDONLY); 926 if (fd == -1) { 927 fprintf(stderr, "error opening for read %s\n", filename); 928 return 1; 929 } 930 931 KeyedVector<String8,FileState> readSnapshot; 932 err = read_snapshot_file(fd, &readSnapshot); 933 if (err != 0) { 934 fprintf(stderr, "read_snapshot_file failed %d\n", err); 935 return err; 936 } 937 938 if (readSnapshot.size() != 0) { 939 fprintf(stderr, "readSnapshot should be length 0\n"); 940 return 1; 941 } 942 943 return 0; 944} 945 946int 947backup_helper_test_four() 948{ 949 int err; 950 int fd; 951 KeyedVector<String8,FileRec> snapshot; 952 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap"; 953 954 system("rm -r " SCRATCH_DIR); 955 mkdir(SCRATCH_DIR, 0777); 956 957 // write 958 fd = creat(filename, 0666); 959 if (fd == -1) { 960 fprintf(stderr, "error opening %s\n", filename); 961 return 1; 962 } 963 964 String8 filenames[4]; 965 FileState states[4]; 966 FileRec r; 967 r.deleted = false; 968 969 states[0].modTime_sec = 0xfedcba98; 970 states[0].modTime_nsec = 0xdeadbeef; 971 states[0].mode = 0777; // decimal 511, hex 0x000001ff 972 states[0].size = 0xababbcbc; 973 states[0].crc32 = 0x12345678; 974 states[0].nameLen = -12; 975 r.s = states[0]; 976 filenames[0] = String8("bytes_of_padding"); 977 snapshot.add(filenames[0], r); 978 979 states[1].modTime_sec = 0x93400031; 980 states[1].modTime_nsec = 0xdeadbeef; 981 states[1].mode = 0666; // decimal 438, hex 0x000001b6 982 states[1].size = 0x88557766; 983 states[1].crc32 = 0x22334422; 984 states[1].nameLen = -1; 985 r.s = states[1]; 986 filenames[1] = String8("bytes_of_padding3"); 987 snapshot.add(filenames[1], r); 988 989 states[2].modTime_sec = 0x33221144; 990 states[2].modTime_nsec = 0xdeadbeef; 991 states[2].mode = 0744; // decimal 484, hex 0x000001e4 992 states[2].size = 0x11223344; 993 states[2].crc32 = 0x01122334; 994 states[2].nameLen = 0; 995 r.s = states[2]; 996 filenames[2] = String8("bytes_of_padding_2"); 997 snapshot.add(filenames[2], r); 998 999 states[3].modTime_sec = 0x33221144; 1000 states[3].modTime_nsec = 0xdeadbeef; 1001 states[3].mode = 0755; // decimal 493, hex 0x000001ed 1002 states[3].size = 0x11223344; 1003 states[3].crc32 = 0x01122334; 1004 states[3].nameLen = 0; 1005 r.s = states[3]; 1006 filenames[3] = String8("bytes_of_padding__1"); 1007 snapshot.add(filenames[3], r); 1008 1009 err = write_snapshot_file(fd, snapshot); 1010 1011 close(fd); 1012 1013 if (err != 0) { 1014 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err)); 1015 return err; 1016 } 1017 1018 static const unsigned char correct_data[] = { 1019 // header 1020 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00, 1021 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00, 1022 1023 // bytes_of_padding 1024 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde, 1025 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab, 1026 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00, 1027 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, 1028 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 1029 1030 // bytes_of_padding3 1031 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde, 1032 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88, 1033 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 1034 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, 1035 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 1036 0x33, 0xab, 0xab, 0xab, 1037 1038 // bytes of padding2 1039 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde, 1040 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11, 1041 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00, 1042 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, 1043 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 1044 0x5f, 0x32, 0xab, 0xab, 1045 1046 // bytes of padding3 1047 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde, 1048 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11, 1049 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00, 1050 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, 1051 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 1052 0x5f, 0x5f, 0x31, 0xab 1053 }; 1054 1055 err = compare_file(filename, correct_data, sizeof(correct_data)); 1056 if (err != 0) { 1057 return err; 1058 } 1059 1060 // read 1061 fd = open(filename, O_RDONLY); 1062 if (fd == -1) { 1063 fprintf(stderr, "error opening for read %s\n", filename); 1064 return 1; 1065 } 1066 1067 1068 KeyedVector<String8,FileState> readSnapshot; 1069 err = read_snapshot_file(fd, &readSnapshot); 1070 if (err != 0) { 1071 fprintf(stderr, "read_snapshot_file failed %d\n", err); 1072 return err; 1073 } 1074 1075 if (readSnapshot.size() != 4) { 1076 fprintf(stderr, "readSnapshot should be length 4 is %zu\n", readSnapshot.size()); 1077 return 1; 1078 } 1079 1080 bool matched = true; 1081 for (size_t i=0; i<readSnapshot.size(); i++) { 1082 const String8& name = readSnapshot.keyAt(i); 1083 const FileState state = readSnapshot.valueAt(i); 1084 1085 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec 1086 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode 1087 || states[i].size != state.size || states[i].crc32 != states[i].crc32) { 1088 fprintf(stderr, "state %zu expected={%d/%d, %04o, 0x%08x, 0x%08x, %3zu} '%s'\n" 1089 " actual={%d/%d, %04o, 0x%08x, 0x%08x, %3d} '%s'\n", i, 1090 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size, 1091 states[i].crc32, name.length(), filenames[i].string(), 1092 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32, 1093 state.nameLen, name.string()); 1094 matched = false; 1095 } 1096 } 1097 1098 return matched ? 0 : 1; 1099} 1100 1101// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data 1102const unsigned char DATA_GOLDEN_FILE[] = { 1103 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00, 1104 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70, 1105 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00, 1106 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 1107 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61, 1108 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 1109 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 1110 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc, 1111 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 1112 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc, 1113 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00, 1114 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64, 1115 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f, 1116 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64, 1117 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f, 1118 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61, 1119 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 1120 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 1121 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64, 1122 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00 1123 1124}; 1125const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE); 1126 1127static int 1128test_write_header_and_entity(BackupDataWriter& writer, const char* str) 1129{ 1130 int err; 1131 String8 text(str); 1132 1133 err = writer.WriteEntityHeader(text, text.length()+1); 1134 if (err != 0) { 1135 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err)); 1136 return err; 1137 } 1138 1139 err = writer.WriteEntityData(text.string(), text.length()+1); 1140 if (err != 0) { 1141 fprintf(stderr, "write failed for data '%s'\n", text.string()); 1142 return errno; 1143 } 1144 1145 return err; 1146} 1147 1148int 1149backup_helper_test_data_writer() 1150{ 1151 int err; 1152 int fd; 1153 const char* filename = SCRATCH_DIR "data_writer.data"; 1154 1155 system("rm -r " SCRATCH_DIR); 1156 mkdir(SCRATCH_DIR, 0777); 1157 mkdir(SCRATCH_DIR "data", 0777); 1158 1159 fd = creat(filename, 0666); 1160 if (fd == -1) { 1161 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1162 return errno; 1163 } 1164 1165 BackupDataWriter writer(fd); 1166 1167 err = 0; 1168 err |= test_write_header_and_entity(writer, "no_padding_"); 1169 err |= test_write_header_and_entity(writer, "padded_to__3"); 1170 err |= test_write_header_and_entity(writer, "padded_to_2__"); 1171 err |= test_write_header_and_entity(writer, "padded_to1"); 1172 1173 close(fd); 1174 1175 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE); 1176 if (err != 0) { 1177 return err; 1178 } 1179 1180 return err; 1181} 1182 1183int 1184test_read_header_and_entity(BackupDataReader& reader, const char* str) 1185{ 1186 int err; 1187 size_t bufSize = strlen(str)+1; 1188 char* buf = (char*)malloc(bufSize); 1189 String8 string; 1190 size_t actualSize; 1191 bool done; 1192 int type; 1193 ssize_t nRead; 1194 1195 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str); 1196 1197 err = reader.ReadNextHeader(&done, &type); 1198 if (done) { 1199 fprintf(stderr, "should not be done yet\n"); 1200 goto finished; 1201 } 1202 if (err != 0) { 1203 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err)); 1204 goto finished; 1205 } 1206 if (type != BACKUP_HEADER_ENTITY_V1) { 1207 err = EINVAL; 1208 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1); 1209 } 1210 1211 err = reader.ReadEntityHeader(&string, &actualSize); 1212 if (err != 0) { 1213 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err)); 1214 goto finished; 1215 } 1216 if (string != str) { 1217 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string()); 1218 err = EINVAL; 1219 goto finished; 1220 } 1221 if (actualSize != bufSize) { 1222 fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n", 1223 bufSize, actualSize); 1224 err = EINVAL; 1225 goto finished; 1226 } 1227 1228 nRead = reader.ReadEntityData(buf, bufSize); 1229 if (nRead < 0) { 1230 err = reader.Status(); 1231 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err)); 1232 goto finished; 1233 } 1234 1235 if (0 != memcmp(buf, str, bufSize)) { 1236 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with " 1237 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3], 1238 buf[0], buf[1], buf[2], buf[3]); 1239 err = EINVAL; 1240 goto finished; 1241 } 1242 1243 // The next read will confirm whether it got the right amount of data. 1244 1245finished: 1246 if (err != NO_ERROR) { 1247 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err)); 1248 } 1249 free(buf); 1250 return err; 1251} 1252 1253int 1254backup_helper_test_data_reader() 1255{ 1256 int err; 1257 int fd; 1258 const char* filename = SCRATCH_DIR "data_reader.data"; 1259 1260 system("rm -r " SCRATCH_DIR); 1261 mkdir(SCRATCH_DIR, 0777); 1262 mkdir(SCRATCH_DIR "data", 0777); 1263 1264 fd = creat(filename, 0666); 1265 if (fd == -1) { 1266 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1267 return errno; 1268 } 1269 1270 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE); 1271 if (err != DATA_GOLDEN_FILE_SIZE) { 1272 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename); 1273 return errno; 1274 } 1275 1276 close(fd); 1277 1278 fd = open(filename, O_RDONLY); 1279 if (fd == -1) { 1280 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno), 1281 filename); 1282 return errno; 1283 } 1284 1285 { 1286 BackupDataReader reader(fd); 1287 1288 err = 0; 1289 1290 if (err == NO_ERROR) { 1291 err = test_read_header_and_entity(reader, "no_padding_"); 1292 } 1293 1294 if (err == NO_ERROR) { 1295 err = test_read_header_and_entity(reader, "padded_to__3"); 1296 } 1297 1298 if (err == NO_ERROR) { 1299 err = test_read_header_and_entity(reader, "padded_to_2__"); 1300 } 1301 1302 if (err == NO_ERROR) { 1303 err = test_read_header_and_entity(reader, "padded_to1"); 1304 } 1305 } 1306 1307 close(fd); 1308 1309 return err; 1310} 1311 1312static int 1313get_mod_time(const char* filename, struct timeval times[2]) 1314{ 1315 int err; 1316 struct stat64 st; 1317 err = stat64(filename, &st); 1318 if (err != 0) { 1319 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno)); 1320 return errno; 1321 } 1322 1323 times[0].tv_sec = st.st_atim.tv_sec; 1324 times[0].tv_usec = st.st_atim.tv_nsec / 1000; 1325 1326 times[1].tv_sec = st.st_mtim.tv_sec; 1327 times[1].tv_usec = st.st_mtim.tv_nsec / 1000; 1328 1329 return 0; 1330} 1331 1332int 1333backup_helper_test_files() 1334{ 1335 int err; 1336 int oldSnapshotFD; 1337 int dataStreamFD; 1338 int newSnapshotFD; 1339 1340 system("rm -r " SCRATCH_DIR); 1341 mkdir(SCRATCH_DIR, 0777); 1342 mkdir(SCRATCH_DIR "data", 0777); 1343 1344 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n"); 1345 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n"); 1346 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n"); 1347 write_text_file(SCRATCH_DIR "data/e", "e\nee\n"); 1348 write_text_file(SCRATCH_DIR "data/f", "f\nff\n"); 1349 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n"); 1350 1351 char const* files_before[] = { 1352 SCRATCH_DIR "data/b", 1353 SCRATCH_DIR "data/c", 1354 SCRATCH_DIR "data/d", 1355 SCRATCH_DIR "data/e", 1356 SCRATCH_DIR "data/f" 1357 }; 1358 1359 char const* keys_before[] = { 1360 "data/b", 1361 "data/c", 1362 "data/d", 1363 "data/e", 1364 "data/f" 1365 }; 1366 1367 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666); 1368 if (dataStreamFD == -1) { 1369 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1370 return errno; 1371 } 1372 1373 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666); 1374 if (newSnapshotFD == -1) { 1375 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1376 return errno; 1377 } 1378 1379 { 1380 BackupDataWriter dataStream(dataStreamFD); 1381 1382 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5); 1383 if (err != 0) { 1384 return err; 1385 } 1386 } 1387 1388 close(dataStreamFD); 1389 close(newSnapshotFD); 1390 1391 sleep(3); 1392 1393 struct timeval d_times[2]; 1394 struct timeval e_times[2]; 1395 1396 err = get_mod_time(SCRATCH_DIR "data/d", d_times); 1397 err |= get_mod_time(SCRATCH_DIR "data/e", e_times); 1398 if (err != 0) { 1399 return err; 1400 } 1401 1402 write_text_file(SCRATCH_DIR "data/a", "a\naa\n"); 1403 unlink(SCRATCH_DIR "data/c"); 1404 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n"); 1405 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n"); 1406 utimes(SCRATCH_DIR "data/d", d_times); 1407 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n"); 1408 utimes(SCRATCH_DIR "data/e", e_times); 1409 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n"); 1410 unlink(SCRATCH_DIR "data/f"); 1411 1412 char const* files_after[] = { 1413 SCRATCH_DIR "data/a", // added 1414 SCRATCH_DIR "data/b", // same 1415 SCRATCH_DIR "data/c", // different mod time 1416 SCRATCH_DIR "data/d", // different size (same mod time) 1417 SCRATCH_DIR "data/e", // different contents (same mod time, same size) 1418 SCRATCH_DIR "data/g" // added 1419 }; 1420 1421 char const* keys_after[] = { 1422 "data/a", // added 1423 "data/b", // same 1424 "data/c", // different mod time 1425 "data/d", // different size (same mod time) 1426 "data/e", // different contents (same mod time, same size) 1427 "data/g" // added 1428 }; 1429 1430 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY); 1431 if (oldSnapshotFD == -1) { 1432 fprintf(stderr, "error opening: %s\n", strerror(errno)); 1433 return errno; 1434 } 1435 1436 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666); 1437 if (dataStreamFD == -1) { 1438 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1439 return errno; 1440 } 1441 1442 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666); 1443 if (newSnapshotFD == -1) { 1444 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1445 return errno; 1446 } 1447 1448 { 1449 BackupDataWriter dataStream(dataStreamFD); 1450 1451 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6); 1452 if (err != 0) { 1453 return err; 1454 } 1455} 1456 1457 close(oldSnapshotFD); 1458 close(dataStreamFD); 1459 close(newSnapshotFD); 1460 1461 return 0; 1462} 1463 1464int 1465backup_helper_test_null_base() 1466{ 1467 int err; 1468 int dataStreamFD; 1469 int newSnapshotFD; 1470 1471 system("rm -r " SCRATCH_DIR); 1472 mkdir(SCRATCH_DIR, 0777); 1473 mkdir(SCRATCH_DIR "data", 0777); 1474 1475 write_text_file(SCRATCH_DIR "data/a", "a\naa\n"); 1476 1477 char const* files[] = { 1478 SCRATCH_DIR "data/a", 1479 }; 1480 1481 char const* keys[] = { 1482 "a", 1483 }; 1484 1485 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666); 1486 if (dataStreamFD == -1) { 1487 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1488 return errno; 1489 } 1490 1491 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666); 1492 if (newSnapshotFD == -1) { 1493 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1494 return errno; 1495 } 1496 1497 { 1498 BackupDataWriter dataStream(dataStreamFD); 1499 1500 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1); 1501 if (err != 0) { 1502 return err; 1503 } 1504 } 1505 1506 close(dataStreamFD); 1507 close(newSnapshotFD); 1508 1509 return 0; 1510} 1511 1512int 1513backup_helper_test_missing_file() 1514{ 1515 int err; 1516 int dataStreamFD; 1517 int newSnapshotFD; 1518 1519 system("rm -r " SCRATCH_DIR); 1520 mkdir(SCRATCH_DIR, 0777); 1521 mkdir(SCRATCH_DIR "data", 0777); 1522 1523 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n"); 1524 1525 char const* files[] = { 1526 SCRATCH_DIR "data/a", 1527 SCRATCH_DIR "data/b", 1528 SCRATCH_DIR "data/c", 1529 }; 1530 1531 char const* keys[] = { 1532 "a", 1533 "b", 1534 "c", 1535 }; 1536 1537 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666); 1538 if (dataStreamFD == -1) { 1539 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1540 return errno; 1541 } 1542 1543 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666); 1544 if (newSnapshotFD == -1) { 1545 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1546 return errno; 1547 } 1548 1549 { 1550 BackupDataWriter dataStream(dataStreamFD); 1551 1552 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1); 1553 if (err != 0) { 1554 return err; 1555 } 1556 } 1557 1558 close(dataStreamFD); 1559 close(newSnapshotFD); 1560 1561 return 0; 1562} 1563 1564 1565#endif // TEST_BACKUP_HELPERS 1566 1567} 1568