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