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