diff options
author | Joe Onorato <joeo@android.com> | 2009-05-15 18:20:19 -0400 |
---|---|---|
committer | Joe Onorato <joeo@android.com> | 2009-05-15 18:20:19 -0400 |
commit | 2e1da32203b7f6df76023f25a7382a31fad6b19d (patch) | |
tree | 4595241ae1e0e2207fc2285774f6fef86320e6b6 /libs | |
parent | 4535e40544aeb957d44fad75fbe5676effe03689 (diff) | |
download | frameworks_base-2e1da32203b7f6df76023f25a7382a31fad6b19d.zip frameworks_base-2e1da32203b7f6df76023f25a7382a31fad6b19d.tar.gz frameworks_base-2e1da32203b7f6df76023f25a7382a31fad6b19d.tar.bz2 |
Add the backup data file writer C++ class.
Diffstat (limited to 'libs')
-rw-r--r-- | libs/utils/backup_data.cpp | 228 | ||||
-rw-r--r-- | libs/utils/backup_helper_file.cpp | 189 |
2 files changed, 384 insertions, 33 deletions
diff --git a/libs/utils/backup_data.cpp b/libs/utils/backup_data.cpp index c7f1fdb..dd04449 100644 --- a/libs/utils/backup_data.cpp +++ b/libs/utils/backup_data.cpp @@ -14,12 +14,16 @@ * limitations under the License. */ +#define LOG_TAG "backup_data" + #include <utils/backup_helpers.h> #include <utils/ByteOrder.h> #include <stdio.h> #include <unistd.h> +#include <cutils/log.h> + namespace android { /* @@ -39,22 +43,6 @@ namespace android { #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 @@ -102,7 +90,7 @@ BackupDataWriter::write_padding_for(int n) } status_t -BackupDataWriter::WriteAppHeader(const String8& packageName) +BackupDataWriter::WriteAppHeader(const String8& packageName, int cookie) { if (m_status != NO_ERROR) { return m_status; @@ -122,6 +110,7 @@ BackupDataWriter::WriteAppHeader(const String8& packageName) header.type = tolel(APP_MAGIC_V1); header.packageLen = tolel(nameLen); + header.cookie = cookie; amt = write(m_fd, &header, sizeof(app_header_v1)); if (amt != sizeof(app_header_v1)) { @@ -204,7 +193,7 @@ BackupDataWriter::WriteEntityData(const void* data, size_t size) } status_t -BackupDataWriter::WriteAppFooter() +BackupDataWriter::WriteAppFooter(int cookie) { if (m_status != NO_ERROR) { return m_status; @@ -222,6 +211,7 @@ BackupDataWriter::WriteAppFooter() footer.type = tolel(FOOTER_MAGIC_V1); footer.entityCount = tolel(m_entityCount); + footer.cookie = cookie; amt = write(m_fd, &footer, sizeof(app_footer_v1)); if (amt != sizeof(app_footer_v1)) { @@ -233,4 +223,206 @@ BackupDataWriter::WriteAppFooter() return NO_ERROR; } + +BackupDataReader::BackupDataReader(int fd) + :m_fd(fd), + m_status(NO_ERROR), + m_pos(0), + m_entityCount(0) +{ + memset(&m_header, 0, sizeof(m_header)); +} + +BackupDataReader::~BackupDataReader() +{ +} + +status_t +BackupDataReader::Status() +{ + return m_status; +} + +#define CHECK_SIZE(actual, expected) \ + do { \ + if ((actual) != (expected)) { \ + if ((actual) == 0) { \ + m_status = EIO; \ + } else { \ + m_status = errno; \ + } \ + return m_status; \ + } \ + } while(0) +#define SKIP_PADDING() \ + do { \ + status_t err = skip_padding(); \ + if (err != NO_ERROR) { \ + m_status = err; \ + return err; \ + } \ + } while(0) + +status_t +BackupDataReader::ReadNextHeader() +{ + if (m_status != NO_ERROR) { + return m_status; + } + + int amt; + + SKIP_PADDING(); + amt = read(m_fd, &m_header, sizeof(m_header)); + CHECK_SIZE(amt, sizeof(m_header)); + + // validate and fix up the fields. + m_header.type = fromlel(m_header.type); + switch (m_header.type) + { + case APP_MAGIC_V1: + m_header.app.packageLen = fromlel(m_header.app.packageLen); + if (m_header.app.packageLen < 0) { + LOGD("App header at %d has packageLen<0: 0x%08x\n", (int)m_pos, + (int)m_header.app.packageLen); + m_status = EINVAL; + } + m_header.app.cookie = m_header.app.cookie; + break; + case ENTITY_MAGIC_V1: + m_header.entity.keyLen = fromlel(m_header.entity.keyLen); + if (m_header.entity.keyLen <= 0) { + LOGD("Entity header at %d has keyLen<=0: 0x%08x\n", (int)m_pos, + (int)m_header.entity.keyLen); + m_status = EINVAL; + } + m_header.entity.dataSize = fromlel(m_header.entity.dataSize); + if (m_header.entity.dataSize < 0) { + LOGD("Entity header at %d has dataSize<0: 0x%08x\n", (int)m_pos, + (int)m_header.entity.dataSize); + m_status = EINVAL; + } + m_entityCount++; + break; + case FOOTER_MAGIC_V1: + m_header.footer.entityCount = fromlel(m_header.footer.entityCount); + if (m_header.footer.entityCount < 0) { + LOGD("Entity header at %d has entityCount<0: 0x%08x\n", (int)m_pos, + (int)m_header.footer.entityCount); + m_status = EINVAL; + } + m_header.footer.cookie = m_header.footer.cookie; + break; + default: + LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type); + m_status = EINVAL; + } + m_pos += sizeof(m_header); + + return m_status; +} + +status_t +BackupDataReader::ReadAppHeader(String8* packageName, int* cookie) +{ + if (m_status != NO_ERROR) { + return m_status; + } + if (m_header.type != APP_MAGIC_V1) { + return EINVAL; + } + size_t size = m_header.app.packageLen; + char* buf = packageName->lockBuffer(size); + if (packageName == NULL) { + packageName->unlockBuffer(); + m_status = ENOMEM; + return m_status; + } + int amt = read(m_fd, buf, size+1); + CHECK_SIZE(amt, (int)size+1); + packageName->unlockBuffer(size); + m_pos += size+1; + *cookie = m_header.app.cookie; + return NO_ERROR; +} + +bool +BackupDataReader::HasEntities() +{ + return m_status == NO_ERROR && m_header.type == ENTITY_MAGIC_V1; +} + +status_t +BackupDataReader::ReadEntityHeader(String8* key, size_t* dataSize) +{ + if (m_status != NO_ERROR) { + return m_status; + } + if (m_header.type != ENTITY_MAGIC_V1) { + return EINVAL; + } + size_t size = m_header.app.packageLen; + char* buf = key->lockBuffer(size); + if (key == NULL) { + key->unlockBuffer(); + m_status = ENOMEM; + return m_status; + } + int amt = read(m_fd, buf, size+1); + CHECK_SIZE(amt, (int)size+1); + key->unlockBuffer(size); + m_pos += size+1; + *dataSize = m_header.entity.dataSize; + SKIP_PADDING(); + return NO_ERROR; +} + +status_t +BackupDataReader::ReadEntityData(void* data, size_t size) +{ + if (m_status != NO_ERROR) { + return m_status; + } + int amt = read(m_fd, data, size); + CHECK_SIZE(amt, (int)size); + m_pos += size; + return NO_ERROR; +} + +status_t +BackupDataReader::ReadAppFooter(int* cookie) +{ + if (m_status != NO_ERROR) { + return m_status; + } + if (m_header.type != FOOTER_MAGIC_V1) { + return EINVAL; + } + if (m_header.footer.entityCount != m_entityCount) { + LOGD("entity count mismatch actual=%d expected=%d", m_entityCount, + m_header.footer.entityCount); + m_status = EINVAL; + return m_status; + } + *cookie = m_header.footer.cookie; + return NO_ERROR; +} + +status_t +BackupDataReader::skip_padding() +{ + ssize_t amt; + ssize_t paddingSize; + + paddingSize = padding_extra(m_pos); + if (paddingSize > 0) { + uint32_t padding; + amt = read(m_fd, &padding, paddingSize); + CHECK_SIZE(amt, paddingSize); + m_pos += amt; + } + return NO_ERROR; +} + + } // namespace android diff --git a/libs/utils/backup_helper_file.cpp b/libs/utils/backup_helper_file.cpp index 1fa6a0f..bf56945 100644 --- a/libs/utils/backup_helper_file.cpp +++ b/libs/utils/backup_helper_file.cpp @@ -599,13 +599,14 @@ backup_helper_test_four() // 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, + 0xdd, 0xcc, 0xbb, 0xaa, 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, - 0x41, 0x70, 0x70, 0x31, 0x0c, 0x00, 0x00, 0x00, + 0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69, + 0x6e, 0x67, 0x5f, 0x00, 0x41, 0x70, 0x70, 0x31, + 0x0c, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa, 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00, @@ -614,15 +615,16 @@ const unsigned char DATA_GOLDEN_FILE[] = { 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, + 0x0d, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa, 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, + 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, 0xdd, 0xcc, 0xbb, 0xaa, 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, @@ -630,6 +632,7 @@ const unsigned char DATA_GOLDEN_FILE[] = { 0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc, 0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00, + 0x99, 0x99, 0x77, 0x77 }; const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE); @@ -639,7 +642,7 @@ test_write_header_and_entity(BackupDataWriter& writer, const char* str) int err; String8 text(str); - err = writer.WriteAppHeader(text); + err = writer.WriteAppHeader(text, 0xaabbccdd); if (err != 0) { fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err)); return err; @@ -685,7 +688,7 @@ backup_helper_test_data_writer() err |= test_write_header_and_entity(writer, "padded_to_2__"); err |= test_write_header_and_entity(writer, "padded_to1"); - writer.WriteAppFooter(); + writer.WriteAppFooter(0x77779999); close(fd); @@ -697,6 +700,162 @@ backup_helper_test_data_writer() return err; } +int +test_read_header_and_entity(BackupDataReader& reader, const char* str) +{ + int err; + int bufSize = strlen(str)+1; + char* buf = (char*)malloc(bufSize); + String8 string; + int cookie = 0x11111111; + size_t actualSize; + + // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str); + + err = reader.ReadNextHeader(); + if (err != 0) { + fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err)); + goto done; + } + + err = reader.ReadAppHeader(&string, &cookie); + if (err != 0) { + fprintf(stderr, "ReadAppHeader failed with %s\n", strerror(err)); + goto done; + } + if (string != str) { + fprintf(stderr, "ReadAppHeader expected packageName '%s' got '%s'\n", str, string.string()); + err = EINVAL; + goto done; + } + if (cookie != (int)0xaabbccdd) { + fprintf(stderr, "ReadAppHeader expected cookie 0x%08x got 0x%08x\n", 0xaabbccdd, cookie); + err = EINVAL; + goto done; + } + + err = reader.ReadNextHeader(); + if (err != 0) { + fprintf(stderr, "ReadNextHeader (for entity header) failed with %s\n", strerror(err)); + goto done; + } + + err = reader.ReadEntityHeader(&string, &actualSize); + if (err != 0) { + fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err)); + goto done; + } + if (string != str) { + fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string()); + err = EINVAL; + goto done; + } + if ((int)actualSize != bufSize) { + fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize, + actualSize); + err = EINVAL; + goto done; + } + + err = reader.ReadEntityData(buf, bufSize); + if (err != NO_ERROR) { + fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err)); + goto done; + } + + if (0 != memcmp(buf, str, bufSize)) { + fprintf(stderr, "ReadEntityData expected '%s' but got something starting with " + "%02x %02x %02x %02x\n", str, buf[0], buf[1], buf[2], buf[3]); + err = EINVAL; + goto done; + } + + // The next read will confirm whether it got the right amount of data. + +done: + if (err != NO_ERROR) { + fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err)); + } + free(buf); + return err; +} + +int +backup_helper_test_data_reader() +{ + int err; + int fd; + const char* filename = SCRATCH_DIR "data_reader.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; + } + + err = write(fd, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE); + if (err != DATA_GOLDEN_FILE_SIZE) { + fprintf(stderr, "Error \"%s\" writing golden file %s\n", strerror(errno), filename); + return errno; + } + + close(fd); + + fd = open(filename, O_RDONLY); + if (fd == -1) { + fprintf(stderr, "Error \"%s\" opening golden file %s for read\n", strerror(errno), + filename); + return errno; + } + + { + BackupDataReader reader(fd); + + err = 0; + + if (err == NO_ERROR) { + err = test_read_header_and_entity(reader, "no_padding_"); + } + + if (err == NO_ERROR) { + err = test_read_header_and_entity(reader, "padded_to__3"); + } + + if (err == NO_ERROR) { + err = test_read_header_and_entity(reader, "padded_to_2__"); + } + + if (err == NO_ERROR) { + err = test_read_header_and_entity(reader, "padded_to1"); + } + + if (err == NO_ERROR) { + err = reader.ReadNextHeader(); + if (err != 0) { + fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err)); + } + + if (err == NO_ERROR) { + int cookie; + err |= reader.ReadAppFooter(&cookie); + if (cookie != 0x77779999) { + fprintf(stderr, "app footer cookie expected=0x%08x actual=0x%08x\n", + 0x77779999, cookie); + err = EINVAL; + } + } + } + } + + close(fd); + + return err; +} + static int get_mod_time(const char* filename, struct timeval times[2]) { |