summaryrefslogtreecommitdiffstats
path: root/libs/utils
diff options
context:
space:
mode:
authorJoe Onorato <joeo@android.com>2009-05-15 07:55:51 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-05-15 07:55:51 -0700
commit55051ebdd1ebf043f9d0e3dcf025c8c8930cf567 (patch)
treee2e51e5c9fa3bcba1dabf7e770b6c2b85e4e6cd7 /libs/utils
parentdd6face5a66ed6c9ac24b2754ec046b82881182c (diff)
parent4535e40544aeb957d44fad75fbe5676effe03689 (diff)
downloadframeworks_base-55051ebdd1ebf043f9d0e3dcf025c8c8930cf567.zip
frameworks_base-55051ebdd1ebf043f9d0e3dcf025c8c8930cf567.tar.gz
frameworks_base-55051ebdd1ebf043f9d0e3dcf025c8c8930cf567.tar.bz2
am 4535e405: Implement the C++ class to write the backed up file data.
Merge commit '4535e40544aeb957d44fad75fbe5676effe03689' * commit '4535e40544aeb957d44fad75fbe5676effe03689': Implement the C++ class to write the backed up file data.
Diffstat (limited to 'libs/utils')
-rw-r--r--libs/utils/Android.mk3
-rw-r--r--libs/utils/backup_data.cpp236
-rw-r--r--libs/utils/backup_helper_file.cpp (renamed from libs/utils/file_backup_helper.cpp)153
3 files changed, 385 insertions, 7 deletions
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index f9fb780..5a1a89b 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -117,7 +117,8 @@ LOCAL_SRC_FILES:= \
IPermissionController.cpp \
IServiceManager.cpp \
Unicode.cpp \
- file_backup_helper.cpp
+ backup_data.cpp \
+ backup_helper_file.cpp
ifeq ($(TARGET_SIMULATOR),true)
LOCAL_SRC_FILES += $(hostSources)
diff --git a/libs/utils/backup_data.cpp b/libs/utils/backup_data.cpp
new file mode 100644
index 0000000..c7f1fdb
--- /dev/null
+++ b/libs/utils/backup_data.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/backup_helpers.h>
+#include <utils/ByteOrder.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+namespace android {
+
+/*
+ * File Format (v1):
+ *
+ * All ints are stored little-endian.
+ *
+ * - An app_header_v1 struct.
+ * - The name of the package, utf-8, null terminated, padded to 4-byte boundary.
+ * - A sequence of zero or more key/value paires (entities), each with
+ * - A entity_header_v1 struct
+ * - The key, utf-8, null terminated, padded to 4-byte boundary.
+ * - The value, padded to 4 byte boundary
+ */
+
+#define APP_MAGIC_V1 0x31707041 // App1 (little endian)
+#define ENTITY_MAGIC_V1 0x61746144 // Data (little endian)
+#define FOOTER_MAGIC_V1 0x746f6f46 // Foot (little endian)
+
+typedef struct {
+ int type; // == APP_MAGIC_V1
+ int packageLen; // length of the name of the package that follows, not including the null.
+} app_header_v1;
+
+typedef struct {
+ int type; // ENTITY_MAGIC_V1
+ int keyLen; // length of the key name, not including the null terminator
+ int dataSize; // size of the data, not including the padding
+} entity_header_v1;
+
+typedef struct {
+ int type; // FOOTER_MAGIC_V1
+ int entityCount; // the number of entities that were written
+} app_footer_v1;
+
+const static int ROUND_UP[4] = { 0, 3, 2, 1 };
+
+static inline size_t
+round_up(size_t n)
+{
+ return n + ROUND_UP[n % 4];
+}
+
+static inline size_t
+padding_extra(size_t n)
+{
+ return ROUND_UP[n % 4];
+}
+
+BackupDataWriter::BackupDataWriter(int fd)
+ :m_fd(fd),
+ m_status(NO_ERROR),
+ m_pos(0),
+ m_entityCount(0)
+{
+}
+
+BackupDataWriter::~BackupDataWriter()
+{
+}
+
+// Pad out anything they've previously written to the next 4 byte boundary.
+status_t
+BackupDataWriter::write_padding_for(int n)
+{
+ ssize_t amt;
+ ssize_t paddingSize;
+
+ paddingSize = padding_extra(n);
+ if (paddingSize > 0) {
+ uint32_t padding = 0xbcbcbcbc;
+ amt = write(m_fd, &padding, paddingSize);
+ if (amt != paddingSize) {
+ m_status = errno;
+ return m_status;
+ }
+ m_pos += amt;
+ }
+ return NO_ERROR;
+}
+
+status_t
+BackupDataWriter::WriteAppHeader(const String8& packageName)
+{
+ if (m_status != NO_ERROR) {
+ return m_status;
+ }
+
+ ssize_t amt;
+
+ amt = write_padding_for(m_pos);
+ if (amt != 0) {
+ return amt;
+ }
+
+ app_header_v1 header;
+ ssize_t nameLen;
+
+ nameLen = packageName.length();
+
+ header.type = tolel(APP_MAGIC_V1);
+ header.packageLen = tolel(nameLen);
+
+ amt = write(m_fd, &header, sizeof(app_header_v1));
+ if (amt != sizeof(app_header_v1)) {
+ m_status = errno;
+ return m_status;
+ }
+ m_pos += amt;
+
+ amt = write(m_fd, packageName.string(), nameLen+1);
+ if (amt != nameLen+1) {
+ m_status = errno;
+ return m_status;
+ }
+ m_pos += amt;
+
+ return NO_ERROR;
+}
+
+status_t
+BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
+{
+ if (m_status != NO_ERROR) {
+ return m_status;
+ }
+
+ ssize_t amt;
+
+ amt = write_padding_for(m_pos);
+ if (amt != 0) {
+ return amt;
+ }
+
+ entity_header_v1 header;
+ ssize_t keyLen;
+
+ keyLen = key.length();
+
+ header.type = tolel(ENTITY_MAGIC_V1);
+ header.keyLen = tolel(keyLen);
+ header.dataSize = tolel(dataSize);
+
+ amt = write(m_fd, &header, sizeof(entity_header_v1));
+ if (amt != sizeof(entity_header_v1)) {
+ m_status = errno;
+ return m_status;
+ }
+ m_pos += amt;
+
+ amt = write(m_fd, key.string(), keyLen+1);
+ if (amt != keyLen+1) {
+ m_status = errno;
+ return m_status;
+ }
+ m_pos += amt;
+
+ amt = write_padding_for(keyLen+1);
+
+ m_entityCount++;
+
+ return amt;
+}
+
+status_t
+BackupDataWriter::WriteEntityData(const void* data, size_t size)
+{
+ if (m_status != NO_ERROR) {
+ return m_status;
+ }
+
+ // We don't write padding here, because they're allowed to call this several
+ // times with smaller buffers. We write it at the end of WriteEntityHeader
+ // instead.
+ ssize_t amt = write(m_fd, data, size);
+ if (amt != (ssize_t)size) {
+ m_status = errno;
+ return m_status;
+ }
+ m_pos += amt;
+ return NO_ERROR;
+}
+
+status_t
+BackupDataWriter::WriteAppFooter()
+{
+ if (m_status != NO_ERROR) {
+ return m_status;
+ }
+
+ ssize_t amt;
+
+ amt = write_padding_for(m_pos);
+ if (amt != 0) {
+ return amt;
+ }
+
+ app_footer_v1 footer;
+ ssize_t nameLen;
+
+ footer.type = tolel(FOOTER_MAGIC_V1);
+ footer.entityCount = tolel(m_entityCount);
+
+ amt = write(m_fd, &footer, sizeof(app_footer_v1));
+ if (amt != sizeof(app_footer_v1)) {
+ m_status = errno;
+ return m_status;
+ }
+ m_pos += amt;
+
+ return NO_ERROR;
+}
+
+} // namespace android
diff --git a/libs/utils/file_backup_helper.cpp b/libs/utils/backup_helper_file.cpp
index 453084a..1fa6a0f 100644
--- a/libs/utils/file_backup_helper.cpp
+++ b/libs/utils/backup_helper_file.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#define LOG_TAG "file_backup_helper"
#include <utils/backup_helpers.h>
@@ -19,13 +35,16 @@
#include <cutils/log.h>
-using namespace android;
+namespace android {
#define MAGIC0 0x70616e53 // Snap
#define MAGIC1 0x656c6946 // File
+#if TEST_BACKUP_HELPERS
+#define LOGP(x...) printf(x)
+#else
#define LOGP(x...) LOGD(x)
-//#define LOGP(x...) printf(x)
+#endif
struct SnapshotHeader {
int magic0;
@@ -118,6 +137,8 @@ write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot)
bytesWritten += sizeof(FileState) + round_up(name.length());
}
+ LOGP("write_snapshot_file fd=%d\n", fd);
+
int amt;
SnapshotHeader header = { MAGIC0, N, MAGIC1, bytesWritten };
@@ -248,11 +269,13 @@ back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD,
// file added
String8 realFilename(base);
realFilename.appendPath(q);
+ LOGP("file added: %s\n", realFilename.string());
write_update_file(realFilename, q);
m++;
}
else if (cmp < 0) {
// file removed
+ LOGP("file removed: %s\n", p.string());
write_delete_file(p);
n++;
}
@@ -573,6 +596,107 @@ backup_helper_test_four()
return matched ? 0 : 1;
}
+// hexdump -v -e '" " 8/1 " 0x%02x," "\n"' data_writer.data
+const unsigned char DATA_GOLDEN_FILE[] = {
+ 0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00,
+ 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
+ 0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
+ 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+ 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
+ 0x6e, 0x67, 0x5f, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
+ 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
+ 0x41, 0x70, 0x70, 0x31, 0x0c, 0x00, 0x00, 0x00,
+ 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
+ 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
+ 0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00,
+ 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
+ 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
+ 0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
+ 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
+ 0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
+ 0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
+ 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
+ 0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
+ 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
+ 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
+ 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
+ 0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
+ 0x41, 0x70, 0x70, 0x31, 0x0a, 0x00, 0x00, 0x00,
+ 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
+ 0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61,
+ 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
+ 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
+ 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
+ 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc,
+ 0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00,
+};
+const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
+
+static int
+test_write_header_and_entity(BackupDataWriter& writer, const char* str)
+{
+ int err;
+ String8 text(str);
+
+ err = writer.WriteAppHeader(text);
+ if (err != 0) {
+ fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err));
+ return err;
+ }
+
+ err = writer.WriteEntityHeader(text, text.length()+1);
+ if (err != 0) {
+ fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
+ return err;
+ }
+
+ err = writer.WriteEntityData(text.string(), text.length()+1);
+ if (err != 0) {
+ fprintf(stderr, "write failed for data '%s'\n", text.string());
+ return errno;
+ }
+
+ return err;
+}
+
+int
+backup_helper_test_data_writer()
+{
+ int err;
+ int fd;
+ const char* filename = SCRATCH_DIR "data_writer.data";
+
+ system("rm -r " SCRATCH_DIR);
+ mkdir(SCRATCH_DIR, 0777);
+ mkdir(SCRATCH_DIR "data", 0777);
+
+ fd = creat(filename, 0666);
+ if (fd == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
+ BackupDataWriter writer(fd);
+
+ err = 0;
+ err |= test_write_header_and_entity(writer, "no_padding_");
+ err |= test_write_header_and_entity(writer, "padded_to__3");
+ err |= test_write_header_and_entity(writer, "padded_to_2__");
+ err |= test_write_header_and_entity(writer, "padded_to1");
+
+ writer.WriteAppFooter();
+
+ close(fd);
+
+ err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
+ if (err != 0) {
+ return err;
+ }
+
+ return err;
+}
+
static int
get_mod_time(const char* filename, struct timeval times[2])
{
@@ -594,8 +718,9 @@ int
backup_helper_test_files()
{
int err;
- int newSnapshotFD;
int oldSnapshotFD;
+ int dataStreamFD;
+ int newSnapshotFD;
system("rm -r " SCRATCH_DIR);
mkdir(SCRATCH_DIR, 0777);
@@ -616,17 +741,24 @@ backup_helper_test_files()
"data/f"
};
+ dataStreamFD = creat(SCRATCH_DIR "1.data", 0666);
+ if (dataStreamFD == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
newSnapshotFD = creat(SCRATCH_DIR "before.snap", 0666);
if (newSnapshotFD == -1) {
fprintf(stderr, "error creating: %s\n", strerror(errno));
return errno;
}
-
- err = back_up_files(-1, newSnapshotFD, 0, SCRATCH_DIR, files_before, 5);
+
+ err = back_up_files(-1, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_before, 5);
if (err != 0) {
return err;
}
+ close(dataStreamFD);
close(newSnapshotFD);
sleep(3);
@@ -665,21 +797,30 @@ backup_helper_test_files()
return errno;
}
+ dataStreamFD = creat(SCRATCH_DIR "2.data", 0666);
+ if (dataStreamFD == -1) {
+ fprintf(stderr, "error creating: %s\n", strerror(errno));
+ return errno;
+ }
+
newSnapshotFD = creat(SCRATCH_DIR "after.snap", 0666);
if (newSnapshotFD == -1) {
fprintf(stderr, "error creating: %s\n", strerror(errno));
return errno;
}
- err = back_up_files(oldSnapshotFD, newSnapshotFD, 0, SCRATCH_DIR, files_after, 6);
+ err = back_up_files(oldSnapshotFD, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_after, 6);
if (err != 0) {
return err;
}
close(oldSnapshotFD);
+ close(dataStreamFD);
close(newSnapshotFD);
return 0;
}
#endif // TEST_BACKUP_HELPERS
+
+}