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