diff options
author | Joe Onorato <joeo@android.com> | 2009-05-15 07:55:51 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-05-15 07:55:51 -0700 |
commit | 55051ebdd1ebf043f9d0e3dcf025c8c8930cf567 (patch) | |
tree | e2e51e5c9fa3bcba1dabf7e770b6c2b85e4e6cd7 /libs/utils | |
parent | dd6face5a66ed6c9ac24b2754ec046b82881182c (diff) | |
parent | 4535e40544aeb957d44fad75fbe5676effe03689 (diff) | |
download | frameworks_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.mk | 3 | ||||
-rw-r--r-- | libs/utils/backup_data.cpp | 236 | ||||
-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 + +} |