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