summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/utils/BackupHelpers.h1
-rw-r--r--libs/utils/BackupHelpers.cpp153
-rw-r--r--tests/backup/backup_helper_test.cpp1
3 files changed, 110 insertions, 45 deletions
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
index 1d0daa7..f60f4ea 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -128,6 +128,7 @@ int backup_helper_test_empty();
int backup_helper_test_four();
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_reader();
#endif
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index ffe4dff..4c3e37d 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -64,6 +64,7 @@ struct FileState {
struct FileRec {
char const* file; // this object does not own this string
+ bool deleted;
FileState s;
};
@@ -135,18 +136,23 @@ read_snapshot_file(int fd, KeyedVector<String8,FileState>* snapshot)
static int
write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
{
+ int fileCount = 0;
int bytesWritten = sizeof(SnapshotHeader);
// preflight size
const int N = snapshot.size();
for (int i=0; i<N; i++) {
- const String8& name = snapshot.keyAt(i);
- bytesWritten += sizeof(FileState) + round_up(name.length());
+ const FileRec& g = snapshot.valueAt(i);
+ if (!g.deleted) {
+ const String8& name = snapshot.keyAt(i);
+ bytesWritten += sizeof(FileState) + round_up(name.length());
+ fileCount++;
+ }
}
LOGP("write_snapshot_file fd=%d\n", fd);
int amt;
- SnapshotHeader header = { MAGIC0, N, MAGIC1, bytesWritten };
+ SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
amt = write(fd, &header, sizeof(header));
if (amt != sizeof(header)) {
@@ -154,32 +160,34 @@ write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
return errno;
}
- for (int i=0; i<header.fileCount; i++) {
- const String8& name = snapshot.keyAt(i);
+ for (int i=0; i<N; i++) {
FileRec r = snapshot.valueAt(i);
- int nameLen = r.s.nameLen = name.length();
+ if (!r.deleted) {
+ const String8& name = snapshot.keyAt(i);
+ int nameLen = r.s.nameLen = name.length();
- amt = write(fd, &r.s, sizeof(FileState));
- if (amt != sizeof(FileState)) {
- LOGW("write_snapshot_file error writing header %s", strerror(errno));
- return 1;
- }
+ amt = write(fd, &r.s, sizeof(FileState));
+ if (amt != sizeof(FileState)) {
+ LOGW("write_snapshot_file error writing header %s", strerror(errno));
+ return 1;
+ }
- // filename is not NULL terminated, but it is padded
- amt = write(fd, name.string(), nameLen);
- if (amt != nameLen) {
- LOGW("write_snapshot_file error writing filename %s", strerror(errno));
- return 1;
- }
- int paddingLen = ROUND_UP[nameLen % 4];
- if (paddingLen != 0) {
- int padding = 0xabababab;
- amt = write(fd, &padding, paddingLen);
- if (amt != paddingLen) {
- LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
- paddingLen, strerror(errno));
+ // filename is not NULL terminated, but it is padded
+ amt = write(fd, name.string(), nameLen);
+ if (amt != nameLen) {
+ LOGW("write_snapshot_file error writing filename %s", strerror(errno));
return 1;
}
+ int paddingLen = ROUND_UP[nameLen % 4];
+ if (paddingLen != 0) {
+ int padding = 0xabababab;
+ amt = write(fd, &padding, paddingLen);
+ if (amt != paddingLen) {
+ LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
+ paddingLen, strerror(errno));
+ return 1;
+ }
+ }
}
}
@@ -308,18 +316,19 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
err = stat(file, &st);
if (err != 0) {
LOGW("Error stating file %s", file);
- continue;
- }
-
- r.s.modTime_sec = st.st_mtime;
- r.s.modTime_nsec = 0; // workaround sim breakage
- //r.s.modTime_nsec = st.st_mtime_nsec;
- r.s.size = st.st_size;
- // we compute the crc32 later down below, when we already have the file open.
-
- if (newSnapshot.indexOfKey(key) >= 0) {
- LOGP("back_up_files key already in use '%s'", key.string());
- return -1;
+ r.deleted = true;
+ } else {
+ r.deleted = false;
+ r.s.modTime_sec = st.st_mtime;
+ r.s.modTime_nsec = 0; // workaround sim breakage
+ //r.s.modTime_nsec = st.st_mtime_nsec;
+ r.s.size = st.st_size;
+ // we compute the crc32 later down below, when we already have the file open.
+
+ if (newSnapshot.indexOfKey(key) >= 0) {
+ LOGP("back_up_files key already in use '%s'", key.string());
+ return -1;
+ }
}
newSnapshot.add(key, r);
}
@@ -331,24 +340,24 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
while (n<N && m<fileCount) {
const String8& p = oldSnapshot.keyAt(n);
const String8& q = newSnapshot.keyAt(m);
+ FileRec& g = newSnapshot.editValueAt(m);
int cmp = p.compare(q);
- if (cmp > 0) {
- // file added
- const FileRec& g = newSnapshot.valueAt(m);
- LOGP("file added: %s", g.file);
- write_update_file(dataStream, q, g.file);
- m++;
- }
- else if (cmp < 0) {
+ if (g.deleted || cmp < 0) {
// file removed
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);
n++;
}
+ else if (cmp > 0) {
+ // file added
+ LOGP("file added: %s", g.file);
+ write_update_file(dataStream, q, g.file);
+ m++;
+ }
else {
// both files exist, check them
const FileState& f = oldSnapshot.valueAt(n);
- FileRec& g = newSnapshot.editValueAt(m);
int fd = open(g.file, O_RDONLY);
if (fd < 0) {
@@ -550,6 +559,7 @@ backup_helper_test_four()
String8 filenames[4];
FileState states[4];
FileRec r;
+ r.deleted = false;
r.file = NULL;
states[0].modTime_sec = 0xfedcba98;
@@ -1149,6 +1159,59 @@ backup_helper_test_null_base()
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
diff --git a/tests/backup/backup_helper_test.cpp b/tests/backup/backup_helper_test.cpp
index 919df93..04358ad 100644
--- a/tests/backup/backup_helper_test.cpp
+++ b/tests/backup/backup_helper_test.cpp
@@ -39,6 +39,7 @@ Test TESTS[] = {
{ "backup_helper_test_four", backup_helper_test_four, 0, false },
{ "backup_helper_test_files", backup_helper_test_files, 0, false },
{ "backup_helper_test_null_base", backup_helper_test_null_base, 0, false },
+ { "backup_helper_test_missing_file", backup_helper_test_missing_file, 0, false },
{ "backup_helper_test_data_writer", backup_helper_test_data_writer, 0, false },
{ "backup_helper_test_data_reader", backup_helper_test_data_reader, 0, false },
{ 0, NULL, 0, false}