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