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, off_t* outSize, 482 BackupDataWriter* writer) 483{ 484 // In the output stream everything is stored relative to the root 485 const char* relstart = filepath.string() + rootpath.length(); 486 if (*relstart == '/') relstart++; // won't be true when path == rootpath 487 String8 relpath(relstart); 488 489 // If relpath is empty, it means this is the top of one of the standard named 490 // domain directories, so we should just skip it 491 if (relpath.length() == 0) { 492 *outSize = 0; 493 return 0; 494 } 495 496 // Too long a name for the ustar format? 497 // "apps/" + packagename + '/' + domainpath < 155 chars 498 // relpath < 100 chars 499 bool needExtended = false; 500 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) { 501 needExtended = true; 502 } 503 504 // Non-7bit-clean path also means needing pax extended format 505 if (!needExtended) { 506 for (size_t i = 0; i < filepath.length(); i++) { 507 if ((filepath[i] & 0x80) != 0) { 508 needExtended = true; 509 break; 510 } 511 } 512 } 513 514 int err = 0; 515 struct stat64 s; 516 if (lstat64(filepath.string(), &s) != 0) { 517 err = errno; 518 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string()); 519 return err; 520 } 521 522 // very large files need a pax extended size header 523 if (s.st_size > 077777777777LL) { 524 needExtended = true; 525 } 526 527 String8 fullname; // for pax later on 528 String8 prefix; 529 530 const int isdir = S_ISDIR(s.st_mode); 531 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream 532 533 // Report the size, including a rough tar overhead estimation: 512 bytes for the 534 // overall tar file-block header, plus 2 blocks if using the pax extended format, 535 // plus the raw content size rounded up to a multiple of 512. 536 *outSize = 512 + (needExtended ? 1024 : 0) + 512*((s.st_size + 511)/512); 537 538 // Measure case: we've returned the size; now return without moving data 539 if (!writer) return 0; 540 541 // !!! TODO: use mmap when possible to avoid churning the buffer cache 542 // !!! TODO: this will break with symlinks; need to use readlink(2) 543 int fd = open(filepath.string(), O_RDONLY); 544 if (fd < 0) { 545 err = errno; 546 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string()); 547 return err; 548 } 549 550 // read/write up to this much at a time. 551 const size_t BUFSIZE = 32 * 1024; 552 char* buf = (char *)calloc(1,BUFSIZE); 553 char* paxHeader = buf + 512; // use a different chunk of it as separate scratch 554 char* paxData = buf + 1024; 555 556 if (buf == NULL) { 557 ALOGE("Out of mem allocating transfer buffer"); 558 err = ENOMEM; 559 goto done; 560 } 561 562 // Magic fields for the ustar file format 563 strcat(buf + 257, "ustar"); 564 strcat(buf + 263, "00"); 565 566 // [ 265 : 32 ] user name, ignored on restore 567 // [ 297 : 32 ] group name, ignored on restore 568 569 // [ 100 : 8 ] file mode 570 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT); 571 572 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time 573 // [ 116 : 8 ] gid -- ignored in Android format 574 snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid); 575 snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid); 576 577 // [ 124 : 12 ] file size in bytes 578 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size); 579 580 // [ 136 : 12 ] last mod time as a UTC time_t 581 snprintf(buf + 136, 12, "%0lo", (unsigned long)s.st_mtime); 582 583 // [ 156 : 1 ] link/file type 584 uint8_t type; 585 if (isdir) { 586 type = '5'; // tar magic: '5' == directory 587 } else if (S_ISREG(s.st_mode)) { 588 type = '0'; // tar magic: '0' == normal file 589 } else { 590 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string()); 591 goto cleanup; 592 } 593 buf[156] = type; 594 595 // [ 157 : 100 ] name of linked file [not implemented] 596 597 { 598 // Prefix and main relative path. Path lengths have been preflighted. 599 if (packageName.length() > 0) { 600 prefix = "apps/"; 601 prefix += packageName; 602 } 603 if (domain.length() > 0) { 604 prefix.appendPath(domain); 605 } 606 607 // pax extended means we don't put in a prefix field, and put a different 608 // string in the basic name field. We can also construct the full path name 609 // out of the substrings we've now built. 610 fullname = prefix; 611 fullname.appendPath(relpath); 612 613 // ustar: 614 // [ 0 : 100 ]; file name/path 615 // [ 345 : 155 ] filename path prefix 616 // We only use the prefix area if fullname won't fit in the path 617 if (fullname.length() > 100) { 618 strncpy(buf, relpath.string(), 100); 619 strncpy(buf + 345, prefix.string(), 155); 620 } else { 621 strncpy(buf, fullname.string(), 100); 622 } 623 } 624 625 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used 626 627 ALOGI(" Name: %s", fullname.string()); 628 629 // If we're using a pax extended header, build & write that here; lengths are 630 // already preflighted 631 if (needExtended) { 632 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal 633 char* p = paxData; 634 635 // construct the pax extended header data block 636 memset(paxData, 0, BUFSIZE - (paxData - buf)); 637 638 // size header -- calc len in digits by actually rendering the number 639 // to a string - brute force but simple 640 snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size); 641 p += write_pax_header_entry(p, "size", sizeStr); 642 643 // fullname was generated above with the ustar paths 644 p += write_pax_header_entry(p, "path", fullname.string()); 645 646 // Now we know how big the pax data is 647 int paxLen = p - paxData; 648 649 // Now build the pax *header* templated on the ustar header 650 memcpy(paxHeader, buf, 512); 651 652 String8 leaf = fullname.getPathLeaf(); 653 memset(paxHeader, 0, 100); // rewrite the name area 654 snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string()); 655 memset(paxHeader + 345, 0, 155); // rewrite the prefix area 656 strncpy(paxHeader + 345, prefix.string(), 155); 657 658 paxHeader[156] = 'x'; // mark it as a pax extended header 659 660 // [ 124 : 12 ] size of pax extended header data 661 memset(paxHeader + 124, 0, 12); 662 snprintf(paxHeader + 124, 12, "%011o", (unsigned int)(p - paxData)); 663 664 // Checksum and write the pax block header 665 calc_tar_checksum(paxHeader); 666 send_tarfile_chunk(writer, paxHeader, 512); 667 668 // Now write the pax data itself 669 int paxblocks = (paxLen + 511) / 512; 670 send_tarfile_chunk(writer, paxData, 512 * paxblocks); 671 } 672 673 // Checksum and write the 512-byte ustar file header block to the output 674 calc_tar_checksum(buf); 675 send_tarfile_chunk(writer, buf, 512); 676 677 // Now write the file data itself, for real files. We honor tar's convention that 678 // only full 512-byte blocks are sent to write(). 679 if (!isdir) { 680 off64_t toWrite = s.st_size; 681 while (toWrite > 0) { 682 size_t toRead = toWrite; 683 if (toRead > BUFSIZE) { 684 toRead = BUFSIZE; 685 } 686 ssize_t nRead = read(fd, buf, toRead); 687 if (nRead < 0) { 688 err = errno; 689 ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(), 690 err, strerror(err)); 691 break; 692 } else if (nRead == 0) { 693 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite, 694 filepath.string()); 695 err = EIO; 696 break; 697 } 698 699 // At EOF we might have a short block; NUL-pad that to a 512-byte multiple. This 700 // depends on the OS guarantee that for ordinary files, read() will never return 701 // less than the number of bytes requested. 702 ssize_t partial = (nRead+512) % 512; 703 if (partial > 0) { 704 ssize_t remainder = 512 - partial; 705 memset(buf + nRead, 0, remainder); 706 nRead += remainder; 707 } 708 send_tarfile_chunk(writer, buf, nRead); 709 toWrite -= nRead; 710 } 711 } 712 713cleanup: 714 free(buf); 715done: 716 close(fd); 717 return err; 718} 719// end tarfile 720 721 722 723#define RESTORE_BUF_SIZE (8*1024) 724 725RestoreHelperBase::RestoreHelperBase() 726{ 727 m_buf = malloc(RESTORE_BUF_SIZE); 728 m_loggedUnknownMetadata = false; 729} 730 731RestoreHelperBase::~RestoreHelperBase() 732{ 733 free(m_buf); 734} 735 736status_t 737RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in) 738{ 739 ssize_t err; 740 size_t dataSize; 741 String8 key; 742 int fd; 743 void* buf = m_buf; 744 ssize_t amt; 745 int mode; 746 int crc; 747 struct stat st; 748 FileRec r; 749 750 err = in->ReadEntityHeader(&key, &dataSize); 751 if (err != NO_ERROR) { 752 return err; 753 } 754 755 // Get the metadata block off the head of the file entity and use that to 756 // set up the output file 757 file_metadata_v1 metadata; 758 amt = in->ReadEntityData(&metadata, sizeof(metadata)); 759 if (amt != sizeof(metadata)) { 760 ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(), 761 (long)amt, strerror(errno)); 762 return EIO; 763 } 764 metadata.version = fromlel(metadata.version); 765 metadata.mode = fromlel(metadata.mode); 766 if (metadata.version > CURRENT_METADATA_VERSION) { 767 if (!m_loggedUnknownMetadata) { 768 m_loggedUnknownMetadata = true; 769 ALOGW("Restoring file with unsupported metadata version %d (currently %d)", 770 metadata.version, CURRENT_METADATA_VERSION); 771 } 772 } 773 mode = metadata.mode; 774 775 // Write the file and compute the crc 776 crc = crc32(0L, Z_NULL, 0); 777 fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode); 778 if (fd == -1) { 779 ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno)); 780 return errno; 781 } 782 783 while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) { 784 err = write(fd, buf, amt); 785 if (err != amt) { 786 close(fd); 787 ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string()); 788 return errno; 789 } 790 crc = crc32(crc, (Bytef*)buf, amt); 791 } 792 793 close(fd); 794 795 // Record for the snapshot 796 err = stat(filename.string(), &st); 797 if (err != 0) { 798 ALOGW("Error stating file that we just created %s", filename.string()); 799 return errno; 800 } 801 802 r.file = filename; 803 r.deleted = false; 804 r.s.modTime_sec = st.st_mtime; 805 r.s.modTime_nsec = 0; // workaround sim breakage 806 //r.s.modTime_nsec = st.st_mtime_nsec; 807 r.s.mode = st.st_mode; 808 r.s.size = st.st_size; 809 r.s.crc32 = crc; 810 811 m_files.add(key, r); 812 813 return NO_ERROR; 814} 815 816status_t 817RestoreHelperBase::WriteSnapshot(int fd) 818{ 819 return write_snapshot_file(fd, m_files);; 820} 821 822#if TEST_BACKUP_HELPERS 823 824#define SCRATCH_DIR "/data/backup_helper_test/" 825 826static int 827write_text_file(const char* path, const char* data) 828{ 829 int amt; 830 int fd; 831 int len; 832 833 fd = creat(path, 0666); 834 if (fd == -1) { 835 fprintf(stderr, "creat %s failed\n", path); 836 return errno; 837 } 838 839 len = strlen(data); 840 amt = write(fd, data, len); 841 if (amt != len) { 842 fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path); 843 return errno; 844 } 845 846 close(fd); 847 848 return 0; 849} 850 851static int 852compare_file(const char* path, const unsigned char* data, int len) 853{ 854 int fd; 855 int amt; 856 857 fd = open(path, O_RDONLY); 858 if (fd == -1) { 859 fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path); 860 return errno; 861 } 862 863 unsigned char* contents = (unsigned char*)malloc(len); 864 if (contents == NULL) { 865 fprintf(stderr, "malloc(%d) failed\n", len); 866 return ENOMEM; 867 } 868 869 bool sizesMatch = true; 870 amt = lseek(fd, 0, SEEK_END); 871 if (amt != len) { 872 fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt); 873 sizesMatch = false; 874 } 875 lseek(fd, 0, SEEK_SET); 876 877 int readLen = amt < len ? amt : len; 878 amt = read(fd, contents, readLen); 879 if (amt != readLen) { 880 fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt); 881 } 882 883 bool contentsMatch = true; 884 for (int i=0; i<readLen; i++) { 885 if (data[i] != contents[i]) { 886 if (contentsMatch) { 887 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n"); 888 contentsMatch = false; 889 } 890 fprintf(stderr, " [%-2d] %02x %02x\n", i, data[i], contents[i]); 891 } 892 } 893 894 free(contents); 895 return contentsMatch && sizesMatch ? 0 : 1; 896} 897 898int 899backup_helper_test_empty() 900{ 901 int err; 902 int fd; 903 KeyedVector<String8,FileRec> snapshot; 904 const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap"; 905 906 system("rm -r " SCRATCH_DIR); 907 mkdir(SCRATCH_DIR, 0777); 908 909 // write 910 fd = creat(filename, 0666); 911 if (fd == -1) { 912 fprintf(stderr, "error creating %s\n", filename); 913 return 1; 914 } 915 916 err = write_snapshot_file(fd, snapshot); 917 918 close(fd); 919 920 if (err != 0) { 921 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err)); 922 return err; 923 } 924 925 static const unsigned char correct_data[] = { 926 0x53, 0x6e, 0x61, 0x70, 0x00, 0x00, 0x00, 0x00, 927 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x00, 0x00 928 }; 929 930 err = compare_file(filename, correct_data, sizeof(correct_data)); 931 if (err != 0) { 932 return err; 933 } 934 935 // read 936 fd = open(filename, O_RDONLY); 937 if (fd == -1) { 938 fprintf(stderr, "error opening for read %s\n", filename); 939 return 1; 940 } 941 942 KeyedVector<String8,FileState> readSnapshot; 943 err = read_snapshot_file(fd, &readSnapshot); 944 if (err != 0) { 945 fprintf(stderr, "read_snapshot_file failed %d\n", err); 946 return err; 947 } 948 949 if (readSnapshot.size() != 0) { 950 fprintf(stderr, "readSnapshot should be length 0\n"); 951 return 1; 952 } 953 954 return 0; 955} 956 957int 958backup_helper_test_four() 959{ 960 int err; 961 int fd; 962 KeyedVector<String8,FileRec> snapshot; 963 const char* filename = SCRATCH_DIR "backup_helper_test_four.snap"; 964 965 system("rm -r " SCRATCH_DIR); 966 mkdir(SCRATCH_DIR, 0777); 967 968 // write 969 fd = creat(filename, 0666); 970 if (fd == -1) { 971 fprintf(stderr, "error opening %s\n", filename); 972 return 1; 973 } 974 975 String8 filenames[4]; 976 FileState states[4]; 977 FileRec r; 978 r.deleted = false; 979 980 states[0].modTime_sec = 0xfedcba98; 981 states[0].modTime_nsec = 0xdeadbeef; 982 states[0].mode = 0777; // decimal 511, hex 0x000001ff 983 states[0].size = 0xababbcbc; 984 states[0].crc32 = 0x12345678; 985 states[0].nameLen = -12; 986 r.s = states[0]; 987 filenames[0] = String8("bytes_of_padding"); 988 snapshot.add(filenames[0], r); 989 990 states[1].modTime_sec = 0x93400031; 991 states[1].modTime_nsec = 0xdeadbeef; 992 states[1].mode = 0666; // decimal 438, hex 0x000001b6 993 states[1].size = 0x88557766; 994 states[1].crc32 = 0x22334422; 995 states[1].nameLen = -1; 996 r.s = states[1]; 997 filenames[1] = String8("bytes_of_padding3"); 998 snapshot.add(filenames[1], r); 999 1000 states[2].modTime_sec = 0x33221144; 1001 states[2].modTime_nsec = 0xdeadbeef; 1002 states[2].mode = 0744; // decimal 484, hex 0x000001e4 1003 states[2].size = 0x11223344; 1004 states[2].crc32 = 0x01122334; 1005 states[2].nameLen = 0; 1006 r.s = states[2]; 1007 filenames[2] = String8("bytes_of_padding_2"); 1008 snapshot.add(filenames[2], r); 1009 1010 states[3].modTime_sec = 0x33221144; 1011 states[3].modTime_nsec = 0xdeadbeef; 1012 states[3].mode = 0755; // decimal 493, hex 0x000001ed 1013 states[3].size = 0x11223344; 1014 states[3].crc32 = 0x01122334; 1015 states[3].nameLen = 0; 1016 r.s = states[3]; 1017 filenames[3] = String8("bytes_of_padding__1"); 1018 snapshot.add(filenames[3], r); 1019 1020 err = write_snapshot_file(fd, snapshot); 1021 1022 close(fd); 1023 1024 if (err != 0) { 1025 fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err)); 1026 return err; 1027 } 1028 1029 static const unsigned char correct_data[] = { 1030 // header 1031 0x53, 0x6e, 0x61, 0x70, 0x04, 0x00, 0x00, 0x00, 1032 0x46, 0x69, 0x6c, 0x65, 0xbc, 0x00, 0x00, 0x00, 1033 1034 // bytes_of_padding 1035 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xbe, 0xad, 0xde, 1036 0xff, 0x01, 0x00, 0x00, 0xbc, 0xbc, 0xab, 0xab, 1037 0x78, 0x56, 0x34, 0x12, 0x10, 0x00, 0x00, 0x00, 1038 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, 1039 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 1040 1041 // bytes_of_padding3 1042 0x31, 0x00, 0x40, 0x93, 0xef, 0xbe, 0xad, 0xde, 1043 0xb6, 0x01, 0x00, 0x00, 0x66, 0x77, 0x55, 0x88, 1044 0x22, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 1045 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, 1046 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 1047 0x33, 0xab, 0xab, 0xab, 1048 1049 // bytes of padding2 1050 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde, 1051 0xe4, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11, 1052 0x34, 0x23, 0x12, 0x01, 0x12, 0x00, 0x00, 0x00, 1053 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, 1054 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 1055 0x5f, 0x32, 0xab, 0xab, 1056 1057 // bytes of padding3 1058 0x44, 0x11, 0x22, 0x33, 0xef, 0xbe, 0xad, 0xde, 1059 0xed, 0x01, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11, 1060 0x34, 0x23, 0x12, 0x01, 0x13, 0x00, 0x00, 0x00, 1061 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x6f, 0x66, 1062 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 1063 0x5f, 0x5f, 0x31, 0xab 1064 }; 1065 1066 err = compare_file(filename, correct_data, sizeof(correct_data)); 1067 if (err != 0) { 1068 return err; 1069 } 1070 1071 // read 1072 fd = open(filename, O_RDONLY); 1073 if (fd == -1) { 1074 fprintf(stderr, "error opening for read %s\n", filename); 1075 return 1; 1076 } 1077 1078 1079 KeyedVector<String8,FileState> readSnapshot; 1080 err = read_snapshot_file(fd, &readSnapshot); 1081 if (err != 0) { 1082 fprintf(stderr, "read_snapshot_file failed %d\n", err); 1083 return err; 1084 } 1085 1086 if (readSnapshot.size() != 4) { 1087 fprintf(stderr, "readSnapshot should be length 4 is %zu\n", readSnapshot.size()); 1088 return 1; 1089 } 1090 1091 bool matched = true; 1092 for (size_t i=0; i<readSnapshot.size(); i++) { 1093 const String8& name = readSnapshot.keyAt(i); 1094 const FileState state = readSnapshot.valueAt(i); 1095 1096 if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec 1097 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode 1098 || states[i].size != state.size || states[i].crc32 != states[i].crc32) { 1099 fprintf(stderr, "state %zu expected={%d/%d, %04o, 0x%08x, 0x%08x, %3zu} '%s'\n" 1100 " actual={%d/%d, %04o, 0x%08x, 0x%08x, %3d} '%s'\n", i, 1101 states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size, 1102 states[i].crc32, name.length(), filenames[i].string(), 1103 state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32, 1104 state.nameLen, name.string()); 1105 matched = false; 1106 } 1107 } 1108 1109 return matched ? 0 : 1; 1110} 1111 1112// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data 1113const unsigned char DATA_GOLDEN_FILE[] = { 1114 0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00, 1115 0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70, 1116 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00, 1117 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, 1118 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61, 1119 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 1120 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 1121 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc, 1122 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 1123 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc, 1124 0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00, 1125 0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64, 1126 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f, 1127 0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64, 1128 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f, 1129 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61, 1130 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 1131 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 1132 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64, 1133 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00 1134 1135}; 1136const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE); 1137 1138static int 1139test_write_header_and_entity(BackupDataWriter& writer, const char* str) 1140{ 1141 int err; 1142 String8 text(str); 1143 1144 err = writer.WriteEntityHeader(text, text.length()+1); 1145 if (err != 0) { 1146 fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err)); 1147 return err; 1148 } 1149 1150 err = writer.WriteEntityData(text.string(), text.length()+1); 1151 if (err != 0) { 1152 fprintf(stderr, "write failed for data '%s'\n", text.string()); 1153 return errno; 1154 } 1155 1156 return err; 1157} 1158 1159int 1160backup_helper_test_data_writer() 1161{ 1162 int err; 1163 int fd; 1164 const char* filename = SCRATCH_DIR "data_writer.data"; 1165 1166 system("rm -r " SCRATCH_DIR); 1167 mkdir(SCRATCH_DIR, 0777); 1168 mkdir(SCRATCH_DIR "data", 0777); 1169 1170 fd = creat(filename, 0666); 1171 if (fd == -1) { 1172 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1173 return errno; 1174 } 1175 1176 BackupDataWriter writer(fd); 1177 1178 err = 0; 1179 err |= test_write_header_and_entity(writer, "no_padding_"); 1180 err |= test_write_header_and_entity(writer, "padded_to__3"); 1181 err |= test_write_header_and_entity(writer, "padded_to_2__"); 1182 err |= test_write_header_and_entity(writer, "padded_to1"); 1183 1184 close(fd); 1185 1186 err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE); 1187 if (err != 0) { 1188 return err; 1189 } 1190 1191 return err; 1192} 1193 1194int 1195test_read_header_and_entity(BackupDataReader& reader, const char* str) 1196{ 1197 int err; 1198 size_t bufSize = strlen(str)+1; 1199 char* buf = (char*)malloc(bufSize); 1200 String8 string; 1201 size_t actualSize; 1202 bool done; 1203 int type; 1204 ssize_t nRead; 1205 1206 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str); 1207 1208 err = reader.ReadNextHeader(&done, &type); 1209 if (done) { 1210 fprintf(stderr, "should not be done yet\n"); 1211 goto finished; 1212 } 1213 if (err != 0) { 1214 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err)); 1215 goto finished; 1216 } 1217 if (type != BACKUP_HEADER_ENTITY_V1) { 1218 err = EINVAL; 1219 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1); 1220 } 1221 1222 err = reader.ReadEntityHeader(&string, &actualSize); 1223 if (err != 0) { 1224 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err)); 1225 goto finished; 1226 } 1227 if (string != str) { 1228 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string()); 1229 err = EINVAL; 1230 goto finished; 1231 } 1232 if (actualSize != bufSize) { 1233 fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n", 1234 bufSize, actualSize); 1235 err = EINVAL; 1236 goto finished; 1237 } 1238 1239 nRead = reader.ReadEntityData(buf, bufSize); 1240 if (nRead < 0) { 1241 err = reader.Status(); 1242 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err)); 1243 goto finished; 1244 } 1245 1246 if (0 != memcmp(buf, str, bufSize)) { 1247 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with " 1248 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3], 1249 buf[0], buf[1], buf[2], buf[3]); 1250 err = EINVAL; 1251 goto finished; 1252 } 1253 1254 // The next read will confirm whether it got the right amount of data. 1255 1256finished: 1257 if (err != NO_ERROR) { 1258 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err)); 1259 } 1260 free(buf); 1261 return err; 1262} 1263 1264int 1265backup_helper_test_data_reader() 1266{ 1267 int err; 1268 int fd; 1269 const char* filename = SCRATCH_DIR "data_reader.data"; 1270 1271 system("rm -r " SCRATCH_DIR); 1272 mkdir(SCRATCH_DIR, 0777); 1273 mkdir(SCRATCH_DIR "data", 0777); 1274 1275 fd = creat(filename, 0666); 1276 if (fd == -1) { 1277 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1278 return errno; 1279 } 1280 1281 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE); 1282 if (err != DATA_GOLDEN_FILE_SIZE) { 1283 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename); 1284 return errno; 1285 } 1286 1287 close(fd); 1288 1289 fd = open(filename, O_RDONLY); 1290 if (fd == -1) { 1291 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno), 1292 filename); 1293 return errno; 1294 } 1295 1296 { 1297 BackupDataReader reader(fd); 1298 1299 err = 0; 1300 1301 if (err == NO_ERROR) { 1302 err = test_read_header_and_entity(reader, "no_padding_"); 1303 } 1304 1305 if (err == NO_ERROR) { 1306 err = test_read_header_and_entity(reader, "padded_to__3"); 1307 } 1308 1309 if (err == NO_ERROR) { 1310 err = test_read_header_and_entity(reader, "padded_to_2__"); 1311 } 1312 1313 if (err == NO_ERROR) { 1314 err = test_read_header_and_entity(reader, "padded_to1"); 1315 } 1316 } 1317 1318 close(fd); 1319 1320 return err; 1321} 1322 1323static int 1324get_mod_time(const char* filename, struct timeval times[2]) 1325{ 1326 int err; 1327 struct stat64 st; 1328 err = stat64(filename, &st); 1329 if (err != 0) { 1330 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno)); 1331 return errno; 1332 } 1333 1334 times[0].tv_sec = st.st_atim.tv_sec; 1335 times[0].tv_usec = st.st_atim.tv_nsec / 1000; 1336 1337 times[1].tv_sec = st.st_mtim.tv_sec; 1338 times[1].tv_usec = st.st_mtim.tv_nsec / 1000; 1339 1340 return 0; 1341} 1342 1343int 1344backup_helper_test_files() 1345{ 1346 int err; 1347 int oldSnapshotFD; 1348 int dataStreamFD; 1349 int newSnapshotFD; 1350 1351 system("rm -r " SCRATCH_DIR); 1352 mkdir(SCRATCH_DIR, 0777); 1353 mkdir(SCRATCH_DIR "data", 0777); 1354 1355 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n"); 1356 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n"); 1357 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n"); 1358 write_text_file(SCRATCH_DIR "data/e", "e\nee\n"); 1359 write_text_file(SCRATCH_DIR "data/f", "f\nff\n"); 1360 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n"); 1361 1362 char const* files_before[] = { 1363 SCRATCH_DIR "data/b", 1364 SCRATCH_DIR "data/c", 1365 SCRATCH_DIR "data/d", 1366 SCRATCH_DIR "data/e", 1367 SCRATCH_DIR "data/f" 1368 }; 1369 1370 char const* keys_before[] = { 1371 "data/b", 1372 "data/c", 1373 "data/d", 1374 "data/e", 1375 "data/f" 1376 }; 1377 1378 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666); 1379 if (dataStreamFD == -1) { 1380 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1381 return errno; 1382 } 1383 1384 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666); 1385 if (newSnapshotFD == -1) { 1386 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1387 return errno; 1388 } 1389 1390 { 1391 BackupDataWriter dataStream(dataStreamFD); 1392 1393 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5); 1394 if (err != 0) { 1395 return err; 1396 } 1397 } 1398 1399 close(dataStreamFD); 1400 close(newSnapshotFD); 1401 1402 sleep(3); 1403 1404 struct timeval d_times[2]; 1405 struct timeval e_times[2]; 1406 1407 err = get_mod_time(SCRATCH_DIR "data/d", d_times); 1408 err |= get_mod_time(SCRATCH_DIR "data/e", e_times); 1409 if (err != 0) { 1410 return err; 1411 } 1412 1413 write_text_file(SCRATCH_DIR "data/a", "a\naa\n"); 1414 unlink(SCRATCH_DIR "data/c"); 1415 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n"); 1416 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n"); 1417 utimes(SCRATCH_DIR "data/d", d_times); 1418 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n"); 1419 utimes(SCRATCH_DIR "data/e", e_times); 1420 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n"); 1421 unlink(SCRATCH_DIR "data/f"); 1422 1423 char const* files_after[] = { 1424 SCRATCH_DIR "data/a", // added 1425 SCRATCH_DIR "data/b", // same 1426 SCRATCH_DIR "data/c", // different mod time 1427 SCRATCH_DIR "data/d", // different size (same mod time) 1428 SCRATCH_DIR "data/e", // different contents (same mod time, same size) 1429 SCRATCH_DIR "data/g" // added 1430 }; 1431 1432 char const* keys_after[] = { 1433 "data/a", // added 1434 "data/b", // same 1435 "data/c", // different mod time 1436 "data/d", // different size (same mod time) 1437 "data/e", // different contents (same mod time, same size) 1438 "data/g" // added 1439 }; 1440 1441 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY); 1442 if (oldSnapshotFD == -1) { 1443 fprintf(stderr, "error opening: %s\n", strerror(errno)); 1444 return errno; 1445 } 1446 1447 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666); 1448 if (dataStreamFD == -1) { 1449 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1450 return errno; 1451 } 1452 1453 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666); 1454 if (newSnapshotFD == -1) { 1455 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1456 return errno; 1457 } 1458 1459 { 1460 BackupDataWriter dataStream(dataStreamFD); 1461 1462 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6); 1463 if (err != 0) { 1464 return err; 1465 } 1466} 1467 1468 close(oldSnapshotFD); 1469 close(dataStreamFD); 1470 close(newSnapshotFD); 1471 1472 return 0; 1473} 1474 1475int 1476backup_helper_test_null_base() 1477{ 1478 int err; 1479 int dataStreamFD; 1480 int newSnapshotFD; 1481 1482 system("rm -r " SCRATCH_DIR); 1483 mkdir(SCRATCH_DIR, 0777); 1484 mkdir(SCRATCH_DIR "data", 0777); 1485 1486 write_text_file(SCRATCH_DIR "data/a", "a\naa\n"); 1487 1488 char const* files[] = { 1489 SCRATCH_DIR "data/a", 1490 }; 1491 1492 char const* keys[] = { 1493 "a", 1494 }; 1495 1496 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666); 1497 if (dataStreamFD == -1) { 1498 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1499 return errno; 1500 } 1501 1502 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666); 1503 if (newSnapshotFD == -1) { 1504 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1505 return errno; 1506 } 1507 1508 { 1509 BackupDataWriter dataStream(dataStreamFD); 1510 1511 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1); 1512 if (err != 0) { 1513 return err; 1514 } 1515 } 1516 1517 close(dataStreamFD); 1518 close(newSnapshotFD); 1519 1520 return 0; 1521} 1522 1523int 1524backup_helper_test_missing_file() 1525{ 1526 int err; 1527 int dataStreamFD; 1528 int newSnapshotFD; 1529 1530 system("rm -r " SCRATCH_DIR); 1531 mkdir(SCRATCH_DIR, 0777); 1532 mkdir(SCRATCH_DIR "data", 0777); 1533 1534 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n"); 1535 1536 char const* files[] = { 1537 SCRATCH_DIR "data/a", 1538 SCRATCH_DIR "data/b", 1539 SCRATCH_DIR "data/c", 1540 }; 1541 1542 char const* keys[] = { 1543 "a", 1544 "b", 1545 "c", 1546 }; 1547 1548 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666); 1549 if (dataStreamFD == -1) { 1550 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1551 return errno; 1552 } 1553 1554 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666); 1555 if (newSnapshotFD == -1) { 1556 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1557 return errno; 1558 } 1559 1560 { 1561 BackupDataWriter dataStream(dataStreamFD); 1562 1563 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1); 1564 if (err != 0) { 1565 return err; 1566 } 1567 } 1568 1569 close(dataStreamFD); 1570 close(newSnapshotFD); 1571 1572 return 0; 1573} 1574 1575 1576#endif // TEST_BACKUP_HELPERS 1577 1578} 1579