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