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