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