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