BackupHelpers.cpp revision 52eb4e01a49fe2e94555c000de38bbcbbb13401b
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 <errno.h> 22#include <fcntl.h> 23#include <stdio.h> 24#include <stdlib.h> 25#include <sys/stat.h> 26#include <sys/types.h> 27#include <sys/time.h> // for utimes 28#include <sys/uio.h> 29#include <unistd.h> 30#include <utime.h> 31#include <zlib.h> 32 33#include <log/log.h> 34#include <utils/ByteOrder.h> 35#include <utils/KeyedVector.h> 36#include <utils/String8.h> 37 38namespace android { 39 40#define MAGIC0 0x70616e53 // Snap 41#define MAGIC1 0x656c6946 // File 42 43/* 44 * File entity data format (v1): 45 * 46 * - 4-byte version number of the metadata, little endian (0x00000001 for v1) 47 * - 12 bytes of metadata 48 * - the file data itself 49 * 50 * i.e. a 16-byte metadata header followed by the raw file data. If the 51 * restore code does not recognize the metadata version, it can still 52 * interpret the file data itself correctly. 53 * 54 * file_metadata_v1: 55 * 56 * - 4 byte version number === 0x00000001 (little endian) 57 * - 4-byte access mode (little-endian) 58 * - undefined (8 bytes) 59 */ 60 61struct file_metadata_v1 { 62 int version; 63 int mode; 64 int undefined_1; 65 int undefined_2; 66}; 67 68const static int CURRENT_METADATA_VERSION = 1; 69 70static const bool kIsDebug = false; 71#if TEST_BACKUP_HELPERS 72#define LOGP(f, x...) if (kIsDebug) printf(f "\n", x) 73#else 74#define LOGP(x...) if (kIsDebug) ALOGD(x) 75#endif 76 77const static int ROUND_UP[4] = { 0, 3, 2, 1 }; 78 79static inline int 80round_up(int n) 81{ 82 return n + ROUND_UP[n % 4]; 83} 84 85static int 86read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot) 87{ 88 int bytesRead = 0; 89 int amt; 90 SnapshotHeader header; 91 92 amt = read(fd, &header, sizeof(header)); 93 if (amt != sizeof(header)) { 94 return errno; 95 } 96 bytesRead += amt; 97 98 if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) { 99 ALOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1); 100 return 1; 101 } 102 103 for (int i=0; i<header.fileCount; i++) { 104 FileState file; 105 char filenameBuf[128]; 106 107 amt = read(fd, &file, sizeof(FileState)); 108 if (amt != sizeof(FileState)) { 109 ALOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead); 110 return 1; 111 } 112 bytesRead += amt; 113 114 // filename is not NULL terminated, but it is padded 115 int nameBufSize = round_up(file.nameLen); 116 char* filename = nameBufSize <= (int)sizeof(filenameBuf) 117 ? filenameBuf 118 : (char*)malloc(nameBufSize); 119 amt = read(fd, filename, nameBufSize); 120 if (amt == nameBufSize) { 121 snapshot->add(String8(filename, file.nameLen), file); 122 } 123 bytesRead += amt; 124 if (filename != filenameBuf) { 125 free(filename); 126 } 127 if (amt != nameBufSize) { 128 ALOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead); 129 return 1; 130 } 131 } 132 133 if (header.totalSize != bytesRead) { 134 ALOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n", 135 header.totalSize, bytesRead); 136 return 1; 137 } 138 139 return 0; 140} 141 142static int 143write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot) 144{ 145 int fileCount = 0; 146 int bytesWritten = sizeof(SnapshotHeader); 147 // preflight size 148 const int N = snapshot.size(); 149 for (int i=0; i<N; i++) { 150 const FileRec& g = snapshot.valueAt(i); 151 if (!g.deleted) { 152 const String8& name = snapshot.keyAt(i); 153 bytesWritten += sizeof(FileState) + round_up(name.length()); 154 fileCount++; 155 } 156 } 157 158 LOGP("write_snapshot_file fd=%d\n", fd); 159 160 int amt; 161 SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten }; 162 163 amt = write(fd, &header, sizeof(header)); 164 if (amt != sizeof(header)) { 165 ALOGW("write_snapshot_file error writing header %s", strerror(errno)); 166 return errno; 167 } 168 169 for (int i=0; i<N; i++) { 170 FileRec r = snapshot.valueAt(i); 171 if (!r.deleted) { 172 const String8& name = snapshot.keyAt(i); 173 int nameLen = r.s.nameLen = name.length(); 174 175 amt = write(fd, &r.s, sizeof(FileState)); 176 if (amt != sizeof(FileState)) { 177 ALOGW("write_snapshot_file error writing header %s", strerror(errno)); 178 return 1; 179 } 180 181 // filename is not NULL terminated, but it is padded 182 amt = write(fd, name.string(), nameLen); 183 if (amt != nameLen) { 184 ALOGW("write_snapshot_file error writing filename %s", strerror(errno)); 185 return 1; 186 } 187 int paddingLen = ROUND_UP[nameLen % 4]; 188 if (paddingLen != 0) { 189 int padding = 0xabababab; 190 amt = write(fd, &padding, paddingLen); 191 if (amt != paddingLen) { 192 ALOGW("write_snapshot_file error writing %d bytes of filename padding %s", 193 paddingLen, strerror(errno)); 194 return 1; 195 } 196 } 197 } 198 } 199 200 return 0; 201} 202 203static int 204write_delete_file(BackupDataWriter* dataStream, const String8& key) 205{ 206 LOGP("write_delete_file %s\n", key.string()); 207 return dataStream->WriteEntityHeader(key, -1); 208} 209 210static int 211write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key, 212 char const* realFilename) 213{ 214 LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode); 215 216 const int bufsize = 4*1024; 217 int err; 218 int amt; 219 int fileSize; 220 int bytesLeft; 221 file_metadata_v1 metadata; 222 223 char* buf = (char*)malloc(bufsize); 224 225 fileSize = lseek(fd, 0, SEEK_END); 226 lseek(fd, 0, SEEK_SET); 227 228 if (sizeof(metadata) != 16) { 229 ALOGE("ERROR: metadata block is the wrong size!"); 230 } 231 232 bytesLeft = fileSize + sizeof(metadata); 233 err = dataStream->WriteEntityHeader(key, bytesLeft); 234 if (err != 0) { 235 free(buf); 236 return err; 237 } 238 239 // store the file metadata first 240 metadata.version = tolel(CURRENT_METADATA_VERSION); 241 metadata.mode = tolel(mode); 242 metadata.undefined_1 = metadata.undefined_2 = 0; 243 err = dataStream->WriteEntityData(&metadata, sizeof(metadata)); 244 if (err != 0) { 245 free(buf); 246 return err; 247 } 248 bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now 249 250 // now store the file content 251 while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) { 252 bytesLeft -= amt; 253 if (bytesLeft < 0) { 254 amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised. 255 } 256 err = dataStream->WriteEntityData(buf, amt); 257 if (err != 0) { 258 free(buf); 259 return err; 260 } 261 } 262 if (bytesLeft != 0) { 263 if (bytesLeft > 0) { 264 // Pad out the space we promised in the buffer. We can't corrupt the buffer, 265 // even though the data we're sending is probably bad. 266 memset(buf, 0, bufsize); 267 while (bytesLeft > 0) { 268 amt = bytesLeft < bufsize ? bytesLeft : bufsize; 269 bytesLeft -= amt; 270 err = dataStream->WriteEntityData(buf, amt); 271 if (err != 0) { 272 free(buf); 273 return err; 274 } 275 } 276 } 277 ALOGE("write_update_file size mismatch for %s. expected=%d actual=%d." 278 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft); 279 } 280 281 free(buf); 282 return NO_ERROR; 283} 284 285static int 286write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename) 287{ 288 int err; 289 struct stat st; 290 291 err = stat(realFilename, &st); 292 if (err < 0) { 293 return errno; 294 } 295 296 int fd = open(realFilename, O_RDONLY); 297 if (fd == -1) { 298 return errno; 299 } 300 301 err = write_update_file(dataStream, fd, st.st_mode, key, realFilename); 302 close(fd); 303 return err; 304} 305 306static int 307compute_crc32(const char* file, FileRec* out) { 308 int fd = open(file, O_RDONLY); 309 if (fd < 0) { 310 return -1; 311 } 312 313 const int bufsize = 4*1024; 314 int amt; 315 316 char* buf = (char*)malloc(bufsize); 317 int crc = crc32(0L, Z_NULL, 0); 318 319 lseek(fd, 0, SEEK_SET); 320 321 while ((amt = read(fd, buf, bufsize)) != 0) { 322 crc = crc32(crc, (Bytef*)buf, amt); 323 } 324 325 close(fd); 326 free(buf); 327 328 out->s.crc32 = crc; 329 return NO_ERROR; 330} 331 332int 333back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD, 334 char const* const* files, char const* const* keys, int fileCount) 335{ 336 int err; 337 KeyedVector<String8,FileState> oldSnapshot; 338 KeyedVector<String8,FileRec> newSnapshot; 339 340 if (oldSnapshotFD != -1) { 341 err = read_snapshot_file(oldSnapshotFD, &oldSnapshot); 342 if (err != 0) { 343 // On an error, treat this as a full backup. 344 oldSnapshot.clear(); 345 } 346 } 347 348 for (int i=0; i<fileCount; i++) { 349 String8 key(keys[i]); 350 FileRec r; 351 char const* file = files[i]; 352 r.file = file; 353 struct stat st; 354 355 err = stat(file, &st); 356 if (err != 0) { 357 // not found => treat as deleted 358 continue; 359 } else { 360 r.deleted = false; 361 r.s.modTime_sec = st.st_mtime; 362 r.s.modTime_nsec = 0; // workaround sim breakage 363 //r.s.modTime_nsec = st.st_mtime_nsec; 364 r.s.mode = st.st_mode; 365 r.s.size = st.st_size; 366 367 if (newSnapshot.indexOfKey(key) >= 0) { 368 LOGP("back_up_files key already in use '%s'", key.string()); 369 return -1; 370 } 371 372 // compute the CRC 373 if (compute_crc32(file, &r) != NO_ERROR) { 374 ALOGW("Unable to open file %s", file); 375 continue; 376 } 377 } 378 newSnapshot.add(key, r); 379 } 380 381 int n = 0; 382 int N = oldSnapshot.size(); 383 int m = 0; 384 int M = newSnapshot.size(); 385 386 while (n<N && m<M) { 387 const String8& p = oldSnapshot.keyAt(n); 388 const String8& q = newSnapshot.keyAt(m); 389 FileRec& g = newSnapshot.editValueAt(m); 390 int cmp = p.compare(q); 391 if (cmp < 0) { 392 // file present in oldSnapshot, but not present in newSnapshot 393 LOGP("file removed: %s", p.string()); 394 write_delete_file(dataStream, p); 395 n++; 396 } else if (cmp > 0) { 397 // file added 398 LOGP("file added: %s crc=0x%08x", g.file.string(), g.s.crc32); 399 write_update_file(dataStream, q, g.file.string()); 400 m++; 401 } else { 402 // same file exists in both old and new; check whether to update 403 const FileState& f = oldSnapshot.valueAt(n); 404 405 LOGP("%s", q.string()); 406 LOGP(" old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x", 407 f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32); 408 LOGP(" new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x", 409 g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32); 410 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec 411 || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) { 412 int fd = open(g.file.string(), O_RDONLY); 413 if (fd < 0) { 414 ALOGE("Unable to read file for backup: %s", g.file.string()); 415 } else { 416 write_update_file(dataStream, fd, g.s.mode, p, g.file.string()); 417 close(fd); 418 } 419 } 420 n++; 421 m++; 422 } 423 } 424 425 // these were deleted 426 while (n<N) { 427 write_delete_file(dataStream, oldSnapshot.keyAt(n)); 428 n++; 429 } 430 431 // these were added 432 while (m<M) { 433 const String8& q = newSnapshot.keyAt(m); 434 FileRec& g = newSnapshot.editValueAt(m); 435 write_update_file(dataStream, q, g.file.string()); 436 m++; 437 } 438 439 err = write_snapshot_file(newSnapshotFD, newSnapshot); 440 441 return 0; 442} 443 444static void calc_tar_checksum(char* buf, size_t buf_size) { 445 // [ 148 : 8 ] checksum -- to be calculated with this field as space chars 446 memset(buf + 148, ' ', 8); 447 448 uint16_t sum = 0; 449 for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) { 450 sum += *p; 451 } 452 453 // Now write the real checksum value: 454 // [ 148 : 8 ] checksum: 6 octal digits [leading zeroes], NUL, SPC 455 snprintf(buf + 148, buf_size - 148, "%06o", sum); // the trailing space is 456 // already in place 457} 458 459// Returns number of bytes written 460static int write_pax_header_entry(char* buf, size_t buf_size, 461 const char* key, const char* value) { 462 // start with the size of "1 key=value\n" 463 int len = strlen(key) + strlen(value) + 4; 464 if (len > 9) len++; 465 if (len > 99) len++; 466 if (len > 999) len++; 467 // since PATH_MAX is 4096 we don't expect to have to generate any single 468 // header entry longer than 9999 characters 469 470 return snprintf(buf, buf_size, "%d %s=%s\n", len, key, value); 471} 472 473// Wire format to the backup manager service is chunked: each chunk is prefixed by 474// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD. 475void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) { 476 uint32_t chunk_size_no = htonl(size); 477 writer->WriteEntityData(&chunk_size_no, 4); 478 if (size != 0) writer->WriteEntityData(buffer, size); 479} 480 481int write_tarfile(const String8& packageName, const String8& domain, 482 const String8& rootpath, const String8& filepath, off_t* outSize, 483 BackupDataWriter* writer) 484{ 485 // In the output stream everything is stored relative to the root 486 const char* relstart = filepath.string() + rootpath.length(); 487 if (*relstart == '/') relstart++; // won't be true when path == rootpath 488 String8 relpath(relstart); 489 490 // If relpath is empty, it means this is the top of one of the standard named 491 // domain directories, so we should just skip it 492 if (relpath.length() == 0) { 493 *outSize = 0; 494 return 0; 495 } 496 497 // Too long a name for the ustar format? 498 // "apps/" + packagename + '/' + domainpath < 155 chars 499 // relpath < 100 chars 500 bool needExtended = false; 501 if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) { 502 needExtended = true; 503 } 504 505 // Non-7bit-clean path also means needing pax extended format 506 if (!needExtended) { 507 for (size_t i = 0; i < filepath.length(); i++) { 508 if ((filepath[i] & 0x80) != 0) { 509 needExtended = true; 510 break; 511 } 512 } 513 } 514 515 int err = 0; 516 struct stat64 s; 517 if (lstat64(filepath.string(), &s) != 0) { 518 err = errno; 519 ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string()); 520 return err; 521 } 522 523 // very large files need a pax extended size header 524 if (s.st_size > 077777777777LL) { 525 needExtended = true; 526 } 527 528 String8 fullname; // for pax later on 529 String8 prefix; 530 531 const int isdir = S_ISDIR(s.st_mode); 532 if (isdir) s.st_size = 0; // directories get no actual data in the tar stream 533 534 // Report the size, including a rough tar overhead estimation: 512 bytes for the 535 // overall tar file-block header, plus 2 blocks if using the pax extended format, 536 // plus the raw content size rounded up to a multiple of 512. 537 *outSize = 512 + (needExtended ? 1024 : 0) + 512*((s.st_size + 511)/512); 538 539 // Measure case: we've returned the size; now return without moving data 540 if (!writer) return 0; 541 542 // !!! TODO: use mmap when possible to avoid churning the buffer cache 543 // !!! TODO: this will break with symlinks; need to use readlink(2) 544 int fd = open(filepath.string(), O_RDONLY); 545 if (fd < 0) { 546 err = errno; 547 ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string()); 548 return err; 549 } 550 551 // read/write up to this much at a time. 552 const size_t BUFSIZE = 32 * 1024; 553 char* buf = (char *)calloc(1,BUFSIZE); 554 const size_t PAXHEADER_OFFSET = 512; 555 const size_t PAXHEADER_SIZE = 512; 556 const size_t PAXDATA_SIZE = BUFSIZE - (PAXHEADER_SIZE + PAXHEADER_OFFSET); 557 char* const paxHeader = buf + PAXHEADER_OFFSET; // use a different chunk of 558 // it as separate scratch 559 char* const paxData = paxHeader + PAXHEADER_SIZE; 560 561 if (buf == NULL) { 562 ALOGE("Out of mem allocating transfer buffer"); 563 err = ENOMEM; 564 goto done; 565 } 566 567 // Magic fields for the ustar file format 568 strcat(buf + 257, "ustar"); 569 strcat(buf + 263, "00"); 570 571 // [ 265 : 32 ] user name, ignored on restore 572 // [ 297 : 32 ] group name, ignored on restore 573 574 // [ 100 : 8 ] file mode 575 snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT); 576 577 // [ 108 : 8 ] uid -- ignored in Android format; uids are remapped at restore time 578 // [ 116 : 8 ] gid -- ignored in Android format 579 snprintf(buf + 108, 8, "0%lo", (unsigned long)s.st_uid); 580 snprintf(buf + 116, 8, "0%lo", (unsigned long)s.st_gid); 581 582 // [ 124 : 12 ] file size in bytes 583 snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size); 584 585 // [ 136 : 12 ] last mod time as a UTC time_t 586 snprintf(buf + 136, 12, "%0lo", (unsigned long)s.st_mtime); 587 588 // [ 156 : 1 ] link/file type 589 uint8_t type; 590 if (isdir) { 591 type = '5'; // tar magic: '5' == directory 592 } else if (S_ISREG(s.st_mode)) { 593 type = '0'; // tar magic: '0' == normal file 594 } else { 595 ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string()); 596 goto cleanup; 597 } 598 buf[156] = type; 599 600 // [ 157 : 100 ] name of linked file [not implemented] 601 602 { 603 // Prefix and main relative path. Path lengths have been preflighted. 604 if (packageName.length() > 0) { 605 prefix = "apps/"; 606 prefix += packageName; 607 } 608 if (domain.length() > 0) { 609 prefix.appendPath(domain); 610 } 611 612 // pax extended means we don't put in a prefix field, and put a different 613 // string in the basic name field. We can also construct the full path name 614 // out of the substrings we've now built. 615 fullname = prefix; 616 fullname.appendPath(relpath); 617 618 // ustar: 619 // [ 0 : 100 ]; file name/path 620 // [ 345 : 155 ] filename path prefix 621 // We only use the prefix area if fullname won't fit in the path 622 if (fullname.length() > 100) { 623 strncpy(buf, relpath.string(), 100); 624 strncpy(buf + 345, prefix.string(), 155); 625 } else { 626 strncpy(buf, fullname.string(), 100); 627 } 628 } 629 630 // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used 631 632 ALOGI(" Name: %s", fullname.string()); 633 634 // If we're using a pax extended header, build & write that here; lengths are 635 // already preflighted 636 if (needExtended) { 637 char sizeStr[32]; // big enough for a 64-bit unsigned value in decimal 638 639 // construct the pax extended header data block 640 memset(paxData, 0, PAXDATA_SIZE); 641 642 // size header -- calc len in digits by actually rendering the number 643 // to a string - brute force but simple 644 int paxLen = 0; 645 snprintf(sizeStr, sizeof(sizeStr), "%lld", (long long)s.st_size); 646 paxLen += write_pax_header_entry(paxData, PAXDATA_SIZE, "size", sizeStr); 647 648 // fullname was generated above with the ustar paths 649 paxLen += write_pax_header_entry(paxData + paxLen, PAXDATA_SIZE - paxLen, 650 "path", fullname.string()); 651 652 // Now we know how big the pax data is 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)paxLen); 668 669 // Checksum and write the pax block header 670 calc_tar_checksum(paxHeader, PAXHEADER_SIZE); 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, BUFSIZE); 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 718cleanup: 719 free(buf); 720done: 721 close(fd); 722 return err; 723} 724// end tarfile 725 726 727 728#define RESTORE_BUF_SIZE (8*1024) 729 730RestoreHelperBase::RestoreHelperBase() 731{ 732 m_buf = malloc(RESTORE_BUF_SIZE); 733 m_loggedUnknownMetadata = false; 734} 735 736RestoreHelperBase::~RestoreHelperBase() 737{ 738 free(m_buf); 739} 740 741status_t 742RestoreHelperBase::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 821status_t 822RestoreHelperBase::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 831static int 832write_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 856static int 857compare_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 903int 904backup_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 962int 963backup_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 1118const 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}; 1141const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE); 1142 1143static int 1144test_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 1164int 1165backup_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 1199int 1200test_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 size_t actualSize; 1207 bool done; 1208 int type; 1209 ssize_t nRead; 1210 1211 // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str); 1212 1213 err = reader.ReadNextHeader(&done, &type); 1214 if (done) { 1215 fprintf(stderr, "should not be done yet\n"); 1216 goto finished; 1217 } 1218 if (err != 0) { 1219 fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err)); 1220 goto finished; 1221 } 1222 if (type != BACKUP_HEADER_ENTITY_V1) { 1223 err = EINVAL; 1224 fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1); 1225 } 1226 1227 err = reader.ReadEntityHeader(&string, &actualSize); 1228 if (err != 0) { 1229 fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err)); 1230 goto finished; 1231 } 1232 if (string != str) { 1233 fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string()); 1234 err = EINVAL; 1235 goto finished; 1236 } 1237 if (actualSize != bufSize) { 1238 fprintf(stderr, "ReadEntityHeader expected dataSize %zu got %zu\n", 1239 bufSize, actualSize); 1240 err = EINVAL; 1241 goto finished; 1242 } 1243 1244 nRead = reader.ReadEntityData(buf, bufSize); 1245 if (nRead < 0) { 1246 err = reader.Status(); 1247 fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err)); 1248 goto finished; 1249 } 1250 1251 if (0 != memcmp(buf, str, bufSize)) { 1252 fprintf(stderr, "ReadEntityData expected '%s' but got something starting with " 1253 "%02x %02x %02x %02x '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3], 1254 buf[0], buf[1], buf[2], buf[3]); 1255 err = EINVAL; 1256 goto finished; 1257 } 1258 1259 // The next read will confirm whether it got the right amount of data. 1260 1261finished: 1262 if (err != NO_ERROR) { 1263 fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err)); 1264 } 1265 free(buf); 1266 return err; 1267} 1268 1269int 1270backup_helper_test_data_reader() 1271{ 1272 int err; 1273 int fd; 1274 const char* filename = SCRATCH_DIR "data_reader.data"; 1275 1276 system("rm -r " SCRATCH_DIR); 1277 mkdir(SCRATCH_DIR, 0777); 1278 mkdir(SCRATCH_DIR "data", 0777); 1279 1280 fd = creat(filename, 0666); 1281 if (fd == -1) { 1282 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1283 return errno; 1284 } 1285 1286 err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE); 1287 if (err != DATA_GOLDEN_FILE_SIZE) { 1288 fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename); 1289 return errno; 1290 } 1291 1292 close(fd); 1293 1294 fd = open(filename, O_RDONLY); 1295 if (fd == -1) { 1296 fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno), 1297 filename); 1298 return errno; 1299 } 1300 1301 { 1302 BackupDataReader reader(fd); 1303 1304 err = 0; 1305 1306 if (err == NO_ERROR) { 1307 err = test_read_header_and_entity(reader, "no_padding_"); 1308 } 1309 1310 if (err == NO_ERROR) { 1311 err = test_read_header_and_entity(reader, "padded_to__3"); 1312 } 1313 1314 if (err == NO_ERROR) { 1315 err = test_read_header_and_entity(reader, "padded_to_2__"); 1316 } 1317 1318 if (err == NO_ERROR) { 1319 err = test_read_header_and_entity(reader, "padded_to1"); 1320 } 1321 } 1322 1323 close(fd); 1324 1325 return err; 1326} 1327 1328static int 1329get_mod_time(const char* filename, struct timeval times[2]) 1330{ 1331 int err; 1332 struct stat64 st; 1333 err = stat64(filename, &st); 1334 if (err != 0) { 1335 fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno)); 1336 return errno; 1337 } 1338 1339 times[0].tv_sec = st.st_atim.tv_sec; 1340 times[0].tv_usec = st.st_atim.tv_nsec / 1000; 1341 1342 times[1].tv_sec = st.st_mtim.tv_sec; 1343 times[1].tv_usec = st.st_mtim.tv_nsec / 1000; 1344 1345 return 0; 1346} 1347 1348int 1349backup_helper_test_files() 1350{ 1351 int err; 1352 int oldSnapshotFD; 1353 int dataStreamFD; 1354 int newSnapshotFD; 1355 1356 system("rm -r " SCRATCH_DIR); 1357 mkdir(SCRATCH_DIR, 0777); 1358 mkdir(SCRATCH_DIR "data", 0777); 1359 1360 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n"); 1361 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n"); 1362 write_text_file(SCRATCH_DIR "data/d", "d\ndd\n"); 1363 write_text_file(SCRATCH_DIR "data/e", "e\nee\n"); 1364 write_text_file(SCRATCH_DIR "data/f", "f\nff\n"); 1365 write_text_file(SCRATCH_DIR "data/h", "h\nhh\n"); 1366 1367 char const* files_before[] = { 1368 SCRATCH_DIR "data/b", 1369 SCRATCH_DIR "data/c", 1370 SCRATCH_DIR "data/d", 1371 SCRATCH_DIR "data/e", 1372 SCRATCH_DIR "data/f" 1373 }; 1374 1375 char const* keys_before[] = { 1376 "data/b", 1377 "data/c", 1378 "data/d", 1379 "data/e", 1380 "data/f" 1381 }; 1382 1383 dataStreamFD = creat(SCRATCH_DIR "1.data", 0666); 1384 if (dataStreamFD == -1) { 1385 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1386 return errno; 1387 } 1388 1389 newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666); 1390 if (newSnapshotFD == -1) { 1391 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1392 return errno; 1393 } 1394 1395 { 1396 BackupDataWriter dataStream(dataStreamFD); 1397 1398 err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5); 1399 if (err != 0) { 1400 return err; 1401 } 1402 } 1403 1404 close(dataStreamFD); 1405 close(newSnapshotFD); 1406 1407 sleep(3); 1408 1409 struct timeval d_times[2]; 1410 struct timeval e_times[2]; 1411 1412 err = get_mod_time(SCRATCH_DIR "data/d", d_times); 1413 err |= get_mod_time(SCRATCH_DIR "data/e", e_times); 1414 if (err != 0) { 1415 return err; 1416 } 1417 1418 write_text_file(SCRATCH_DIR "data/a", "a\naa\n"); 1419 unlink(SCRATCH_DIR "data/c"); 1420 write_text_file(SCRATCH_DIR "data/c", "c\ncc\n"); 1421 write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n"); 1422 utimes(SCRATCH_DIR "data/d", d_times); 1423 write_text_file(SCRATCH_DIR "data/e", "z\nzz\n"); 1424 utimes(SCRATCH_DIR "data/e", e_times); 1425 write_text_file(SCRATCH_DIR "data/g", "g\ngg\n"); 1426 unlink(SCRATCH_DIR "data/f"); 1427 1428 char const* files_after[] = { 1429 SCRATCH_DIR "data/a", // added 1430 SCRATCH_DIR "data/b", // same 1431 SCRATCH_DIR "data/c", // different mod time 1432 SCRATCH_DIR "data/d", // different size (same mod time) 1433 SCRATCH_DIR "data/e", // different contents (same mod time, same size) 1434 SCRATCH_DIR "data/g" // added 1435 }; 1436 1437 char const* keys_after[] = { 1438 "data/a", // added 1439 "data/b", // same 1440 "data/c", // different mod time 1441 "data/d", // different size (same mod time) 1442 "data/e", // different contents (same mod time, same size) 1443 "data/g" // added 1444 }; 1445 1446 oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY); 1447 if (oldSnapshotFD == -1) { 1448 fprintf(stderr, "error opening: %s\n", strerror(errno)); 1449 return errno; 1450 } 1451 1452 dataStreamFD = creat(SCRATCH_DIR "2.data", 0666); 1453 if (dataStreamFD == -1) { 1454 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1455 return errno; 1456 } 1457 1458 newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666); 1459 if (newSnapshotFD == -1) { 1460 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1461 return errno; 1462 } 1463 1464 { 1465 BackupDataWriter dataStream(dataStreamFD); 1466 1467 err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6); 1468 if (err != 0) { 1469 return err; 1470 } 1471} 1472 1473 close(oldSnapshotFD); 1474 close(dataStreamFD); 1475 close(newSnapshotFD); 1476 1477 return 0; 1478} 1479 1480int 1481backup_helper_test_null_base() 1482{ 1483 int err; 1484 int dataStreamFD; 1485 int newSnapshotFD; 1486 1487 system("rm -r " SCRATCH_DIR); 1488 mkdir(SCRATCH_DIR, 0777); 1489 mkdir(SCRATCH_DIR "data", 0777); 1490 1491 write_text_file(SCRATCH_DIR "data/a", "a\naa\n"); 1492 1493 char const* files[] = { 1494 SCRATCH_DIR "data/a", 1495 }; 1496 1497 char const* keys[] = { 1498 "a", 1499 }; 1500 1501 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666); 1502 if (dataStreamFD == -1) { 1503 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1504 return errno; 1505 } 1506 1507 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666); 1508 if (newSnapshotFD == -1) { 1509 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1510 return errno; 1511 } 1512 1513 { 1514 BackupDataWriter dataStream(dataStreamFD); 1515 1516 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1); 1517 if (err != 0) { 1518 return err; 1519 } 1520 } 1521 1522 close(dataStreamFD); 1523 close(newSnapshotFD); 1524 1525 return 0; 1526} 1527 1528int 1529backup_helper_test_missing_file() 1530{ 1531 int err; 1532 int dataStreamFD; 1533 int newSnapshotFD; 1534 1535 system("rm -r " SCRATCH_DIR); 1536 mkdir(SCRATCH_DIR, 0777); 1537 mkdir(SCRATCH_DIR "data", 0777); 1538 1539 write_text_file(SCRATCH_DIR "data/b", "b\nbb\n"); 1540 1541 char const* files[] = { 1542 SCRATCH_DIR "data/a", 1543 SCRATCH_DIR "data/b", 1544 SCRATCH_DIR "data/c", 1545 }; 1546 1547 char const* keys[] = { 1548 "a", 1549 "b", 1550 "c", 1551 }; 1552 1553 dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666); 1554 if (dataStreamFD == -1) { 1555 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1556 return errno; 1557 } 1558 1559 newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666); 1560 if (newSnapshotFD == -1) { 1561 fprintf(stderr, "error creating: %s\n", strerror(errno)); 1562 return errno; 1563 } 1564 1565 { 1566 BackupDataWriter dataStream(dataStreamFD); 1567 1568 err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1); 1569 if (err != 0) { 1570 return err; 1571 } 1572 } 1573 1574 close(dataStreamFD); 1575 close(newSnapshotFD); 1576 1577 return 0; 1578} 1579 1580 1581#endif // TEST_BACKUP_HELPERS 1582 1583} 1584