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