BackupHelpers.cpp revision fbb92385f2fb0ae1146bb8f3d73547d90bda6db1
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/*
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
62struct file_metadata_v1 {
63    int version;
64    int mode;
65    int undefined_1;
66    int undefined_2;
67};
68
69const static int CURRENT_METADATA_VERSION = 1;
70
71// auto-free buffer management object
72class StAutoFree {
73public:
74    StAutoFree(void* buffer) { mBuf = buffer; }
75    ~StAutoFree() { free(mBuf); }
76private:
77    void* mBuf;
78};
79
80#if 0 // TEST_BACKUP_HELPERS
81#define LOGP(f, x...) printf(f "\n", x)
82#else
83#define LOGP(x...) LOGD(x)
84#endif
85
86const static int ROUND_UP[4] = { 0, 3, 2, 1 };
87
88static inline int
89round_up(int n)
90{
91    return n + ROUND_UP[n % 4];
92}
93
94static int
95read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
96{
97    int bytesRead = 0;
98    int amt;
99    SnapshotHeader header;
100
101    amt = read(fd, &header, sizeof(header));
102    if (amt != sizeof(header)) {
103        return errno;
104    }
105    bytesRead += amt;
106
107    if (header.magic0 != MAGIC0 || header.magic1 != MAGIC1) {
108        LOGW("read_snapshot_file header.magic0=0x%08x magic1=0x%08x", header.magic0, header.magic1);
109        return 1;
110    }
111
112    for (int i=0; i<header.fileCount; i++) {
113        FileState file;
114        char filenameBuf[128];
115
116        amt = read(fd, &file, sizeof(FileState));
117        if (amt != sizeof(FileState)) {
118            LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
119            return 1;
120        }
121        bytesRead += amt;
122
123        // filename is not NULL terminated, but it is padded
124        int nameBufSize = round_up(file.nameLen);
125        char* filename = nameBufSize <= (int)sizeof(filenameBuf)
126                ? filenameBuf
127                : (char*)malloc(nameBufSize);
128        amt = read(fd, filename, nameBufSize);
129        if (amt == nameBufSize) {
130            snapshot->add(String8(filename, file.nameLen), file);
131        }
132        bytesRead += amt;
133        if (filename != filenameBuf) {
134            free(filename);
135        }
136        if (amt != nameBufSize) {
137            LOGW("read_snapshot_file filename truncated/error with read at %d bytes\n", bytesRead);
138            return 1;
139        }
140    }
141
142    if (header.totalSize != bytesRead) {
143        LOGW("read_snapshot_file length mismatch: header.totalSize=%d bytesRead=%d\n",
144                header.totalSize, bytesRead);
145        return 1;
146    }
147
148    return 0;
149}
150
151static int
152write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
153{
154    int fileCount = 0;
155    int bytesWritten = sizeof(SnapshotHeader);
156    // preflight size
157    const int N = snapshot.size();
158    for (int i=0; i<N; i++) {
159        const FileRec& g = snapshot.valueAt(i);
160        if (!g.deleted) {
161            const String8& name = snapshot.keyAt(i);
162            bytesWritten += sizeof(FileState) + round_up(name.length());
163            fileCount++;
164        }
165    }
166
167    LOGP("write_snapshot_file fd=%d\n", fd);
168
169    int amt;
170    SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
171
172    amt = write(fd, &header, sizeof(header));
173    if (amt != sizeof(header)) {
174        LOGW("write_snapshot_file error writing header %s", strerror(errno));
175        return errno;
176    }
177
178    for (int i=0; i<N; i++) {
179        FileRec r = snapshot.valueAt(i);
180        if (!r.deleted) {
181            const String8& name = snapshot.keyAt(i);
182            int nameLen = r.s.nameLen = name.length();
183
184            amt = write(fd, &r.s, sizeof(FileState));
185            if (amt != sizeof(FileState)) {
186                LOGW("write_snapshot_file error writing header %s", strerror(errno));
187                return 1;
188            }
189
190            // filename is not NULL terminated, but it is padded
191            amt = write(fd, name.string(), nameLen);
192            if (amt != nameLen) {
193                LOGW("write_snapshot_file error writing filename %s", strerror(errno));
194                return 1;
195            }
196            int paddingLen = ROUND_UP[nameLen % 4];
197            if (paddingLen != 0) {
198                int padding = 0xabababab;
199                amt = write(fd, &padding, paddingLen);
200                if (amt != paddingLen) {
201                    LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
202                            paddingLen, strerror(errno));
203                    return 1;
204                }
205            }
206        }
207    }
208
209    return 0;
210}
211
212static int
213write_delete_file(BackupDataWriter* dataStream, const String8& key)
214{
215    LOGP("write_delete_file %s\n", key.string());
216    return dataStream->WriteEntityHeader(key, -1);
217}
218
219static int
220write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
221        char const* realFilename)
222{
223    LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
224
225    const int bufsize = 4*1024;
226    int err;
227    int amt;
228    int fileSize;
229    int bytesLeft;
230    file_metadata_v1 metadata;
231
232    char* buf = (char*)malloc(bufsize);
233    StAutoFree _autoFree(buf);
234
235    int crc = crc32(0L, Z_NULL, 0);
236
237
238    fileSize = lseek(fd, 0, SEEK_END);
239    lseek(fd, 0, SEEK_SET);
240
241    if (sizeof(metadata) != 16) {
242        LOGE("ERROR: metadata block is the wrong size!");
243    }
244
245    bytesLeft = fileSize + sizeof(metadata);
246    err = dataStream->WriteEntityHeader(key, bytesLeft);
247    if (err != 0) {
248        return err;
249    }
250
251    // store the file metadata first
252    metadata.version = tolel(CURRENT_METADATA_VERSION);
253    metadata.mode = tolel(mode);
254    metadata.undefined_1 = metadata.undefined_2 = 0;
255    err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
256    if (err != 0) {
257        return err;
258    }
259    bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
260
261    // now store the file content
262    while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
263        bytesLeft -= amt;
264        if (bytesLeft < 0) {
265            amt += bytesLeft; // Plus a negative is minus.  Don't write more than we promised.
266        }
267        err = dataStream->WriteEntityData(buf, amt);
268        if (err != 0) {
269            return err;
270        }
271    }
272    if (bytesLeft != 0) {
273        if (bytesLeft > 0) {
274            // Pad out the space we promised in the buffer.  We can't corrupt the buffer,
275            // even though the data we're sending is probably bad.
276            memset(buf, 0, bufsize);
277            while (bytesLeft > 0) {
278                amt = bytesLeft < bufsize ? bytesLeft : bufsize;
279                bytesLeft -= amt;
280                err = dataStream->WriteEntityData(buf, amt);
281                if (err != 0) {
282                    return err;
283                }
284            }
285        }
286        LOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
287                " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
288    }
289
290    return NO_ERROR;
291}
292
293static int
294write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
295{
296    int err;
297    struct stat st;
298
299    err = stat(realFilename, &st);
300    if (err < 0) {
301        return errno;
302    }
303
304    int fd = open(realFilename, O_RDONLY);
305    if (fd == -1) {
306        return errno;
307    }
308
309    err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
310    close(fd);
311    return err;
312}
313
314static int
315compute_crc32(int fd)
316{
317    const int bufsize = 4*1024;
318    int amt;
319
320    char* buf = (char*)malloc(bufsize);
321    StAutoFree _autoFree(buf);
322
323    int crc = crc32(0L, Z_NULL, 0);
324
325    lseek(fd, 0, SEEK_SET);
326
327    while ((amt = read(fd, buf, bufsize)) != 0) {
328        crc = crc32(crc, (Bytef*)buf, amt);
329    }
330
331    return crc;
332}
333
334int
335back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
336        char const* const* files, char const* const* keys, int fileCount)
337{
338    int err;
339    KeyedVector<String8,FileState> oldSnapshot;
340    KeyedVector<String8,FileRec> newSnapshot;
341
342    if (oldSnapshotFD != -1) {
343        err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
344        if (err != 0) {
345            // On an error, treat this as a full backup.
346            oldSnapshot.clear();
347        }
348    }
349
350    for (int i=0; i<fileCount; i++) {
351        String8 key(keys[i]);
352        FileRec r;
353        char const* file = files[i];
354        r.file = file;
355        struct stat st;
356
357        err = stat(file, &st);
358        if (err != 0) {
359            LOGW("Error stating file %s", file);
360            r.deleted = true;
361        } else {
362            r.deleted = false;
363            r.s.modTime_sec = st.st_mtime;
364            r.s.modTime_nsec = 0; // workaround sim breakage
365            //r.s.modTime_nsec = st.st_mtime_nsec;
366            r.s.mode = st.st_mode;
367            r.s.size = st.st_size;
368            // we compute the crc32 later down below, when we already have the file open.
369
370            if (newSnapshot.indexOfKey(key) >= 0) {
371                LOGP("back_up_files key already in use '%s'", key.string());
372                return -1;
373            }
374        }
375        newSnapshot.add(key, r);
376    }
377
378    int n = 0;
379    int N = oldSnapshot.size();
380    int m = 0;
381
382    while (n<N && m<fileCount) {
383        const String8& p = oldSnapshot.keyAt(n);
384        const String8& q = newSnapshot.keyAt(m);
385        FileRec& g = newSnapshot.editValueAt(m);
386        int cmp = p.compare(q);
387        if (g.deleted || cmp < 0) {
388            // file removed
389            LOGP("file removed: %s", p.string());
390            g.deleted = true; // They didn't mention the file, but we noticed that it's gone.
391            dataStream->WriteEntityHeader(p, -1);
392            n++;
393        }
394        else if (cmp > 0) {
395            // file added
396            LOGP("file added: %s", g.file.string());
397            write_update_file(dataStream, q, g.file.string());
398            m++;
399        }
400        else {
401            // both files exist, check them
402            const FileState& f = oldSnapshot.valueAt(n);
403
404            int fd = open(g.file.string(), O_RDONLY);
405            if (fd < 0) {
406                // We can't open the file.  Don't report it as a delete either.  Let the
407                // server keep the old version.  Maybe they'll be able to deal with it
408                // on restore.
409                LOGP("Unable to open file %s - skipping", g.file.string());
410            } else {
411                g.s.crc32 = compute_crc32(fd);
412
413                LOGP("%s", q.string());
414                LOGP("  new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
415                        f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
416                LOGP("  old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
417                        g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
418                if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
419                        || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
420                    write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
421                }
422
423                close(fd);
424            }
425            n++;
426            m++;
427        }
428    }
429
430    // these were deleted
431    while (n<N) {
432        dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1);
433        n++;
434    }
435
436    // these were added
437    while (m<fileCount) {
438        const String8& q = newSnapshot.keyAt(m);
439        FileRec& g = newSnapshot.editValueAt(m);
440        write_update_file(dataStream, q, g.file.string());
441        m++;
442    }
443
444    err = write_snapshot_file(newSnapshotFD, newSnapshot);
445
446    return 0;
447}
448
449#define RESTORE_BUF_SIZE (8*1024)
450
451RestoreHelperBase::RestoreHelperBase()
452{
453    m_buf = malloc(RESTORE_BUF_SIZE);
454}
455
456RestoreHelperBase::~RestoreHelperBase()
457{
458    free(m_buf);
459}
460
461status_t
462RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
463{
464    ssize_t err;
465    size_t dataSize;
466    String8 key;
467    int fd;
468    void* buf = m_buf;
469    ssize_t amt;
470    int mode;
471    int crc;
472    struct stat st;
473    FileRec r;
474
475    err = in->ReadEntityHeader(&key, &dataSize);
476    if (err != NO_ERROR) {
477        return err;
478    }
479
480    // Get the metadata block off the head of the file entity and use that to
481    // set up the output file
482    file_metadata_v1 metadata;
483    amt = in->ReadEntityData(&metadata, sizeof(metadata));
484    if (amt != sizeof(metadata)) {
485        LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
486                (long)amt, strerror(errno));
487        return EIO;
488    }
489    metadata.version = fromlel(metadata.version);
490    metadata.mode = fromlel(metadata.mode);
491    if (metadata.version > CURRENT_METADATA_VERSION) {
492        LOGW("Restoring file with unsupported metadata version %d (currently %d)",
493                metadata.version, CURRENT_METADATA_VERSION);
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
538status_t
539RestoreHelperBase::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
548static int
549write_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
573static int
574compare_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    StAutoFree _autoFree(contents);
591
592    bool sizesMatch = true;
593    amt = lseek(fd, 0, SEEK_END);
594    if (amt != len) {
595        fprintf(stderr, "compare_file file length should be %d, was %d\n", len, amt);
596        sizesMatch = false;
597    }
598    lseek(fd, 0, SEEK_SET);
599
600    int readLen = amt < len ? amt : len;
601    amt = read(fd, contents, readLen);
602    if (amt != readLen) {
603        fprintf(stderr, "compare_file read expected %d bytes but got %d\n", len, amt);
604    }
605
606    bool contentsMatch = true;
607    for (int i=0; i<readLen; i++) {
608        if (data[i] != contents[i]) {
609            if (contentsMatch) {
610                fprintf(stderr, "compare_file contents are different: (index, expected, actual)\n");
611                contentsMatch = false;
612            }
613            fprintf(stderr, "  [%-2d] %02x %02x\n", i, data[i], contents[i]);
614        }
615    }
616
617    return contentsMatch && sizesMatch ? 0 : 1;
618}
619
620int
621backup_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
679int
680backup_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
835const 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};
858const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
859
860static int
861test_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
881int
882backup_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
916int
917test_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    StAutoFree _autoFree(buf);
923    String8 string;
924    int cookie = 0x11111111;
925    size_t actualSize;
926    bool done;
927    int type;
928    ssize_t nRead;
929
930    // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
931
932    err = reader.ReadNextHeader(&done, &type);
933    if (done) {
934        fprintf(stderr, "should not be done yet\n");
935        goto finished;
936    }
937    if (err != 0) {
938        fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
939        goto finished;
940    }
941    if (type != BACKUP_HEADER_ENTITY_V1) {
942        err = EINVAL;
943        fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
944    }
945
946    err = reader.ReadEntityHeader(&string, &actualSize);
947    if (err != 0) {
948        fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
949        goto finished;
950    }
951    if (string != str) {
952        fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
953        err = EINVAL;
954        goto finished;
955    }
956    if ((int)actualSize != bufSize) {
957        fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
958                actualSize);
959        err = EINVAL;
960        goto finished;
961    }
962
963    nRead = reader.ReadEntityData(buf, bufSize);
964    if (nRead < 0) {
965        err = reader.Status();
966        fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
967        goto finished;
968    }
969
970    if (0 != memcmp(buf, str, bufSize)) {
971        fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
972                "%02x %02x %02x %02x  '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
973                buf[0], buf[1], buf[2], buf[3]);
974        err = EINVAL;
975        goto finished;
976    }
977
978    // The next read will confirm whether it got the right amount of data.
979
980finished:
981    if (err != NO_ERROR) {
982        fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
983    }
984    return err;
985}
986
987int
988backup_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
1046static int
1047get_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
1077int
1078backup_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
1209int
1210backup_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
1258int
1259backup_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