BackupHelpers.cpp revision 0032ce80ac127e6bfb25d727162eee4af208dc77
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
39namespace android {
40
41#define MAGIC0 0x70616e53 // Snap
42#define MAGIC1 0x656c6946 // File
43
44#if 0 // TEST_BACKUP_HELPERS
45#define LOGP(x...) printf(x)
46#else
47#define LOGP(x...) LOGD(x)
48#endif
49
50struct SnapshotHeader {
51    int magic0;
52    int fileCount;
53    int magic1;
54    int totalSize;
55};
56
57struct FileState {
58    int modTime_sec;
59    int modTime_nsec;
60    int size;
61    int crc32;
62    int nameLen;
63};
64
65const static int ROUND_UP[4] = { 0, 3, 2, 1 };
66
67static inline int
68round_up(int n)
69{
70    return n + ROUND_UP[n % 4];
71}
72
73static int
74read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
75{
76    int bytesRead = 0;
77    int amt;
78    SnapshotHeader header;
79
80    amt = read(fd, &header, sizeof(header));
81    if (amt != sizeof(header)) {
82        return errno;
83    }
84    bytesRead += amt;
85
86    if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
87        LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
88        return 1;
89    }
90
91    for (int i=0; i<header.fileCount; i++) {
92        FileState file;
93        char filenameBuf[128];
94
95        amt = read(fd, &file, sizeof(file));
96        if (amt != sizeof(file)) {
97            LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
98            return 1;
99        }
100        bytesRead += amt;
101
102        // filename is not NULL terminated, but it is padded
103        int nameBufSize = round_up(file.nameLen);
104        char* filename = nameBufSize <= (int)sizeof(filenameBuf)
105                ? filenameBuf
106                : (char*)malloc(nameBufSize);
107        amt = read(fd, filename, nameBufSize);
108        if (amt == nameBufSize) {
109            snapshot->add(String8(filename, file.nameLen), file);
110        }
111        bytesRead += amt;
112        if (filename != filenameBuf) {
113            free(filename);
114        }
115        if (amt != nameBufSize) {
116            LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
117            return 1;
118        }
119    }
120
121    if (header.totalSize != bytesRead) {
122        LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
123                header.totalSize, bytesRead);
124        return 1;
125    }
126
127    return 0;
128}
129
130static int
131write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot)
132{
133    int bytesWritten = sizeof(SnapshotHeader);
134    // preflight size
135    const int N = snapshot.size();
136    for (int i=0; i<N; i++) {
137        const String8& name = snapshot.keyAt(i);
138        bytesWritten += sizeof(FileState) + round_up(name.length());
139    }
140
141    LOGP("write_snapshot_file fd=%d\n", fd);
142
143    int amt;
144    SnapshotHeader header = { MAGIC0, N, MAGIC1, bytesWritten };
145
146    amt = write(fd, &header, sizeof(header));
147    if (amt != sizeof(header)) {
148        LOGW("write_snapshot_file error writing header %s", strerror(errno));
149        return errno;
150    }
151
152    for (int i=0; i<header.fileCount; i++) {
153        const String8& name = snapshot.keyAt(i);
154        FileState file = snapshot.valueAt(i);
155        int nameLen = file.nameLen = name.length();
156
157        amt = write(fd, &file, sizeof(file));
158        if (amt != sizeof(file)) {
159            LOGW("write_snapshot_file error writing header %s", strerror(errno));
160            return 1;
161        }
162
163        // filename is not NULL terminated, but it is padded
164        amt = write(fd, name.string(), nameLen);
165        if (amt != nameLen) {
166            LOGW("write_snapshot_file error writing filename %s", strerror(errno));
167            return 1;
168        }
169        int paddingLen = ROUND_UP[nameLen % 4];
170        if (paddingLen != 0) {
171            int padding = 0xabababab;
172            amt = write(fd, &padding, paddingLen);
173            if (amt != paddingLen) {
174                LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
175                        paddingLen, strerror(errno));
176                return 1;
177            }
178        }
179    }
180
181    return 0;
182}
183
184static int
185write_delete_file(BackupDataWriter* dataStream, const String8& key)
186{
187    LOGP("write_delete_file %s\n", key.string());
188    return dataStream->WriteEntityHeader(key, -1);
189}
190
191static int
192write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
193        const String8& realFilename)
194{
195    LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string());
196
197    const int bufsize = 4*1024;
198    int err;
199    int amt;
200    int fileSize;
201    int bytesLeft;
202
203    char* buf = (char*)malloc(bufsize);
204    int crc = crc32(0L, Z_NULL, 0);
205
206
207    bytesLeft = fileSize = lseek(fd, 0, SEEK_END);
208    lseek(fd, 0, SEEK_SET);
209
210    err = dataStream->WriteEntityHeader(key, bytesLeft);
211    if (err != 0) {
212        return err;
213    }
214
215    while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
216        bytesLeft -= amt;
217        if (bytesLeft < 0) {
218            amt += bytesLeft; // Plus a negative is minus.  Don't write more than we promised.
219        }
220        err = dataStream->WriteEntityData(buf, amt);
221        if (err != 0) {
222            return err;
223        }
224    }
225    if (bytesLeft != 0) {
226        if (bytesLeft > 0) {
227            // Pad out the space we promised in the buffer.  We can't corrupt the buffer,
228            // even though the data we're sending is probably bad.
229            memset(buf, 0, bufsize);
230            while (bytesLeft > 0) {
231                amt = bytesLeft < bufsize ? bytesLeft : bufsize;
232                bytesLeft -= amt;
233                err = dataStream->WriteEntityData(buf, amt);
234                if (err != 0) {
235                    return err;
236                }
237            }
238        }
239        LOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
240                " You aren't doing proper locking!",
241                realFilename.string(), fileSize, fileSize-bytesLeft);
242    }
243
244    free(buf);
245
246    return NO_ERROR;
247}
248
249static int
250write_update_file(BackupDataWriter* dataStream, const String8& key, const String8& realFilename)
251{
252    int err;
253    int fd = open(realFilename.string(), O_RDONLY);
254    if (fd == -1) {
255        return errno;
256    }
257    err = write_update_file(dataStream, fd, key, realFilename);
258    close(fd);
259    return err;
260}
261
262static int
263compute_crc32(int fd)
264{
265    const int bufsize = 4*1024;
266    int amt;
267
268    char* buf = (char*)malloc(bufsize);
269    int crc = crc32(0L, Z_NULL, 0);
270
271    lseek(fd, 0, SEEK_SET);
272
273    while ((amt = read(fd, buf, bufsize)) != 0) {
274        crc = crc32(crc, (Bytef*)buf, amt);
275    }
276
277    free(buf);
278
279    return crc;
280}
281
282int
283back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
284        char const* fileBase, char const* const* files, int fileCount)
285{
286    int err;
287    const String8 base(fileBase);
288    KeyedVector<String8,FileState> oldSnapshot;
289    KeyedVector<String8,FileState> newSnapshot;
290
291    if (oldSnapshotFD != -1) {
292        err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
293        if (err != 0) {
294            // On an error, treat this as a full backup.
295            oldSnapshot.clear();
296        }
297    }
298
299    for (int i=0; i<fileCount; i++) {
300        String8 name(files[i]);
301        FileState s;
302        struct stat st;
303        String8 realFilename(base);
304        realFilename.appendPath(name);
305
306        err = stat(realFilename.string(), &st);
307        if (err != 0) {
308            LOGW("Error stating file %s", realFilename.string());
309            continue;
310        }
311
312        s.modTime_sec = st.st_mtime;
313        s.modTime_nsec = 0; // workaround sim breakage
314        //s.modTime_nsec = st.st_mtime_nsec;
315        s.size = st.st_size;
316
317        // we compute the crc32 later down below, when we already have the file open.
318
319        newSnapshot.add(name, s);
320    }
321
322    int n = 0;
323    int N = oldSnapshot.size();
324    int m = 0;
325
326    while (n<N && m<fileCount) {
327        const String8& p = oldSnapshot.keyAt(n);
328        const String8& q = newSnapshot.keyAt(m);
329        int cmp = p.compare(q);
330        if (cmp > 0) {
331            // file added
332            String8 realFilename(base);
333            realFilename.appendPath(q);
334            LOGP("file added: %s\n", realFilename.string());
335            write_update_file(dataStream, q, realFilename);
336            m++;
337        }
338        else if (cmp < 0) {
339            // file removed
340            LOGP("file removed: %s\n", p.string());
341            dataStream->WriteEntityHeader(p, -1);
342            n++;
343        }
344        else {
345
346            // both files exist, check them
347            String8 realFilename(base);
348            realFilename.appendPath(q);
349            const FileState& f = oldSnapshot.valueAt(n);
350            FileState& g = newSnapshot.editValueAt(m);
351
352            int fd = open(realFilename.string(), O_RDONLY);
353            if (fd < 0) {
354                // We can't open the file.  Don't report it as a delete either.  Let the
355                // server keep the old version.  Maybe they'll be able to deal with it
356                // on restore.
357                LOGP("Unable to open file %s - skipping", realFilename.string());
358            } else {
359                g.crc32 = compute_crc32(fd);
360
361                LOGP("%s\n", q.string());
362                LOGP("  new: modTime=%d,%d size=%-3d crc32=0x%08x\n",
363                        f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
364                LOGP("  old: modTime=%d,%d size=%-3d crc32=0x%08x\n",
365                        g.modTime_sec, g.modTime_nsec, g.size, g.crc32);
366                if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec
367                        || f.size != g.size || f.crc32 != g.crc32) {
368                    write_update_file(dataStream, fd, p, realFilename);
369                }
370
371                close(fd);
372            }
373            n++;
374            m++;
375        }
376    }
377
378    // these were deleted
379    while (n<N) {
380        dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
381        n++;
382    }
383
384    // these were added
385    while (m<fileCount) {
386        const String8& q = newSnapshot.keyAt(m);
387        String8 realFilename(base);
388        realFilename.appendPath(q);
389        write_update_file(dataStream, q, realFilename);
390        m++;
391    }
392
393    err = write_snapshot_file(newSnapshotFD, newSnapshot);
394
395    return 0;
396}
397
398#if TEST_BACKUP_HELPERS
399
400#define SCRATCH_DIR "/data/backup_helper_test/"
401
402static int
403write_text_file(const char* path, const char* data)
404{
405    int amt;
406    int fd;
407    int len;
408
409    fd = creat(path, 0666);
410    if (fd == -1) {
411        fprintf(stderr, "creat %s failed\n", path);
412        return errno;
413    }
414
415    len = strlen(data);
416    amt = write(fd, data, len);
417    if (amt != len) {
418        fprintf(stderr, "error (%s) writing to file %s\n", strerror(errno), path);
419        return errno;
420    }
421
422    close(fd);
423
424    return 0;
425}
426
427static int
428compare_file(const char* path, const unsigned char* data, int len)
429{
430    int fd;
431    int amt;
432
433    fd = open(path, O_RDONLY);
434    if (fd == -1) {
435        fprintf(stderr, "compare_file error (%s) opening %s\n", strerror(errno), path);
436        return errno;
437    }
438
439    unsigned char* contents = (unsigned char*)malloc(len);
440    if (contents == NULL) {
441        fprintf(stderr, "malloc(%d) failed\n", len);
442        return ENOMEM;
443    }
444
445    bool sizesMatch = true;
446    amt = lseek(fd, 0, SEEK_END);
447    if (amt != len) {
448        fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
449        sizesMatch = false;
450    }
451    lseek(fd, 0, SEEK_SET);
452
453    int readLen = amt < len ? amt : len;
454    amt = read(fd, contents, readLen);
455    if (amt != readLen) {
456        fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
457    }
458
459    bool contentsMatch = true;
460    for (int i=0; i<readLen; i++) {
461        if (data[i] != contents[i]) {
462            if (contentsMatch) {
463                fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
464                contentsMatch = false;
465            }
466            fprintf(stderr, "  [%-2d] %02x %02x\n", i, data[i], contents[i]);
467        }
468    }
469
470    return contentsMatch && sizesMatch ? 0 : 1;
471}
472
473int
474backup_helper_test_empty()
475{
476    int err;
477    int fd;
478    KeyedVector<String8,FileState> snapshot;
479    const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
480
481    system("rm -r " SCRATCH_DIR);
482    mkdir(SCRATCH_DIR, 0777);
483
484    // write
485    fd = creat(filename, 0666);
486    if (fd == -1) {
487        fprintf(stderr, "error creating %s\n", filename);
488        return 1;
489    }
490
491    err = write_snapshot_file(fd, snapshot);
492
493    close(fd);
494
495    if (err != 0) {
496        fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
497        return err;
498    }
499
500    static const unsigned char correct_data[] = {
501        0x53, 0x6e, 0x61, 0x70,  0x00, 0x00, 0x00, 0x00,
502        0x46, 0x69, 0x6c, 0x65,  0x10, 0x00, 0x00, 0x00
503    };
504
505    err = compare_file(filename, correct_data, sizeof(correct_data));
506    if (err != 0) {
507        return err;
508    }
509
510    // read
511    fd = open(filename, O_RDONLY);
512    if (fd == -1) {
513        fprintf(stderr, "error opening for read %s\n", filename);
514        return 1;
515    }
516
517    KeyedVector<String8,FileState> readSnapshot;
518    err = read_snapshot_file(fd, &readSnapshot);
519    if (err != 0) {
520        fprintf(stderr, "read_snapshot_file failed %d\n", err);
521        return err;
522    }
523
524    if (readSnapshot.size() != 0) {
525        fprintf(stderr, "readSnapshot should be length 0\n");
526        return 1;
527    }
528
529    return 0;
530}
531
532int
533backup_helper_test_four()
534{
535    int err;
536    int fd;
537    KeyedVector<String8,FileState> snapshot;
538    const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
539
540    system("rm -r " SCRATCH_DIR);
541    mkdir(SCRATCH_DIR, 0777);
542
543    // write
544    fd = creat(filename, 0666);
545    if (fd == -1) {
546        fprintf(stderr, "error opening %s\n", filename);
547        return 1;
548    }
549
550    String8 filenames[4];
551    FileState states[4];
552
553    states[0].modTime_sec = 0xfedcba98;
554    states[0].modTime_nsec = 0xdeadbeef;
555    states[0].size = 0xababbcbc;
556    states[0].crc32 = 0x12345678;
557    states[0].nameLen = -12;
558    filenames[0] = String8("bytes_of_padding");
559    snapshot.add(filenames[0], states[0]);
560
561    states[1].modTime_sec = 0x93400031;
562    states[1].modTime_nsec = 0xdeadbeef;
563    states[1].size = 0x88557766;
564    states[1].crc32 = 0x22334422;
565    states[1].nameLen = -1;
566    filenames[1] = String8("bytes_of_padding3");
567    snapshot.add(filenames[1], states[1]);
568
569    states[2].modTime_sec = 0x33221144;
570    states[2].modTime_nsec = 0xdeadbeef;
571    states[2].size = 0x11223344;
572    states[2].crc32 = 0x01122334;
573    states[2].nameLen = 0;
574    filenames[2] = String8("bytes_of_padding_2");
575    snapshot.add(filenames[2], states[2]);
576
577    states[3].modTime_sec = 0x33221144;
578    states[3].modTime_nsec = 0xdeadbeef;
579    states[3].size = 0x11223344;
580    states[3].crc32 = 0x01122334;
581    states[3].nameLen = 0;
582    filenames[3] = String8("bytes_of_padding__1");
583    snapshot.add(filenames[3], states[3]);
584
585    err = write_snapshot_file(fd, snapshot);
586
587    close(fd);
588
589    if (err != 0) {
590        fprintf(stderr, "write_snapshot_file reported error %d (%s)\n", err, strerror(err));
591        return err;
592    }
593
594    static const unsigned char correct_data[] = {
595        // header
596        0x53, 0x6e, 0x61, 0x70,  0x04, 0x00, 0x00, 0x00,
597        0x46, 0x69, 0x6c, 0x65,  0xac, 0x00, 0x00, 0x00,
598
599        // bytes_of_padding
600        0x98, 0xba, 0xdc, 0xfe,  0xef, 0xbe, 0xad, 0xde,
601        0xbc, 0xbc, 0xab, 0xab,  0x78, 0x56, 0x34, 0x12,
602        0x10, 0x00, 0x00, 0x00,  0x62, 0x79, 0x74, 0x65,
603        0x73, 0x5f, 0x6f, 0x66,  0x5f, 0x70, 0x61, 0x64,
604        0x64, 0x69, 0x6e, 0x67,
605
606        // bytes_of_padding3
607        0x31, 0x00, 0x40, 0x93,  0xef, 0xbe, 0xad, 0xde,
608        0x66, 0x77, 0x55, 0x88,  0x22, 0x44, 0x33, 0x22,
609        0x11, 0x00, 0x00, 0x00,  0x62, 0x79, 0x74, 0x65,
610        0x73, 0x5f, 0x6f, 0x66,  0x5f, 0x70, 0x61, 0x64,
611        0x64, 0x69, 0x6e, 0x67,  0x33, 0xab, 0xab, 0xab,
612
613        // bytes of padding2
614        0x44, 0x11, 0x22, 0x33,  0xef, 0xbe, 0xad, 0xde,
615        0x44, 0x33, 0x22, 0x11,  0x34, 0x23, 0x12, 0x01,
616        0x12, 0x00, 0x00, 0x00,  0x62, 0x79, 0x74, 0x65,
617        0x73, 0x5f, 0x6f, 0x66,  0x5f, 0x70, 0x61, 0x64,
618        0x64, 0x69, 0x6e, 0x67,  0x5f, 0x32, 0xab, 0xab,
619
620        // bytes of padding3
621        0x44, 0x11, 0x22, 0x33,  0xef, 0xbe, 0xad, 0xde,
622        0x44, 0x33, 0x22, 0x11,  0x34, 0x23, 0x12, 0x01,
623        0x13, 0x00, 0x00, 0x00,  0x62, 0x79, 0x74, 0x65,
624        0x73, 0x5f, 0x6f, 0x66,  0x5f, 0x70, 0x61, 0x64,
625        0x64, 0x69, 0x6e, 0x67,  0x5f, 0x5f, 0x31, 0xab
626    };
627
628    err = compare_file(filename, correct_data, sizeof(correct_data));
629    if (err != 0) {
630        return err;
631    }
632
633    // read
634    fd = open(filename, O_RDONLY);
635    if (fd == -1) {
636        fprintf(stderr, "error opening for read %s\n", filename);
637        return 1;
638    }
639
640
641    KeyedVector<String8,FileState> readSnapshot;
642    err = read_snapshot_file(fd, &readSnapshot);
643    if (err != 0) {
644        fprintf(stderr, "read_snapshot_file failed %d\n", err);
645        return err;
646    }
647
648    if (readSnapshot.size() != 4) {
649        fprintf(stderr, "readSnapshot should be length 4 is %d\n", readSnapshot.size());
650        return 1;
651    }
652
653    bool matched = true;
654    for (size_t i=0; i<readSnapshot.size(); i++) {
655        const String8& name = readSnapshot.keyAt(i);
656        const FileState state = readSnapshot.valueAt(i);
657
658        if (name != filenames[i] || states[i].modTime_sec != state.modTime_sec
659                || states[i].modTime_nsec != state.modTime_nsec
660                || states[i].size != state.size || states[i].crc32 != states[i].crc32) {
661            fprintf(stderr, "state %d expected={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n"
662                            "          actual={%d/%d, 0x%08x, 0x%08x, %3d} '%s'\n", i,
663                    states[i].modTime_sec, states[i].modTime_nsec, states[i].size, states[i].crc32,
664                    name.length(), filenames[i].string(),
665                    state.modTime_sec, state.modTime_nsec, state.size, state.crc32, state.nameLen,
666                    name.string());
667            matched = false;
668        }
669    }
670
671    return matched ? 0 : 1;
672}
673
674// hexdump -v -e '"    " 8/1 " 0x%02x," "\n"' data_writer.data
675const unsigned char DATA_GOLDEN_FILE[] = {
676     0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00,
677     0xdd, 0xcc, 0xbb, 0xaa, 0x6e, 0x6f, 0x5f, 0x70,
678     0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
679     0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
680     0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
681     0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
682     0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
683     0x6e, 0x67, 0x5f, 0x00, 0x41, 0x70, 0x70, 0x31,
684     0x0c, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
685     0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
686     0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
687     0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00,
688     0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
689     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
690     0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
691     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
692     0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
693     0x0d, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
694     0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
695     0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
696     0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
697     0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
698     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
699     0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
700     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
701     0x5f, 0x00, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
702     0x0a, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
703     0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
704     0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61,
705     0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
706     0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
707     0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
708     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc,
709     0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00,
710     0x99, 0x99, 0x77, 0x77
711};
712const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
713
714static int
715test_write_header_and_entity(BackupDataWriter& writer, const char* str)
716{
717    int err;
718    String8 text(str);
719
720    err = writer.WriteAppHeader(text, 0xaabbccdd);
721    if (err != 0) {
722        fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err));
723        return err;
724    }
725
726    err = writer.WriteEntityHeader(text, text.length()+1);
727    if (err != 0) {
728        fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
729        return err;
730    }
731
732    err = writer.WriteEntityData(text.string(), text.length()+1);
733    if (err != 0) {
734        fprintf(stderr, "write failed for data '%s'\n", text.string());
735        return errno;
736    }
737
738    return err;
739}
740
741int
742backup_helper_test_data_writer()
743{
744    int err;
745    int fd;
746    const char* filename = SCRATCH_DIR "data_writer.data";
747
748    system("rm -r " SCRATCH_DIR);
749    mkdir(SCRATCH_DIR, 0777);
750    mkdir(SCRATCH_DIR "data", 0777);
751
752    fd = creat(filename, 0666);
753    if (fd == -1) {
754        fprintf(stderr, "error creating: %s\n", strerror(errno));
755        return errno;
756    }
757
758    BackupDataWriter writer(fd);
759
760    err = 0;
761    err |= test_write_header_and_entity(writer, "no_padding_");
762    err |= test_write_header_and_entity(writer, "padded_to__3");
763    err |= test_write_header_and_entity(writer, "padded_to_2__");
764    err |= test_write_header_and_entity(writer, "padded_to1");
765
766    writer.WriteAppFooter(0x77779999);
767
768    close(fd);
769
770    err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
771    if (err != 0) {
772        return err;
773    }
774
775    return err;
776}
777
778int
779test_read_header_and_entity(BackupDataReader& reader, const char* str)
780{
781    int err;
782    int bufSize = strlen(str)+1;
783    char* buf = (char*)malloc(bufSize);
784    String8 string;
785    int cookie = 0x11111111;
786    size_t actualSize;
787
788    // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
789
790    err = reader.ReadNextHeader();
791    if (err != 0) {
792        fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
793        goto done;
794    }
795
796    err = reader.ReadAppHeader(&string, &cookie);
797    if (err != 0) {
798        fprintf(stderr, "ReadAppHeader failed with %s\n", strerror(err));
799        goto done;
800    }
801    if (string != str) {
802        fprintf(stderr, "ReadAppHeader expected packageName '%s' got '%s'\n", str, string.string());
803        err = EINVAL;
804        goto done;
805    }
806    if (cookie != (int)0xaabbccdd) {
807        fprintf(stderr, "ReadAppHeader expected cookie 0x%08x got 0x%08x\n", 0xaabbccdd, cookie);
808        err = EINVAL;
809        goto done;
810    }
811
812    err = reader.ReadNextHeader();
813    if (err != 0) {
814        fprintf(stderr, "ReadNextHeader (for entity header) failed with %s\n", strerror(err));
815        goto done;
816    }
817
818    err = reader.ReadEntityHeader(&string, &actualSize);
819    if (err != 0) {
820        fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
821        goto done;
822    }
823    if (string != str) {
824        fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
825        err = EINVAL;
826        goto done;
827    }
828    if ((int)actualSize != bufSize) {
829        fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
830                actualSize);
831        err = EINVAL;
832        goto done;
833    }
834
835    err = reader.ReadEntityData(buf, bufSize);
836    if (err != NO_ERROR) {
837        fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
838        goto done;
839    }
840
841    if (0 != memcmp(buf, str, bufSize)) {
842        fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
843                "%02x %02x %02x %02x\n", str, buf[0], buf[1], buf[2], buf[3]);
844        err = EINVAL;
845        goto done;
846    }
847
848    // The next read will confirm whether it got the right amount of data.
849
850done:
851    if (err != NO_ERROR) {
852        fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
853    }
854    free(buf);
855    return err;
856}
857
858int
859backup_helper_test_data_reader()
860{
861    int err;
862    int fd;
863    const char* filename = SCRATCH_DIR "data_reader.data";
864
865    system("rm -r " SCRATCH_DIR);
866    mkdir(SCRATCH_DIR, 0777);
867    mkdir(SCRATCH_DIR "data", 0777);
868
869    fd = creat(filename, 0666);
870    if (fd == -1) {
871        fprintf(stderr, "error creating: %s\n", strerror(errno));
872        return errno;
873    }
874
875    err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
876    if (err != DATA_GOLDEN_FILE_SIZE) {
877        fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename);
878        return errno;
879    }
880
881    close(fd);
882
883    fd = open(filename, O_RDONLY);
884    if (fd == -1) {
885        fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno),
886                filename);
887        return errno;
888    }
889
890    {
891        BackupDataReader reader(fd);
892
893        err = 0;
894
895        if (err == NO_ERROR) {
896            err = test_read_header_and_entity(reader, "no_padding_");
897        }
898
899        if (err == NO_ERROR) {
900            err = test_read_header_and_entity(reader, "padded_to__3");
901        }
902
903        if (err == NO_ERROR) {
904            err = test_read_header_and_entity(reader, "padded_to_2__");
905        }
906
907        if (err == NO_ERROR) {
908            err = test_read_header_and_entity(reader, "padded_to1");
909        }
910
911        if (err == NO_ERROR) {
912            err = reader.ReadNextHeader();
913            if (err != 0) {
914                fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
915            }
916
917            if (err == NO_ERROR) {
918                int cookie;
919                err |= reader.ReadAppFooter(&cookie);
920                if (cookie != 0x77779999) {
921                    fprintf(stderr, "app footer cookie expected=0x%08x actual=0x%08x\n",
922                        0x77779999, cookie);
923                    err = EINVAL;
924                }
925            }
926        }
927    }
928
929    close(fd);
930
931    return err;
932}
933
934static int
935get_mod_time(const char* filename, struct timeval times[2])
936{
937    int err;
938    struct stat64 st;
939    err = stat64(filename, &st);
940    if (err != 0) {
941        fprintf(stderr, "stat '%s' failed: %s\n", filename, strerror(errno));
942        return errno;
943    }
944    times[0].tv_sec = st.st_atime;
945    times[1].tv_sec = st.st_mtime;
946
947    // If st_atime is a macro then struct stat64 uses struct timespec
948    // to store the access and modif time values and typically
949    // st_*time_nsec is not defined. In glibc, this is controlled by
950    // __USE_MISC.
951#ifdef __USE_MISC
952#if !defined(st_atime) || defined(st_atime_nsec)
953#error "Check if this __USE_MISC conditional is still needed."
954#endif
955    times[0].tv_usec = st.st_atim.tv_nsec / 1000;
956    times[1].tv_usec = st.st_mtim.tv_nsec / 1000;
957#else
958    times[0].tv_usec = st.st_atime_nsec / 1000;
959    times[1].tv_usec = st.st_mtime_nsec / 1000;
960#endif
961
962    return 0;
963}
964
965int
966backup_helper_test_files()
967{
968    int err;
969    int oldSnapshotFD;
970    int dataStreamFD;
971    int newSnapshotFD;
972
973    system("rm -r " SCRATCH_DIR);
974    mkdir(SCRATCH_DIR, 0777);
975    mkdir(SCRATCH_DIR "data", 0777);
976
977    write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
978    write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
979    write_text_file(SCRATCH_DIR "data/d", "d\ndd\n");
980    write_text_file(SCRATCH_DIR "data/e", "e\nee\n");
981    write_text_file(SCRATCH_DIR "data/f", "f\nff\n");
982    write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
983
984    char const* files_before[] = {
985        "data/b",
986        "data/c",
987        "data/d",
988        "data/e",
989        "data/f"
990    };
991
992    dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
993    if (dataStreamFD == -1) {
994        fprintf(stderr, "error creating: %s\n", strerror(errno));
995        return errno;
996    }
997
998    newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
999    if (newSnapshotFD == -1) {
1000        fprintf(stderr, "error creating: %s\n", strerror(errno));
1001        return errno;
1002    }
1003
1004    {
1005        BackupDataWriter dataStream(dataStreamFD);
1006
1007        err = back_up_files(-1, &dataStream, newSnapshotFD, SCRATCH_DIR, files_before, 5);
1008        if (err != 0) {
1009            return err;
1010        }
1011    }
1012
1013    close(dataStreamFD);
1014    close(newSnapshotFD);
1015
1016    sleep(3);
1017
1018    struct timeval d_times[2];
1019    struct timeval e_times[2];
1020
1021    err = get_mod_time(SCRATCH_DIR "data/d", d_times);
1022    err |= get_mod_time(SCRATCH_DIR "data/e", e_times);
1023    if (err != 0) {
1024        return err;
1025    }
1026
1027    write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
1028    unlink(SCRATCH_DIR "data/c");
1029    write_text_file(SCRATCH_DIR "data/c", "c\ncc\n");
1030    write_text_file(SCRATCH_DIR "data/d", "dd\ndd\n");
1031    utimes(SCRATCH_DIR "data/d", d_times);
1032    write_text_file(SCRATCH_DIR "data/e", "z\nzz\n");
1033    utimes(SCRATCH_DIR "data/e", e_times);
1034    write_text_file(SCRATCH_DIR "data/g", "g\ngg\n");
1035    unlink(SCRATCH_DIR "data/f");
1036
1037    char const* files_after[] = {
1038        "data/a", // added
1039        "data/b", // same
1040        "data/c", // different mod time
1041        "data/d", // different size (same mod time)
1042        "data/e", // different contents (same mod time, same size)
1043        "data/g"  // added
1044    };
1045
1046    oldSnapshotFD = open(SCRATCH_DIR "before.snap", O_RDONLY);
1047    if (oldSnapshotFD == -1) {
1048        fprintf(stderr, "error opening: %s\n", strerror(errno));
1049        return errno;
1050    }
1051
1052    dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
1053    if (dataStreamFD == -1) {
1054        fprintf(stderr, "error creating: %s\n", strerror(errno));
1055        return errno;
1056    }
1057
1058    newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
1059    if (newSnapshotFD == -1) {
1060        fprintf(stderr, "error creating: %s\n", strerror(errno));
1061        return errno;
1062    }
1063
1064    {
1065        BackupDataWriter dataStream(dataStreamFD);
1066
1067        err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, SCRATCH_DIR,
1068                files_after, 6);
1069        if (err != 0) {
1070            return err;
1071        }
1072}
1073
1074    close(oldSnapshotFD);
1075    close(dataStreamFD);
1076    close(newSnapshotFD);
1077
1078    return 0;
1079}
1080
1081#endif // TEST_BACKUP_HELPERS
1082
1083}
1084