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