• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "file_backup_helper"
18 
19 #include <utils/BackupHelpers.h>
20 
21 #include <utils/KeyedVector.h>
22 #include <utils/ByteOrder.h>
23 #include <utils/String8.h>
24 
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/uio.h>
28 #include <sys/stat.h>
29 #include <sys/time.h>  // for utimes
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <utime.h>
34 #include <fcntl.h>
35 #include <zlib.h>
36 
37 #include <cutils/log.h>
38 
39 namespace android {
40 
41 #define MAGIC0 0x70616e53 // Snap
42 #define MAGIC1 0x656c6946 // File
43 
44 /*
45  * File entity data format (v1):
46  *
47  *   - 4-byte version number of the metadata, little endian (0x00000001 for v1)
48  *   - 12 bytes of metadata
49  *   - the file data itself
50  *
51  * i.e. a 16-byte metadata header followed by the raw file data.  If the
52  * restore code does not recognize the metadata version, it can still
53  * interpret the file data itself correctly.
54  *
55  * file_metadata_v1:
56  *
57  *   - 4 byte version number === 0x00000001 (little endian)
58  *   - 4-byte access mode (little-endian)
59  *   - undefined (8 bytes)
60  */
61 
62 struct file_metadata_v1 {
63     int version;
64     int mode;
65     int undefined_1;
66     int undefined_2;
67 };
68 
69 const static int CURRENT_METADATA_VERSION = 1;
70 
71 #if 1
72 #define LOGP(f, x...)
73 #else
74 #if TEST_BACKUP_HELPERS
75 #define LOGP(f, x...) printf(f "\n", x)
76 #else
77 #define LOGP(x...) LOGD(x)
78 #endif
79 #endif
80 
81 const static int ROUND_UP[4] = { 0, 3, 2, 1 };
82 
83 static inline int
round_up(int n)84 round_up(int n)
85 {
86     return n + ROUND_UP[n % 4];
87 }
88 
89 static int
read_snapshot_file(int fd,KeyedVector<String8,FileState> * snapshot)90 read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
91 {
92     int bytesRead = 0;
93     int amt;
94     SnapshotHeader header;
95 
96     amt = read(fd, &header, sizeof(header));
97     if (amt != sizeof(header)) {
98         return errno;
99     }
100     bytesRead += amt;
101 
102     if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
103         LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
104         return 1;
105     }
106 
107     for (int i=0; i<header.fileCount; i++) {
108         FileState file;
109         char filenameBuf[128];
110 
111         amt = read(fd, &file, sizeof(FileState));
112         if (amt != sizeof(FileState)) {
113             LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
114             return 1;
115         }
116         bytesRead += amt;
117 
118         // filename is not NULL terminated, but it is padded
119         int nameBufSize = round_up(file.nameLen);
120         char* filename = nameBufSize <= (int)sizeof(filenameBuf)
121                 ? filenameBuf
122                 : (char*)malloc(nameBufSize);
123         amt = read(fd, filename, nameBufSize);
124         if (amt == nameBufSize) {
125             snapshot->add(String8(filename, file.nameLen), file);
126         }
127         bytesRead += amt;
128         if (filename != filenameBuf) {
129             free(filename);
130         }
131         if (amt != nameBufSize) {
132             LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
133             return 1;
134         }
135     }
136 
137     if (header.totalSize != bytesRead) {
138         LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
139                 header.totalSize, bytesRead);
140         return 1;
141     }
142 
143     return 0;
144 }
145 
146 static int
write_snapshot_file(int fd,const KeyedVector<String8,FileRec> & snapshot)147 write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
148 {
149     int fileCount = 0;
150     int bytesWritten = sizeof(SnapshotHeader);
151     // preflight size
152     const int N = snapshot.size();
153     for (int i=0; i<N; i++) {
154         const FileRec& g = snapshot.valueAt(i);
155         if (!g.deleted) {
156             const String8& name = snapshot.keyAt(i);
157             bytesWritten += sizeof(FileState) + round_up(name.length());
158             fileCount++;
159         }
160     }
161 
162     LOGP("write_snapshot_file fd=%d\n", fd);
163 
164     int amt;
165     SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
166 
167     amt = write(fd, &header, sizeof(header));
168     if (amt != sizeof(header)) {
169         LOGW("write_snapshot_file error writing header %s", strerror(errno));
170         return errno;
171     }
172 
173     for (int i=0; i<N; i++) {
174         FileRec r = snapshot.valueAt(i);
175         if (!r.deleted) {
176             const String8& name = snapshot.keyAt(i);
177             int nameLen = r.s.nameLen = name.length();
178 
179             amt = write(fd, &r.s, sizeof(FileState));
180             if (amt != sizeof(FileState)) {
181                 LOGW("write_snapshot_file error writing header %s", strerror(errno));
182                 return 1;
183             }
184 
185             // filename is not NULL terminated, but it is padded
186             amt = write(fd, name.string(), nameLen);
187             if (amt != nameLen) {
188                 LOGW("write_snapshot_file error writing filename %s", strerror(errno));
189                 return 1;
190             }
191             int paddingLen = ROUND_UP[nameLen % 4];
192             if (paddingLen != 0) {
193                 int padding = 0xabababab;
194                 amt = write(fd, &padding, paddingLen);
195                 if (amt != paddingLen) {
196                     LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
197                             paddingLen, strerror(errno));
198                     return 1;
199                 }
200             }
201         }
202     }
203 
204     return 0;
205 }
206 
207 static int
write_delete_file(BackupDataWriter * dataStream,const String8 & key)208 write_delete_file(BackupDataWriter* dataStream, const String8& key)
209 {
210     LOGP("write_delete_file %s\n", key.string());
211     return dataStream->WriteEntityHeader(key, -1);
212 }
213 
214 static int
write_update_file(BackupDataWriter * dataStream,int fd,int mode,const String8 & key,char const * realFilename)215 write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
216         char const* realFilename)
217 {
218     LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
219 
220     const int bufsize = 4*1024;
221     int err;
222     int amt;
223     int fileSize;
224     int bytesLeft;
225     file_metadata_v1 metadata;
226 
227     char* buf = (char*)malloc(bufsize);
228     int crc = crc32(0L, Z_NULL, 0);
229 
230 
231     fileSize = lseek(fd, 0, SEEK_END);
232     lseek(fd, 0, SEEK_SET);
233 
234     if (sizeof(metadata) != 16) {
235         LOGE("ERROR: metadata block is the wrong size!");
236     }
237 
238     bytesLeft = fileSize + sizeof(metadata);
239     err = dataStream->WriteEntityHeader(key, bytesLeft);
240     if (err != 0) {
241         free(buf);
242         return err;
243     }
244 
245     // store the file metadata first
246     metadata.version = tolel(CURRENT_METADATA_VERSION);
247     metadata.mode = tolel(mode);
248     metadata.undefined_1 = metadata.undefined_2 = 0;
249     err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
250     if (err != 0) {
251         free(buf);
252         return err;
253     }
254     bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
255 
256     // now store the file content
257     while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
258         bytesLeft -= amt;
259         if (bytesLeft < 0) {
260             amt += bytesLeft; // Plus a negative is minus.  Don't write more than we promised.
261         }
262         err = dataStream->WriteEntityData(buf, amt);
263         if (err != 0) {
264             free(buf);
265             return err;
266         }
267     }
268     if (bytesLeft != 0) {
269         if (bytesLeft > 0) {
270             // Pad out the space we promised in the buffer.  We can't corrupt the buffer,
271             // even though the data we're sending is probably bad.
272             memset(buf, 0, bufsize);
273             while (bytesLeft > 0) {
274                 amt = bytesLeft < bufsize ? bytesLeft : bufsize;
275                 bytesLeft -= amt;
276                 err = dataStream->WriteEntityData(buf, amt);
277                 if (err != 0) {
278                     free(buf);
279                     return err;
280                 }
281             }
282         }
283         LOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
284                 " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
285     }
286 
287     free(buf);
288     return NO_ERROR;
289 }
290 
291 static int
write_update_file(BackupDataWriter * dataStream,const String8 & key,char const * realFilename)292 write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
293 {
294     int err;
295     struct stat st;
296 
297     err = stat(realFilename, &st);
298     if (err < 0) {
299         return errno;
300     }
301 
302     int fd = open(realFilename, O_RDONLY);
303     if (fd == -1) {
304         return errno;
305     }
306 
307     err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
308     close(fd);
309     return err;
310 }
311 
312 static int
compute_crc32(int fd)313 compute_crc32(int fd)
314 {
315     const int bufsize = 4*1024;
316     int amt;
317 
318     char* buf = (char*)malloc(bufsize);
319     int crc = crc32(0L, Z_NULL, 0);
320 
321     lseek(fd, 0, SEEK_SET);
322 
323     while ((amt = read(fd, buf, bufsize)) != 0) {
324         crc = crc32(crc, (Bytef*)buf, amt);
325     }
326 
327     free(buf);
328     return crc;
329 }
330 
331 int
back_up_files(int oldSnapshotFD,BackupDataWriter * dataStream,int newSnapshotFD,char const * const * files,char const * const * keys,int fileCount)332 back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
333         char const* const* files, char const* const* keys, int fileCount)
334 {
335     int err;
336     KeyedVector<String8,FileState> oldSnapshot;
337     KeyedVector<String8,FileRec> newSnapshot;
338 
339     if (oldSnapshotFD != -1) {
340         err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
341         if (err != 0) {
342             // On an error, treat this as a full backup.
343             oldSnapshot.clear();
344         }
345     }
346 
347     for (int i=0; i<fileCount; i++) {
348         String8 key(keys[i]);
349         FileRec r;
350         char const* file = files[i];
351         r.file = file;
352         struct stat st;
353 
354         err = stat(file, &st);
355         if (err != 0) {
356             r.deleted = true;
357         } else {
358             r.deleted = false;
359             r.s.modTime_sec = st.st_mtime;
360             r.s.modTime_nsec = 0; // workaround sim breakage
361             //r.s.modTime_nsec = st.st_mtime_nsec;
362             r.s.mode = st.st_mode;
363             r.s.size = st.st_size;
364             // we compute the crc32 later down below, when we already have the file open.
365 
366             if (newSnapshot.indexOfKey(key) >= 0) {
367                 LOGP("back_up_files key already in use '%s'", key.string());
368                 return -1;
369             }
370         }
371         newSnapshot.add(key, r);
372     }
373 
374     int n = 0;
375     int N = oldSnapshot.size();
376     int m = 0;
377 
378     while (n<N && m<fileCount) {
379         const String8& p = oldSnapshot.keyAt(n);
380         const String8& q = newSnapshot.keyAt(m);
381         FileRec& g = newSnapshot.editValueAt(m);
382         int cmp = p.compare(q);
383         if (g.deleted || cmp < 0) {
384             // file removed
385             LOGP("file removed: %s", p.string());
386             g.deleted = true; // They didn't mention the file, but we noticed that it's gone.
387             dataStream->WriteEntityHeader(p, -1);
388             n++;
389         }
390         else if (cmp > 0) {
391             // file added
392             LOGP("file added: %s", g.file.string());
393             write_update_file(dataStream, q, g.file.string());
394             m++;
395         }
396         else {
397             // both files exist, check them
398             const FileState& f = oldSnapshot.valueAt(n);
399 
400             int fd = open(g.file.string(), O_RDONLY);
401             if (fd < 0) {
402                 // We can't open the file.  Don't report it as a delete either.  Let the
403                 // server keep the old version.  Maybe they'll be able to deal with it
404                 // on restore.
405                 LOGP("Unable to open file %s - skipping", g.file.string());
406             } else {
407                 g.s.crc32 = compute_crc32(fd);
408 
409                 LOGP("%s", q.string());
410                 LOGP("  new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
411                         f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
412                 LOGP("  old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
413                         g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
414                 if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
415                         || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
416                     write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
417                 }
418 
419                 close(fd);
420             }
421             n++;
422             m++;
423         }
424     }
425 
426     // these were deleted
427     while (n<N) {
428         dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
429         n++;
430     }
431 
432     // these were added
433     while (m<fileCount) {
434         const String8& q = newSnapshot.keyAt(m);
435         FileRec& g = newSnapshot.editValueAt(m);
436         write_update_file(dataStream, q, g.file.string());
437         m++;
438     }
439 
440     err = write_snapshot_file(newSnapshotFD, newSnapshot);
441 
442     return 0;
443 }
444 
445 #define RESTORE_BUF_SIZE (8*1024)
446 
RestoreHelperBase()447 RestoreHelperBase::RestoreHelperBase()
448 {
449     m_buf = malloc(RESTORE_BUF_SIZE);
450     m_loggedUnknownMetadata = false;
451 }
452 
~RestoreHelperBase()453 RestoreHelperBase::~RestoreHelperBase()
454 {
455     free(m_buf);
456 }
457 
458 status_t
WriteFile(const String8 & filename,BackupDataReader * in)459 RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
460 {
461     ssize_t err;
462     size_t dataSize;
463     String8 key;
464     int fd;
465     void* buf = m_buf;
466     ssize_t amt;
467     int mode;
468     int crc;
469     struct stat st;
470     FileRec r;
471 
472     err = in->ReadEntityHeader(&key, &dataSize);
473     if (err != NO_ERROR) {
474         return err;
475     }
476 
477     // Get the metadata block off the head of the file entity and use that to
478     // set up the output file
479     file_metadata_v1 metadata;
480     amt = in->ReadEntityData(&metadata, sizeof(metadata));
481     if (amt != sizeof(metadata)) {
482         LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
483                 (long)amt, strerror(errno));
484         return EIO;
485     }
486     metadata.version = fromlel(metadata.version);
487     metadata.mode = fromlel(metadata.mode);
488     if (metadata.version > CURRENT_METADATA_VERSION) {
489         if (!m_loggedUnknownMetadata) {
490             m_loggedUnknownMetadata = true;
491             LOGW("Restoring file with unsupported metadata version %d (currently %d)",
492                     metadata.version, CURRENT_METADATA_VERSION);
493         }
494     }
495     mode = metadata.mode;
496 
497     // Write the file and compute the crc
498     crc = crc32(0L, Z_NULL, 0);
499     fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
500     if (fd == -1) {
501         LOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
502         return errno;
503     }
504 
505     while ((amt = in->ReadEntityData(buf, RESTORE_BUF_SIZE)) > 0) {
506         err = write(fd, buf, amt);
507         if (err != amt) {
508             close(fd);
509             LOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
510             return errno;
511         }
512         crc = crc32(crc, (Bytef*)buf, amt);
513     }
514 
515     close(fd);
516 
517     // Record for the snapshot
518     err = stat(filename.string(), &st);
519     if (err != 0) {
520         LOGW("Error stating file that we just created %s", filename.string());
521         return errno;
522     }
523 
524     r.file = filename;
525     r.deleted = false;
526     r.s.modTime_sec = st.st_mtime;
527     r.s.modTime_nsec = 0; // workaround sim breakage
528     //r.s.modTime_nsec = st.st_mtime_nsec;
529     r.s.mode = st.st_mode;
530     r.s.size = st.st_size;
531     r.s.crc32 = crc;
532 
533     m_files.add(key, r);
534 
535     return NO_ERROR;
536 }
537 
538 status_t
WriteSnapshot(int fd)539 RestoreHelperBase::WriteSnapshot(int fd)
540 {
541     return write_snapshot_file(fd, m_files);;
542 }
543 
544 #if TEST_BACKUP_HELPERS
545 
546 #define SCRATCH_DIR "/data/backup_helper_test/"
547 
548 static int
write_text_file(const char * path,const char * data)549 write_text_file(const char* path, const char* data)
550 {
551     int amt;
552     int fd;
553     int len;
554 
555     fd = creat(path, 0666);
556     if (fd == -1) {
557         fprintf(stderr, "creat %s failed\n", path);
558         return errno;
559     }
560 
561     len = strlen(data);
562     amt = write(fd, data, len);
563     if (amt != len) {
564         fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
565         return errno;
566     }
567 
568     close(fd);
569 
570     return 0;
571 }
572 
573 static int
compare_file(const char * path,const unsigned char * data,int len)574 compare_file(const char* path, const unsigned char* data, int len)
575 {
576     int fd;
577     int amt;
578 
579     fd = open(path, O_RDONLY);
580     if (fd == -1) {
581         fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
582         return errno;
583     }
584 
585     unsigned char* contents = (unsigned char*)malloc(len);
586     if (contents == NULL) {
587         fprintf(stderr, "malloc(%d) failed\n", len);
588         return ENOMEM;
589     }
590 
591     bool sizesMatch = true;
592     amt = lseek(fd, 0, SEEK_END);
593     if (amt != len) {
594         fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
595         sizesMatch = false;
596     }
597     lseek(fd, 0, SEEK_SET);
598 
599     int readLen = amt < len ? amt : len;
600     amt = read(fd, contents, readLen);
601     if (amt != readLen) {
602         fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
603     }
604 
605     bool contentsMatch = true;
606     for (int i=0; i<readLen; i++) {
607         if (data[i] != contents[i]) {
608             if (contentsMatch) {
609                 fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
610                 contentsMatch = false;
611             }
612             fprintf(stderr, "  [%-2d] %02x %02x\n", i, data[i], contents[i]);
613         }
614     }
615 
616     free(contents);
617     return contentsMatch && sizesMatch ? 0 : 1;
618 }
619 
620 int
backup_helper_test_empty()621 backup_helper_test_empty()
622 {
623     int err;
624     int fd;
625     KeyedVector<String8,FileRec> snapshot;
626     const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
627 
628     system("rm -r " SCRATCH_DIR);
629     mkdir(SCRATCH_DIR, 0777);
630 
631     // write
632     fd = creat(filename, 0666);
633     if (fd == -1) {
634         fprintf(stderr, "error creating %s\n", filename);
635         return 1;
636     }
637 
638     err = write_snapshot_file(fd, snapshot);
639 
640     close(fd);
641 
642     if (err != 0) {
643         fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
644         return err;
645     }
646 
647     static const unsigned char correct_data[] = {
648         0x53, 0x6e, 0x61, 0x70,  0x00, 0x00, 0x00, 0x00,
649         0x46, 0x69, 0x6c, 0x65,  0x10, 0x00, 0x00, 0x00
650     };
651 
652     err = compare_file(filename, correct_data, sizeof(correct_data));
653     if (err != 0) {
654         return err;
655     }
656 
657     // read
658     fd = open(filename, O_RDONLY);
659     if (fd == -1) {
660         fprintf(stderr, "error opening for read %s\n", filename);
661         return 1;
662     }
663 
664     KeyedVector<String8,FileState> readSnapshot;
665     err = read_snapshot_file(fd, &readSnapshot);
666     if (err != 0) {
667         fprintf(stderr, "read_snapshot_file failed %d\n", err);
668         return err;
669     }
670 
671     if (readSnapshot.size() != 0) {
672         fprintf(stderr, "readSnapshot should be length 0\n");
673         return 1;
674     }
675 
676     return 0;
677 }
678 
679 int
backup_helper_test_four()680 backup_helper_test_four()
681 {
682     int err;
683     int fd;
684     KeyedVector<String8,FileRec> snapshot;
685     const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
686 
687     system("rm -r " SCRATCH_DIR);
688     mkdir(SCRATCH_DIR, 0777);
689 
690     // write
691     fd = creat(filename, 0666);
692     if (fd == -1) {
693         fprintf(stderr, "error opening %s\n", filename);
694         return 1;
695     }
696 
697     String8 filenames[4];
698     FileState states[4];
699     FileRec r;
700     r.deleted = false;
701 
702     states[0].modTime_sec = 0xfedcba98;
703     states[0].modTime_nsec = 0xdeadbeef;
704     states[0].mode = 0777; // decimal 511, hex 0x000001ff
705     states[0].size = 0xababbcbc;
706     states[0].crc32 = 0x12345678;
707     states[0].nameLen = -12;
708     r.s = states[0];
709     filenames[0] = String8("bytes_of_padding");
710     snapshot.add(filenames[0], r);
711 
712     states[1].modTime_sec = 0x93400031;
713     states[1].modTime_nsec = 0xdeadbeef;
714     states[1].mode = 0666; // decimal 438, hex 0x000001b6
715     states[1].size = 0x88557766;
716     states[1].crc32 = 0x22334422;
717     states[1].nameLen = -1;
718     r.s = states[1];
719     filenames[1] = String8("bytes_of_padding3");
720     snapshot.add(filenames[1], r);
721 
722     states[2].modTime_sec = 0x33221144;
723     states[2].modTime_nsec = 0xdeadbeef;
724     states[2].mode = 0744; // decimal 484, hex 0x000001e4
725     states[2].size = 0x11223344;
726     states[2].crc32 = 0x01122334;
727     states[2].nameLen = 0;
728     r.s = states[2];
729     filenames[2] = String8("bytes_of_padding_2");
730     snapshot.add(filenames[2], r);
731 
732     states[3].modTime_sec = 0x33221144;
733     states[3].modTime_nsec = 0xdeadbeef;
734     states[3].mode = 0755; // decimal 493, hex 0x000001ed
735     states[3].size = 0x11223344;
736     states[3].crc32 = 0x01122334;
737     states[3].nameLen = 0;
738     r.s = states[3];
739     filenames[3] = String8("bytes_of_padding__1");
740     snapshot.add(filenames[3], r);
741 
742     err = write_snapshot_file(fd, snapshot);
743 
744     close(fd);
745 
746     if (err != 0) {
747         fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
748         return err;
749     }
750 
751     static const unsigned char correct_data[] = {
752         // header
753         0x53, 0x6e, 0x61, 0x70,  0x04, 0x00, 0x00, 0x00,
754         0x46, 0x69, 0x6c, 0x65,  0xbc, 0x00, 0x00, 0x00,
755 
756         // bytes_of_padding
757         0x98, 0xba, 0xdc, 0xfe,  0xef, 0xbe, 0xad, 0xde,
758         0xff, 0x01, 0x00, 0x00,  0xbc, 0xbc, 0xab, 0xab,
759         0x78, 0x56, 0x34, 0x12,  0x10, 0x00, 0x00, 0x00,
760         0x62, 0x79, 0x74, 0x65,  0x73, 0x5f, 0x6f, 0x66,
761         0x5f, 0x70, 0x61, 0x64,  0x64, 0x69, 0x6e, 0x67,
762 
763         // bytes_of_padding3
764         0x31, 0x00, 0x40, 0x93,  0xef, 0xbe, 0xad, 0xde,
765         0xb6, 0x01, 0x00, 0x00,  0x66, 0x77, 0x55, 0x88,
766         0x22, 0x44, 0x33, 0x22,  0x11, 0x00, 0x00, 0x00,
767         0x62, 0x79, 0x74, 0x65,  0x73, 0x5f, 0x6f, 0x66,
768         0x5f, 0x70, 0x61, 0x64,  0x64, 0x69, 0x6e, 0x67,
769         0x33, 0xab, 0xab, 0xab,
770 
771         // bytes of padding2
772         0x44, 0x11, 0x22, 0x33,  0xef, 0xbe, 0xad, 0xde,
773         0xe4, 0x01, 0x00, 0x00,  0x44, 0x33, 0x22, 0x11,
774         0x34, 0x23, 0x12, 0x01,  0x12, 0x00, 0x00, 0x00,
775         0x62, 0x79, 0x74, 0x65,  0x73, 0x5f, 0x6f, 0x66,
776         0x5f, 0x70, 0x61, 0x64,  0x64, 0x69, 0x6e, 0x67,
777         0x5f, 0x32, 0xab, 0xab,
778 
779         // bytes of padding3
780         0x44, 0x11, 0x22, 0x33,  0xef, 0xbe, 0xad, 0xde,
781         0xed, 0x01, 0x00, 0x00,  0x44, 0x33, 0x22, 0x11,
782         0x34, 0x23, 0x12, 0x01,  0x13, 0x00, 0x00, 0x00,
783         0x62, 0x79, 0x74, 0x65,  0x73, 0x5f, 0x6f, 0x66,
784         0x5f, 0x70, 0x61, 0x64,  0x64, 0x69, 0x6e, 0x67,
785         0x5f, 0x5f, 0x31, 0xab
786     };
787 
788     err = compare_file(filename, correct_data, sizeof(correct_data));
789     if (err != 0) {
790         return err;
791     }
792 
793     // read
794     fd = open(filename, O_RDONLY);
795     if (fd == -1) {
796         fprintf(stderr, "error opening for read %s\n", filename);
797         return 1;
798     }
799 
800 
801     KeyedVector<String8,FileState> readSnapshot;
802     err = read_snapshot_file(fd, &readSnapshot);
803     if (err != 0) {
804         fprintf(stderr, "read_snapshot_file failed %d\n", err);
805         return err;
806     }
807 
808     if (readSnapshot.size() != 4) {
809         fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
810         return 1;
811     }
812 
813     bool matched = true;
814     for (size_t i=0; i<readSnapshot.size(); i++) {
815         const String8& name = readSnapshot.keyAt(i);
816         const FileState state = readSnapshot.valueAt(i);
817 
818         if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
819                 || states[i].modTime_nsec != state.modTime_nsec || states[i].mode != state.mode
820                 || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
821             fprintf(stderr, "state %d expected={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n"
822                             "          actual={%d/%d, 0x%08x, %04o, 0x%08x, %3d} '%s'\n", i,
823                     states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
824                     states[i].crc32, name.length(), filenames[i].string(),
825                     state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
826                     state.nameLen, name.string());
827             matched = false;
828         }
829     }
830 
831     return matched ? 0 : 1;
832 }
833 
834 // hexdump -v -e '"    " 8/1 " 0x%02x," "\n"' data_writer.data
835 const unsigned char DATA_GOLDEN_FILE[] = {
836      0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
837      0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
838      0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
839      0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
840      0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
841      0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
842      0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
843      0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
844      0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
845      0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
846      0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
847      0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
848      0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
849      0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
850      0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
851      0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
852      0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
853      0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
854      0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
855      0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
856 
857 };
858 const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
859 
860 static int
test_write_header_and_entity(BackupDataWriter & writer,const char * str)861 test_write_header_and_entity(BackupDataWriter& writer, const char* str)
862 {
863     int err;
864     String8 text(str);
865 
866     err = writer.WriteEntityHeader(text, text.length()+1);
867     if (err != 0) {
868         fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
869         return err;
870     }
871 
872     err = writer.WriteEntityData(text.string(), text.length()+1);
873     if (err != 0) {
874         fprintf(stderr, "write failed for data '%s'\n", text.string());
875         return errno;
876     }
877 
878     return err;
879 }
880 
881 int
backup_helper_test_data_writer()882 backup_helper_test_data_writer()
883 {
884     int err;
885     int fd;
886     const char* filename = SCRATCH_DIR "data_writer.data";
887 
888     system("rm -r " SCRATCH_DIR);
889     mkdir(SCRATCH_DIR, 0777);
890     mkdir(SCRATCH_DIR "data", 0777);
891 
892     fd = creat(filename, 0666);
893     if (fd == -1) {
894         fprintf(stderr, "error creating: %s\n", strerror(errno));
895         return errno;
896     }
897 
898     BackupDataWriter writer(fd);
899 
900     err = 0;
901     err |= test_write_header_and_entity(writer, "no_padding_");
902     err |= test_write_header_and_entity(writer, "padded_to__3");
903     err |= test_write_header_and_entity(writer, "padded_to_2__");
904     err |= test_write_header_and_entity(writer, "padded_to1");
905 
906     close(fd);
907 
908     err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
909     if (err != 0) {
910         return err;
911     }
912 
913     return err;
914 }
915 
916 int
test_read_header_and_entity(BackupDataReader & reader,const char * str)917 test_read_header_and_entity(BackupDataReader& reader, const char* str)
918 {
919     int err;
920     int bufSize = strlen(str)+1;
921     char* buf = (char*)malloc(bufSize);
922     String8 string;
923     int cookie = 0x11111111;
924     size_t actualSize;
925     bool done;
926     int type;
927     ssize_t nRead;
928 
929     // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
930 
931     err = reader.ReadNextHeader(&done, &type);
932     if (done) {
933         fprintf(stderr, "should not be done yet\n");
934         goto finished;
935     }
936     if (err != 0) {
937         fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
938         goto finished;
939     }
940     if (type != BACKUP_HEADER_ENTITY_V1) {
941         err = EINVAL;
942         fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
943     }
944 
945     err = reader.ReadEntityHeader(&string, &actualSize);
946     if (err != 0) {
947         fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
948         goto finished;
949     }
950     if (string != str) {
951         fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
952         err = EINVAL;
953         goto finished;
954     }
955     if ((int)actualSize != bufSize) {
956         fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
957                 actualSize);
958         err = EINVAL;
959         goto finished;
960     }
961 
962     nRead = reader.ReadEntityData(buf, bufSize);
963     if (nRead < 0) {
964         err = reader.Status();
965         fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
966         goto finished;
967     }
968 
969     if (0 != memcmp(buf, str, bufSize)) {
970         fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
971                 "%02x %02x %02x %02x  '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
972                 buf[0], buf[1], buf[2], buf[3]);
973         err = EINVAL;
974         goto finished;
975     }
976 
977     // The next read will confirm whether it got the right amount of data.
978 
979 finished:
980     if (err != NO_ERROR) {
981         fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
982     }
983     free(buf);
984     return err;
985 }
986 
987 int
backup_helper_test_data_reader()988 backup_helper_test_data_reader()
989 {
990     int err;
991     int fd;
992     const char* filename = SCRATCH_DIR "data_reader.data";
993 
994     system("rm -r " SCRATCH_DIR);
995     mkdir(SCRATCH_DIR, 0777);
996     mkdir(SCRATCH_DIR "data", 0777);
997 
998     fd = creat(filename, 0666);
999     if (fd == -1) {
1000         fprintf(stderr, "error creating: %s\n", strerror(errno));
1001         return errno;
1002     }
1003 
1004     err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
1005     if (err != DATA_GOLDEN_FILE_SIZE) {
1006         fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
1007         return errno;
1008     }
1009 
1010     close(fd);
1011 
1012     fd = open(filename, O_RDONLY);
1013     if (fd == -1) {
1014         fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
1015                 filename);
1016         return errno;
1017     }
1018 
1019     {
1020         BackupDataReader reader(fd);
1021 
1022         err = 0;
1023 
1024         if (err == NO_ERROR) {
1025             err = test_read_header_and_entity(reader, "no_padding_");
1026         }
1027 
1028         if (err == NO_ERROR) {
1029             err = test_read_header_and_entity(reader, "padded_to__3");
1030         }
1031 
1032         if (err == NO_ERROR) {
1033             err = test_read_header_and_entity(reader, "padded_to_2__");
1034         }
1035 
1036         if (err == NO_ERROR) {
1037             err = test_read_header_and_entity(reader, "padded_to1");
1038         }
1039     }
1040 
1041     close(fd);
1042 
1043     return err;
1044 }
1045 
1046 static int
get_mod_time(const char * filename,struct timeval times[2])1047 get_mod_time(const char* filename, struct timeval times[2])
1048 {
1049     int err;
1050     struct stat64 st;
1051     err = stat64(filename, &st);
1052     if (err != 0) {
1053         fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
1054         return errno;
1055     }
1056     times[0].tv_sec = st.st_atime;
1057     times[1].tv_sec = st.st_mtime;
1058 
1059     // If st_atime is a macro then struct stat64 uses struct timespec
1060     // to store the access and modif time values and typically
1061     // st_*time_nsec is not defined. In glibc, this is controlled by
1062     // __USE_MISC.
1063 #ifdef __USE_MISC
1064 #if !defined(st_atime) || defined(st_atime_nsec)
1065 #error "Check if this __USE_MISC conditional is still needed."
1066 #endif
1067     times[0].tv_usec = st.st_atim.tv_nsec / 1000;
1068     times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
1069 #else
1070     times[0].tv_usec = st.st_atime_nsec / 1000;
1071     times[1].tv_usec = st.st_mtime_nsec / 1000;
1072 #endif
1073 
1074     return 0;
1075 }
1076 
1077 int
backup_helper_test_files()1078 backup_helper_test_files()
1079 {
1080     int err;
1081     int oldSnapshotFD;
1082     int dataStreamFD;
1083     int newSnapshotFD;
1084 
1085     system("rm -r " SCRATCH_DIR);
1086     mkdir(SCRATCH_DIR, 0777);
1087     mkdir(SCRATCH_DIR "data", 0777);
1088 
1089     write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1090     write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1091     write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
1092     write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
1093     write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
1094     write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
1095 
1096     char const* files_before[] = {
1097         SCRATCH_DIR "data/b",
1098         SCRATCH_DIR "data/c",
1099         SCRATCH_DIR "data/d",
1100         SCRATCH_DIR "data/e",
1101         SCRATCH_DIR "data/f"
1102     };
1103 
1104     char const* keys_before[] = {
1105         "data/b",
1106         "data/c",
1107         "data/d",
1108         "data/e",
1109         "data/f"
1110     };
1111 
1112     dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
1113     if (dataStreamFD == -1) {
1114         fprintf(stderr, "error creating: %s\n", strerror(errno));
1115         return errno;
1116     }
1117 
1118     newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
1119     if (newSnapshotFD == -1) {
1120         fprintf(stderr, "error creating: %s\n", strerror(errno));
1121         return errno;
1122     }
1123 
1124     {
1125         BackupDataWriter dataStream(dataStreamFD);
1126 
1127         err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
1128         if (err != 0) {
1129             return err;
1130         }
1131     }
1132 
1133     close(dataStreamFD);
1134     close(newSnapshotFD);
1135 
1136     sleep(3);
1137 
1138     struct timeval d_times[2];
1139     struct timeval e_times[2];
1140 
1141     err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1142     err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1143     if (err != 0) {
1144         return err;
1145     }
1146 
1147     write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1148     unlink(SCRATCH_DIR "data/c");
1149     write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1150     write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1151     utimes(SCRATCH_DIR "data/d", d_times);
1152     write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1153     utimes(SCRATCH_DIR "data/e", e_times);
1154     write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1155     unlink(SCRATCH_DIR "data/f");
1156 
1157     char const* files_after[] = {
1158         SCRATCH_DIR "data/a", // added
1159         SCRATCH_DIR "data/b", // same
1160         SCRATCH_DIR "data/c", // different mod time
1161         SCRATCH_DIR "data/d", // different size (same mod time)
1162         SCRATCH_DIR "data/e", // different contents (same mod time, same size)
1163         SCRATCH_DIR "data/g"  // added
1164     };
1165 
1166     char const* keys_after[] = {
1167         "data/a", // added
1168         "data/b", // same
1169         "data/c", // different mod time
1170         "data/d", // different size (same mod time)
1171         "data/e", // different contents (same mod time, same size)
1172         "data/g"  // added
1173     };
1174 
1175     oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1176     if (oldSnapshotFD == -1) {
1177         fprintf(stderr, "error opening: %s\n", strerror(errno));
1178         return errno;
1179     }
1180 
1181     dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1182     if (dataStreamFD == -1) {
1183         fprintf(stderr, "error creating: %s\n", strerror(errno));
1184         return errno;
1185     }
1186 
1187     newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1188     if (newSnapshotFD == -1) {
1189         fprintf(stderr, "error creating: %s\n", strerror(errno));
1190         return errno;
1191     }
1192 
1193     {
1194         BackupDataWriter dataStream(dataStreamFD);
1195 
1196         err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
1197         if (err != 0) {
1198             return err;
1199         }
1200 }
1201 
1202     close(oldSnapshotFD);
1203     close(dataStreamFD);
1204     close(newSnapshotFD);
1205 
1206     return 0;
1207 }
1208 
1209 int
backup_helper_test_null_base()1210 backup_helper_test_null_base()
1211 {
1212     int err;
1213     int oldSnapshotFD;
1214     int dataStreamFD;
1215     int newSnapshotFD;
1216 
1217     system("rm -r " SCRATCH_DIR);
1218     mkdir(SCRATCH_DIR, 0777);
1219     mkdir(SCRATCH_DIR "data", 0777);
1220 
1221     write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1222 
1223     char const* files[] = {
1224         SCRATCH_DIR "data/a",
1225     };
1226 
1227     char const* keys[] = {
1228         "a",
1229     };
1230 
1231     dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1232     if (dataStreamFD == -1) {
1233         fprintf(stderr, "error creating: %s\n", strerror(errno));
1234         return errno;
1235     }
1236 
1237     newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1238     if (newSnapshotFD == -1) {
1239         fprintf(stderr, "error creating: %s\n", strerror(errno));
1240         return errno;
1241     }
1242 
1243     {
1244         BackupDataWriter dataStream(dataStreamFD);
1245 
1246         err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1247         if (err != 0) {
1248             return err;
1249         }
1250     }
1251 
1252     close(dataStreamFD);
1253     close(newSnapshotFD);
1254 
1255     return 0;
1256 }
1257 
1258 int
backup_helper_test_missing_file()1259 backup_helper_test_missing_file()
1260 {
1261     int err;
1262     int oldSnapshotFD;
1263     int dataStreamFD;
1264     int newSnapshotFD;
1265 
1266     system("rm -r " SCRATCH_DIR);
1267     mkdir(SCRATCH_DIR, 0777);
1268     mkdir(SCRATCH_DIR "data", 0777);
1269 
1270     write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
1271 
1272     char const* files[] = {
1273         SCRATCH_DIR "data/a",
1274         SCRATCH_DIR "data/b",
1275         SCRATCH_DIR "data/c",
1276     };
1277 
1278     char const* keys[] = {
1279         "a",
1280         "b",
1281         "c",
1282     };
1283 
1284     dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
1285     if (dataStreamFD == -1) {
1286         fprintf(stderr, "error creating: %s\n", strerror(errno));
1287         return errno;
1288     }
1289 
1290     newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
1291     if (newSnapshotFD == -1) {
1292         fprintf(stderr, "error creating: %s\n", strerror(errno));
1293         return errno;
1294     }
1295 
1296     {
1297         BackupDataWriter dataStream(dataStreamFD);
1298 
1299         err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
1300         if (err != 0) {
1301             return err;
1302         }
1303     }
1304 
1305     close(dataStreamFD);
1306     close(newSnapshotFD);
1307 
1308     return 0;
1309 }
1310 
1311 
1312 #endif // TEST_BACKUP_HELPERS
1313 
1314 }
1315