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