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