Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fcff1ffa authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

Merge changes 3953,3954 into donut

* changes:
  Make the file backup helper not crash if a file you requested can't be stated.  This means you don't need to know if the files you are backing up exist or not -- we'll figure it out for you.
  Fix SharedPrefsBackupHelper so it doesn't hard code the paths to the files.
parents 4fb8b729 1a9e19a7
Loading
Loading
Loading
Loading
+3 −1
Original line number Original line Diff line number Diff line
@@ -118,7 +118,7 @@ private:
};
};


int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
        char const* fileBase, char const* const* files, int fileCount);
        char const* const* files, char const* const *keys, int fileCount);




#define TEST_BACKUP_HELPERS 1
#define TEST_BACKUP_HELPERS 1
@@ -127,6 +127,8 @@ int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapsh
int backup_helper_test_empty();
int backup_helper_test_empty();
int backup_helper_test_four();
int backup_helper_test_four();
int backup_helper_test_files();
int backup_helper_test_files();
int backup_helper_test_null_base();
int backup_helper_test_missing_file();
int backup_helper_test_data_writer();
int backup_helper_test_data_writer();
int backup_helper_test_data_reader();
int backup_helper_test_data_reader();
#endif
#endif
+227 −92
Original line number Original line Diff line number Diff line
@@ -41,8 +41,8 @@ namespace android {
#define MAGIC0 0x70616e53 // Snap
#define MAGIC0 0x70616e53 // Snap
#define MAGIC1 0x656c6946 // File
#define MAGIC1 0x656c6946 // File


#if 0 // TEST_BACKUP_HELPERS
#if 1 // TEST_BACKUP_HELPERS
#define LOGP(x...) printf(x)
#define LOGP(f, x...) printf(f "\n", x)
#else
#else
#define LOGP(x...) LOGD(x)
#define LOGP(x...) LOGD(x)
#endif
#endif
@@ -62,6 +62,12 @@ struct FileState {
    int nameLen;
    int nameLen;
};
};


struct FileRec {
    char const* file; // this object does not own this string
    bool deleted;
    FileState s;
};

const static int ROUND_UP[4] = { 0, 3, 2, 1 };
const static int ROUND_UP[4] = { 0, 3, 2, 1 };


static inline int
static inline int
@@ -92,8 +98,8 @@ read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
        FileState file;
        FileState file;
        char filenameBuf[128];
        char filenameBuf[128];


        amt = read(fd, &file, sizeof(file));
        amt = read(fd, &file, sizeof(FileState));
        if (amt != sizeof(file)) {
        if (amt != sizeof(FileState)) {
            LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
            LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
            return 1;
            return 1;
        }
        }
@@ -128,20 +134,25 @@ read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
}
}


static int
static int
write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot)
write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
{
{
    int fileCount = 0;
    int bytesWritten = sizeof(SnapshotHeader);
    int bytesWritten = sizeof(SnapshotHeader);
    // preflight size
    // preflight size
    const int N = snapshot.size();
    const int N = snapshot.size();
    for (int i=0; i<N; i++) {
    for (int i=0; i<N; i++) {
        const FileRec& g = snapshot.valueAt(i);
        if (!g.deleted) {
            const String8& name = snapshot.keyAt(i);
            const String8& name = snapshot.keyAt(i);
            bytesWritten += sizeof(FileState) + round_up(name.length());
            bytesWritten += sizeof(FileState) + round_up(name.length());
            fileCount++;
        }
    }
    }


    LOGP("write_snapshot_file fd=%d\n", fd);
    LOGP("write_snapshot_file fd=%d\n", fd);


    int amt;
    int amt;
    SnapshotHeader header = { MAGIC0, N, MAGIC1, bytesWritten };
    SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };


    amt = write(fd, &header, sizeof(header));
    amt = write(fd, &header, sizeof(header));
    if (amt != sizeof(header)) {
    if (amt != sizeof(header)) {
@@ -149,13 +160,14 @@ write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot)
        return errno;
        return errno;
    }
    }


    for (int i=0; i<header.fileCount; i++) {
    for (int i=0; i<N; i++) {
        FileRec r = snapshot.valueAt(i);
        if (!r.deleted) {
            const String8& name = snapshot.keyAt(i);
            const String8& name = snapshot.keyAt(i);
        FileState file = snapshot.valueAt(i);
            int nameLen = r.s.nameLen = name.length();
        int nameLen = file.nameLen = name.length();


        amt = write(fd, &file, sizeof(file));
            amt = write(fd, &r.s, sizeof(FileState));
        if (amt != sizeof(file)) {
            if (amt != sizeof(FileState)) {
                LOGW("write_snapshot_file error writing header %s", strerror(errno));
                LOGW("write_snapshot_file error writing header %s", strerror(errno));
                return 1;
                return 1;
            }
            }
@@ -177,6 +189,7 @@ write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot)
                }
                }
            }
            }
        }
        }
    }


    return 0;
    return 0;
}
}
@@ -190,9 +203,9 @@ write_delete_file(BackupDataWriter* dataStream, const String8& key)


static int
static int
write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
        const String8& realFilename)
        char const* realFilename)
{
{
    LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string());
    LOGP("write_update_file %s (%s)\n", realFilename, key.string());


    const int bufsize = 4*1024;
    const int bufsize = 4*1024;
    int err;
    int err;
@@ -237,8 +250,7 @@ write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
            }
            }
        }
        }
        LOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
        LOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
                " You aren't doing proper locking!",
                " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
                realFilename.string(), fileSize, fileSize-bytesLeft);
    }
    }


    free(buf);
    free(buf);
@@ -247,10 +259,10 @@ write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
}
}


static int
static int
write_update_file(BackupDataWriter* dataStream, const String8& key, const String8& realFilename)
write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
{
{
    int err;
    int err;
    int fd = open(realFilename.string(), O_RDONLY);
    int fd = open(realFilename, O_RDONLY);
    if (fd == -1) {
    if (fd == -1) {
        return errno;
        return errno;
    }
    }
@@ -281,12 +293,11 @@ compute_crc32(int fd)


int
int
back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
        char const* fileBase, char const* const* files, int fileCount)
        char const* const* files, char const* const* keys, int fileCount)
{
{
    int err;
    int err;
    const String8 base(fileBase);
    KeyedVector<String8,FileState> oldSnapshot;
    KeyedVector<String8,FileState> oldSnapshot;
    KeyedVector<String8,FileState> newSnapshot;
    KeyedVector<String8,FileRec> newSnapshot;


    if (oldSnapshotFD != -1) {
    if (oldSnapshotFD != -1) {
        err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
        err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
@@ -297,26 +308,29 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
    }
    }


    for (int i=0; i<fileCount; i++) {
    for (int i=0; i<fileCount; i++) {
        String8 name(files[i]);
        String8 key(keys[i]);
        FileState s;
        FileRec r;
        char const* file = r.file = files[i];
        struct stat st;
        struct stat st;
        String8 realFilename(base);
        realFilename.appendPath(name);


        err = stat(realFilename.string(), &st);
        err = stat(file, &st);
        if (err != 0) {
        if (err != 0) {
            LOGW("Error stating file %s", realFilename.string());
            LOGW("Error stating file %s", file);
            continue;
            r.deleted = true;
        }
        } else {

            r.deleted = false;
        s.modTime_sec = st.st_mtime;
            r.s.modTime_sec = st.st_mtime;
        s.modTime_nsec = 0; // workaround sim breakage
            r.s.modTime_nsec = 0; // workaround sim breakage
        //s.modTime_nsec = st.st_mtime_nsec;
            //r.s.modTime_nsec = st.st_mtime_nsec;
        s.size = st.st_size;
            r.s.size = st.st_size;

            // we compute the crc32 later down below, when we already have the file open.
            // we compute the crc32 later down below, when we already have the file open.


        newSnapshot.add(name, s);
            if (newSnapshot.indexOfKey(key) >= 0) {
                LOGP("back_up_files key already in use '%s'", key.string());
                return -1;
            }
        }
        newSnapshot.add(key, r);
    }
    }


    int n = 0;
    int n = 0;
@@ -326,46 +340,42 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
    while (n<N && m<fileCount) {
    while (n<N && m<fileCount) {
        const String8& p = oldSnapshot.keyAt(n);
        const String8& p = oldSnapshot.keyAt(n);
        const String8& q = newSnapshot.keyAt(m);
        const String8& q = newSnapshot.keyAt(m);
        FileRec& g = newSnapshot.editValueAt(m);
        int cmp = p.compare(q);
        int cmp = p.compare(q);
        if (cmp > 0) {
        if (g.deleted || cmp < 0) {
            // file added
            String8 realFilename(base);
            realFilename.appendPath(q);
            LOGP("file added: %s\n", realFilename.string());
            write_update_file(dataStream, q, realFilename);
            m++;
        }
        else if (cmp < 0) {
            // file removed
            // file removed
            LOGP("file removed: %s\n", p.string());
            LOGP("file removed: %s", p.string());
            g.deleted = true; // They didn't mention the file, but we noticed that it's gone.
            dataStream->WriteEntityHeader(p, -1);
            dataStream->WriteEntityHeader(p, -1);
            n++;
            n++;
        }
        }
        else if (cmp > 0) {
            // file added
            LOGP("file added: %s", g.file);
            write_update_file(dataStream, q, g.file);
            m++;
        }
        else {
        else {

            // both files exist, check them
            // both files exist, check them
            String8 realFilename(base);
            realFilename.appendPath(q);
            const FileState& f = oldSnapshot.valueAt(n);
            const FileState& f = oldSnapshot.valueAt(n);
            FileState& g = newSnapshot.editValueAt(m);


            int fd = open(realFilename.string(), O_RDONLY);
            int fd = open(g.file, O_RDONLY);
            if (fd < 0) {
            if (fd < 0) {
                // We can't open the file.  Don't report it as a delete either.  Let the
                // We can't open the file.  Don't report it as a delete either.  Let the
                // server keep the old version.  Maybe they'll be able to deal with it
                // server keep the old version.  Maybe they'll be able to deal with it
                // on restore.
                // on restore.
                LOGP("Unable to open file %s - skipping", realFilename.string());
                LOGP("Unable to open file %s - skipping", g.file);
            } else {
            } else {
                g.crc32 = compute_crc32(fd);
                g.s.crc32 = compute_crc32(fd);


                LOGP("%s\n", q.string());
                LOGP("%s", q.string());
                LOGP("  new: modTime=%d,%d size=%-3d crc32=0x%08x\n",
                LOGP("  new: modTime=%d,%d size=%-3d crc32=0x%08x",
                        f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
                        f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
                LOGP("  old: modTime=%d,%d size=%-3d crc32=0x%08x\n",
                LOGP("  old: modTime=%d,%d size=%-3d crc32=0x%08x",
                        g.modTime_sec, g.modTime_nsec, g.size, g.crc32);
                        g.s.modTime_sec, g.s.modTime_nsec, g.s.size, g.s.crc32);
                if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec
                if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
                        || f.size != g.size || f.crc32 != g.crc32) {
                        || f.size != g.s.size || f.crc32 != g.s.crc32) {
                    write_update_file(dataStream, fd, p, realFilename);
                    write_update_file(dataStream, fd, p, g.file);
                }
                }


                close(fd);
                close(fd);
@@ -384,9 +394,8 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
    // these were added
    // these were added
    while (m<fileCount) {
    while (m<fileCount) {
        const String8& q = newSnapshot.keyAt(m);
        const String8& q = newSnapshot.keyAt(m);
        String8 realFilename(base);
        FileRec& g = newSnapshot.editValueAt(m);
        realFilename.appendPath(q);
        write_update_file(dataStream, q, g.file);
        write_update_file(dataStream, q, realFilename);
        m++;
        m++;
    }
    }


@@ -475,7 +484,7 @@ backup_helper_test_empty()
{
{
    int err;
    int err;
    int fd;
    int fd;
    KeyedVector<String8,FileState> snapshot;
    KeyedVector<String8,FileRec> snapshot;
    const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
    const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";


    system("rm -r " SCRATCH_DIR);
    system("rm -r " SCRATCH_DIR);
@@ -534,7 +543,7 @@ backup_helper_test_four()
{
{
    int err;
    int err;
    int fd;
    int fd;
    KeyedVector<String8,FileState> snapshot;
    KeyedVector<String8,FileRec> snapshot;
    const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
    const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";


    system("rm -r " SCRATCH_DIR);
    system("rm -r " SCRATCH_DIR);
@@ -549,38 +558,45 @@ backup_helper_test_four()


    String8 filenames[4];
    String8 filenames[4];
    FileState states[4];
    FileState states[4];
    FileRec r;
    r.deleted = false;
    r.file = NULL;


    states[0].modTime_sec = 0xfedcba98;
    states[0].modTime_sec = 0xfedcba98;
    states[0].modTime_nsec = 0xdeadbeef;
    states[0].modTime_nsec = 0xdeadbeef;
    states[0].size = 0xababbcbc;
    states[0].size = 0xababbcbc;
    states[0].crc32 = 0x12345678;
    states[0].crc32 = 0x12345678;
    states[0].nameLen = -12;
    states[0].nameLen = -12;
    r.s = states[0];
    filenames[0] = String8("bytes_of_padding");
    filenames[0] = String8("bytes_of_padding");
    snapshot.add(filenames[0], states[0]);
    snapshot.add(filenames[0], r);


    states[1].modTime_sec = 0x93400031;
    states[1].modTime_sec = 0x93400031;
    states[1].modTime_nsec = 0xdeadbeef;
    states[1].modTime_nsec = 0xdeadbeef;
    states[1].size = 0x88557766;
    states[1].size = 0x88557766;
    states[1].crc32 = 0x22334422;
    states[1].crc32 = 0x22334422;
    states[1].nameLen = -1;
    states[1].nameLen = -1;
    r.s = states[1];
    filenames[1] = String8("bytes_of_padding3");
    filenames[1] = String8("bytes_of_padding3");
    snapshot.add(filenames[1], states[1]);
    snapshot.add(filenames[1], r);


    states[2].modTime_sec = 0x33221144;
    states[2].modTime_sec = 0x33221144;
    states[2].modTime_nsec = 0xdeadbeef;
    states[2].modTime_nsec = 0xdeadbeef;
    states[2].size = 0x11223344;
    states[2].size = 0x11223344;
    states[2].crc32 = 0x01122334;
    states[2].crc32 = 0x01122334;
    states[2].nameLen = 0;
    states[2].nameLen = 0;
    r.s = states[2];
    filenames[2] = String8("bytes_of_padding_2");
    filenames[2] = String8("bytes_of_padding_2");
    snapshot.add(filenames[2], states[2]);
    snapshot.add(filenames[2], r);


    states[3].modTime_sec = 0x33221144;
    states[3].modTime_sec = 0x33221144;
    states[3].modTime_nsec = 0xdeadbeef;
    states[3].modTime_nsec = 0xdeadbeef;
    states[3].size = 0x11223344;
    states[3].size = 0x11223344;
    states[3].crc32 = 0x01122334;
    states[3].crc32 = 0x01122334;
    states[3].nameLen = 0;
    states[3].nameLen = 0;
    r.s = states[3];
    filenames[3] = String8("bytes_of_padding__1");
    filenames[3] = String8("bytes_of_padding__1");
    snapshot.add(filenames[3], states[3]);
    snapshot.add(filenames[3], r);


    err = write_snapshot_file(fd, snapshot);
    err = write_snapshot_file(fd, snapshot);


@@ -982,6 +998,14 @@ backup_helper_test_files()
    write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
    write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");


    char const* files_before[] = {
    char const* files_before[] = {
        SCRATCH_DIR "data/b",
        SCRATCH_DIR "data/c",
        SCRATCH_DIR "data/d",
        SCRATCH_DIR "data/e",
        SCRATCH_DIR "data/f"
    };

    char const* keys_before[] = {
        "data/b",
        "data/b",
        "data/c",
        "data/c",
        "data/d",
        "data/d",
@@ -1004,7 +1028,7 @@ backup_helper_test_files()
    {
    {
        BackupDataWriter dataStream(dataStreamFD);
        BackupDataWriter dataStream(dataStreamFD);


        err = back_up_files(-1, &dataStream, newSnapshotFD, SCRATCH_DIR, files_before, 5);
        err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
        if (err != 0) {
        if (err != 0) {
            return err;
            return err;
        }
        }
@@ -1035,6 +1059,15 @@ backup_helper_test_files()
    unlink(SCRATCH_DIR "data/f");
    unlink(SCRATCH_DIR "data/f");


    char const* files_after[] = {
    char const* files_after[] = {
        SCRATCH_DIR "data/a", // added
        SCRATCH_DIR "data/b", // same
        SCRATCH_DIR "data/c", // different mod time
        SCRATCH_DIR "data/d", // different size (same mod time)
        SCRATCH_DIR "data/e", // different contents (same mod time, same size)
        SCRATCH_DIR "data/g"  // added
    };

    char const* keys_after[] = {
        "data/a", // added
        "data/a", // added
        "data/b", // same
        "data/b", // same
        "data/c", // different mod time
        "data/c", // different mod time
@@ -1064,8 +1097,7 @@ backup_helper_test_files()
    {
    {
        BackupDataWriter dataStream(dataStreamFD);
        BackupDataWriter dataStream(dataStreamFD);


        err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, SCRATCH_DIR,
        err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
                files_after, 6);
        if (err != 0) {
        if (err != 0) {
            return err;
            return err;
        }
        }
@@ -1078,6 +1110,109 @@ backup_helper_test_files()
    return 0;
    return 0;
}
}


int
backup_helper_test_null_base()
{
    int err;
    int oldSnapshotFD;
    int dataStreamFD;
    int newSnapshotFD;

    system("rm -r " SCRATCH_DIR);
    mkdir(SCRATCH_DIR, 0777);
    mkdir(SCRATCH_DIR "data", 0777);

    write_text_file(SCRATCH_DIR "data/a", "a\naa\n");

    char const* files[] = {
        SCRATCH_DIR "data/a",
    };

    char const* keys[] = {
        "a",
    };

    dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
    if (dataStreamFD == -1) {
        fprintf(stderr, "error creating: %s\n", strerror(errno));
        return errno;
    }

    newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
    if (newSnapshotFD == -1) {
        fprintf(stderr, "error creating: %s\n", strerror(errno));
        return errno;
    }

    {
        BackupDataWriter dataStream(dataStreamFD);

        err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
        if (err != 0) {
            return err;
        }
    }

    close(dataStreamFD);
    close(newSnapshotFD);

    return 0;
}

int
backup_helper_test_missing_file()
{
    int err;
    int oldSnapshotFD;
    int dataStreamFD;
    int newSnapshotFD;

    system("rm -r " SCRATCH_DIR);
    mkdir(SCRATCH_DIR, 0777);
    mkdir(SCRATCH_DIR "data", 0777);

    write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");

    char const* files[] = {
        SCRATCH_DIR "data/a",
        SCRATCH_DIR "data/b",
        SCRATCH_DIR "data/c",
    };

    char const* keys[] = {
        "a",
        "b",
        "c",
    };

    dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
    if (dataStreamFD == -1) {
        fprintf(stderr, "error creating: %s\n", strerror(errno));
        return errno;
    }

    newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
    if (newSnapshotFD == -1) {
        fprintf(stderr, "error creating: %s\n", strerror(errno));
        return errno;
    }

    {
        BackupDataWriter dataStream(dataStreamFD);

        err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
        if (err != 0) {
            return err;
        }
    }

    close(dataStreamFD);
    close(newSnapshotFD);

    return 0;
}


#endif // TEST_BACKUP_HELPERS
#endif // TEST_BACKUP_HELPERS


}
}