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