Loading include/utils/backup_helpers.h +16 −8 Original line number Original line Diff line number Diff line Loading @@ -22,24 +22,27 @@ namespace android { namespace android { int back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, enum { char const* fileBase, char const* const* files, int fileCount); BACKUP_HEADER_APP_V1 = 0x31707041, // App1 (little endian) BACKUP_HEADER_ENTITY_V1 = 0x61746144, // Data (little endian) BACKUP_FOOTER_APP_V1 = 0x746f6f46, // Foot (little endian) }; // the sizes of all of these match. // the sizes of all of these match. typedef struct { typedef struct { int type; // == APP_MAGIC_V1 int type; // == BACKUP_HEADER_APP_V1 int packageLen; // length of the name of the package that follows, not including the null. int packageLen; // length of the name of the package that follows, not including the null. int cookie; int cookie; } app_header_v1; } app_header_v1; typedef struct { typedef struct { int type; // ENTITY_MAGIC_V1 int type; // BACKUP_HEADER_ENTITY_V1 int keyLen; // length of the key name, not including the null terminator int keyLen; // length of the key name, not including the null terminator int dataSize; // size of the data, not including the padding int dataSize; // size of the data, not including the padding, -1 means delete } entity_header_v1; } entity_header_v1; typedef struct { typedef struct { int type; // FOOTER_MAGIC_V1 int type; // BACKUP_FOOTER_APP_V1 int entityCount; // the number of entities that were written int entityCount; // the number of entities that were written int cookie; int cookie; } app_footer_v1; } app_footer_v1; Loading Loading @@ -89,11 +92,12 @@ public: ~BackupDataReader(); ~BackupDataReader(); status_t Status(); status_t Status(); status_t ReadNextHeader(); status_t ReadNextHeader(int* type = NULL); status_t ReadAppHeader(String8* packageName, int* cookie); status_t ReadAppHeader(String8* packageName, int* cookie); bool HasEntities(); bool HasEntities(); status_t ReadEntityHeader(String8* key, size_t* dataSize); status_t ReadEntityHeader(String8* key, size_t* dataSize); status_t SkipEntityData(); // must be called with the pointer at the begining of the data. status_t ReadEntityData(void* data, size_t size); status_t ReadEntityData(void* data, size_t size); status_t ReadAppFooter(int* cookie); status_t ReadAppFooter(int* cookie); Loading @@ -113,7 +117,11 @@ private: } m_header; } m_header; }; }; #define TEST_BACKUP_HELPERS 0 int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD, char const* fileBase, char const* const* files, int fileCount); #define TEST_BACKUP_HELPERS 1 #if TEST_BACKUP_HELPERS #if TEST_BACKUP_HELPERS int backup_helper_test_empty(); int backup_helper_test_empty(); Loading libs/utils/backup_data.cpp +32 −21 Original line number Original line Diff line number Diff line Loading @@ -39,10 +39,6 @@ namespace android { * - The value, 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) const static int ROUND_UP[4] = { 0, 3, 2, 1 }; const static int ROUND_UP[4] = { 0, 3, 2, 1 }; static inline size_t static inline size_t Loading Loading @@ -108,7 +104,7 @@ BackupDataWriter::WriteAppHeader(const String8& packageName, int cookie) nameLen = packageName.length(); nameLen = packageName.length(); header.type = tolel(APP_MAGIC_V1); header.type = tolel(BACKUP_HEADER_APP_V1); header.packageLen = tolel(nameLen); header.packageLen = tolel(nameLen); header.cookie = cookie; header.cookie = cookie; Loading Loading @@ -148,7 +144,7 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) keyLen = key.length(); keyLen = key.length(); header.type = tolel(ENTITY_MAGIC_V1); header.type = tolel(BACKUP_HEADER_ENTITY_V1); header.keyLen = tolel(keyLen); header.keyLen = tolel(keyLen); header.dataSize = tolel(dataSize); header.dataSize = tolel(dataSize); Loading Loading @@ -209,7 +205,7 @@ BackupDataWriter::WriteAppFooter(int cookie) app_footer_v1 footer; app_footer_v1 footer; ssize_t nameLen; ssize_t nameLen; footer.type = tolel(FOOTER_MAGIC_V1); footer.type = tolel(BACKUP_FOOTER_APP_V1); footer.entityCount = tolel(m_entityCount); footer.entityCount = tolel(m_entityCount); footer.cookie = cookie; footer.cookie = cookie; Loading Loading @@ -264,7 +260,7 @@ BackupDataReader::Status() } while(0) } while(0) status_t status_t BackupDataReader::ReadNextHeader() BackupDataReader::ReadNextHeader(int* type) { { if (m_status != NO_ERROR) { if (m_status != NO_ERROR) { return m_status; return m_status; Loading @@ -280,7 +276,7 @@ BackupDataReader::ReadNextHeader() m_header.type = fromlel(m_header.type); m_header.type = fromlel(m_header.type); switch (m_header.type) switch (m_header.type) { { case APP_MAGIC_V1: case BACKUP_HEADER_APP_V1: m_header.app.packageLen = fromlel(m_header.app.packageLen); m_header.app.packageLen = fromlel(m_header.app.packageLen); if (m_header.app.packageLen < 0) { if (m_header.app.packageLen < 0) { LOGD("App header at %d has packageLen<0: 0x%08x\n", (int)m_pos, LOGD("App header at %d has packageLen<0: 0x%08x\n", (int)m_pos, Loading @@ -289,7 +285,7 @@ BackupDataReader::ReadNextHeader() } } m_header.app.cookie = m_header.app.cookie; m_header.app.cookie = m_header.app.cookie; break; break; case ENTITY_MAGIC_V1: case BACKUP_HEADER_ENTITY_V1: m_header.entity.keyLen = fromlel(m_header.entity.keyLen); m_header.entity.keyLen = fromlel(m_header.entity.keyLen); if (m_header.entity.keyLen <= 0) { if (m_header.entity.keyLen <= 0) { LOGD("Entity header at %d has keyLen<=0: 0x%08x\n", (int)m_pos, LOGD("Entity header at %d has keyLen<=0: 0x%08x\n", (int)m_pos, Loading @@ -297,14 +293,9 @@ BackupDataReader::ReadNextHeader() m_status = EINVAL; m_status = EINVAL; } } m_header.entity.dataSize = fromlel(m_header.entity.dataSize); 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++; m_entityCount++; break; break; case FOOTER_MAGIC_V1: case BACKUP_FOOTER_APP_V1: m_header.footer.entityCount = fromlel(m_header.footer.entityCount); m_header.footer.entityCount = fromlel(m_header.footer.entityCount); if (m_header.footer.entityCount < 0) { if (m_header.footer.entityCount < 0) { LOGD("Entity header at %d has entityCount<0: 0x%08x\n", (int)m_pos, LOGD("Entity header at %d has entityCount<0: 0x%08x\n", (int)m_pos, Loading @@ -318,6 +309,9 @@ BackupDataReader::ReadNextHeader() m_status = EINVAL; m_status = EINVAL; } } m_pos += sizeof(m_header); m_pos += sizeof(m_header); if (type) { *type = m_header.type; } return m_status; return m_status; } } Loading @@ -328,7 +322,7 @@ BackupDataReader::ReadAppHeader(String8* packageName, int* cookie) if (m_status != NO_ERROR) { if (m_status != NO_ERROR) { return m_status; return m_status; } } if (m_header.type != APP_MAGIC_V1) { if (m_header.type != BACKUP_HEADER_APP_V1) { return EINVAL; return EINVAL; } } size_t size = m_header.app.packageLen; size_t size = m_header.app.packageLen; Loading @@ -349,7 +343,7 @@ BackupDataReader::ReadAppHeader(String8* packageName, int* cookie) bool bool BackupDataReader::HasEntities() BackupDataReader::HasEntities() { { return m_status == NO_ERROR && m_header.type == ENTITY_MAGIC_V1; return m_status == NO_ERROR && m_header.type == BACKUP_HEADER_ENTITY_V1; } } status_t status_t Loading @@ -358,10 +352,10 @@ BackupDataReader::ReadEntityHeader(String8* key, size_t* dataSize) if (m_status != NO_ERROR) { if (m_status != NO_ERROR) { return m_status; return m_status; } } if (m_header.type != ENTITY_MAGIC_V1) { if (m_header.type != BACKUP_HEADER_ENTITY_V1) { return EINVAL; return EINVAL; } } size_t size = m_header.app.packageLen; size_t size = m_header.entity.keyLen; char* buf = key->lockBuffer(size); char* buf = key->lockBuffer(size); if (key == NULL) { if (key == NULL) { key->unlockBuffer(); key->unlockBuffer(); Loading @@ -377,6 +371,23 @@ BackupDataReader::ReadEntityHeader(String8* key, size_t* dataSize) return NO_ERROR; return NO_ERROR; } } status_t BackupDataReader::SkipEntityData() { if (m_status != NO_ERROR) { return m_status; } if (m_header.type != BACKUP_HEADER_ENTITY_V1) { return EINVAL; } if (m_header.entity.dataSize > 0) { int pos = lseek(m_fd, m_header.entity.dataSize, SEEK_CUR); return pos == -1 ? (int)errno : (int)NO_ERROR; } else { return NO_ERROR; } } status_t status_t BackupDataReader::ReadEntityData(void* data, size_t size) BackupDataReader::ReadEntityData(void* data, size_t size) { { Loading @@ -395,7 +406,7 @@ BackupDataReader::ReadAppFooter(int* cookie) if (m_status != NO_ERROR) { if (m_status != NO_ERROR) { return m_status; return m_status; } } if (m_header.type != FOOTER_MAGIC_V1) { if (m_header.type != BACKUP_FOOTER_APP_V1) { return EINVAL; return EINVAL; } } if (m_header.footer.entityCount != m_entityCount) { if (m_header.footer.entityCount != m_entityCount) { Loading libs/utils/backup_helper_file.cpp +117 −35 Original line number Original line Diff line number Diff line Loading @@ -40,7 +40,7 @@ namespace android { #define MAGIC0 0x70616e53 // Snap #define MAGIC0 0x70616e53 // Snap #define MAGIC1 0x656c6946 // File #define MAGIC1 0x656c6946 // File #if TEST_BACKUP_HELPERS #if 0 // TEST_BACKUP_HELPERS #define LOGP(x...) printf(x) #define LOGP(x...) printf(x) #else #else #define LOGP(x...) LOGD(x) #define LOGP(x...) LOGD(x) Loading Loading @@ -181,45 +181,105 @@ write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot) } } static int static int write_delete_file(const String8& key) write_delete_file(BackupDataWriter* dataStream, const String8& key) { { LOGP("write_delete_file %s\n", key.string()); LOGP("write_delete_file %s\n", key.string()); return 0; return dataStream->WriteEntityHeader(key, -1); } } static int static int write_update_file(const String8& realFilename, const String8& key) write_update_file(BackupDataWriter* dataStream, int fd, const String8& key, const String8& realFilename) { { LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string()); LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string()); return 0; } static int compute_crc32(const String8& filename) { const int bufsize = 4*1024; const int bufsize = 4*1024; int err; int amt; int amt; int fileSize; int bytesLeft; char* buf = (char*)malloc(bufsize); int crc = crc32(0L, Z_NULL, 0); bytesLeft = fileSize = lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET); err = dataStream->WriteEntityHeader(key, bytesLeft); if (err != 0) { return err; } while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) { bytesLeft -= amt; if (bytesLeft < 0) { amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised. } err = dataStream->WriteEntityData(buf, amt); if (err != 0) { return err; } } if (bytesLeft != 0) { if (bytesLeft > 0) { // Pad out the space we promised in the buffer. We can't corrupt the buffer, // even though the data we're sending is probably bad. memset(buf, 0, bufsize); while (bytesLeft > 0) { amt = bytesLeft < bufsize ? bytesLeft : bufsize; bytesLeft -= amt; err = dataStream->WriteEntityData(buf, amt); if (err != 0) { return err; } } } LOGE("write_update_file size mismatch for %s. expected=%d actual=%d." " You aren't doing proper locking!", realFilename.string(), fileSize, fileSize-bytesLeft); } free(buf); return NO_ERROR; } int fd = open(filename.string(), O_RDONLY); static int write_update_file(BackupDataWriter* dataStream, const String8& key, const String8& realFilename) { int err; int fd = open(realFilename.string(), O_RDONLY); if (fd == -1) { if (fd == -1) { return -1; return errno; } } err = write_update_file(dataStream, fd, key, realFilename); close(fd); return err; } static int compute_crc32(int fd) { const int bufsize = 4*1024; int amt; char* buf = (char*)malloc(bufsize); char* buf = (char*)malloc(bufsize); int crc = crc32(0L, Z_NULL, 0); int crc = crc32(0L, Z_NULL, 0); lseek(fd, 0, SEEK_SET); while ((amt = read(fd, buf, bufsize)) != 0) { while ((amt = read(fd, buf, bufsize)) != 0) { crc = crc32(crc, (Bytef*)buf, amt); crc = crc32(crc, (Bytef*)buf, amt); } } close(fd); free(buf); free(buf); return crc; return crc; } } int int back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD, char const* fileBase, char const* const* files, int fileCount) char const* fileBase, char const* const* files, int fileCount) { { int err; int err; Loading Loading @@ -252,7 +312,8 @@ back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, s.modTime_nsec = 0; // workaround sim breakage s.modTime_nsec = 0; // workaround sim breakage //s.modTime_nsec = st.st_mtime_nsec; //s.modTime_nsec = st.st_mtime_nsec; s.size = st.st_size; s.size = st.st_size; s.crc32 = compute_crc32(realFilename); // we compute the crc32 later down below, when we already have the file open. newSnapshot.add(name, s); newSnapshot.add(name, s); } } Loading @@ -270,21 +331,30 @@ back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, String8 realFilename(base); String8 realFilename(base); realFilename.appendPath(q); realFilename.appendPath(q); LOGP("file added: %s\n", realFilename.string()); LOGP("file added: %s\n", realFilename.string()); write_update_file(realFilename, q); write_update_file(dataStream, q, realFilename); m++; m++; } } else if (cmp < 0) { else if (cmp < 0) { // file removed // file removed LOGP("file removed: %s\n", p.string()); LOGP("file removed: %s\n", p.string()); write_delete_file(p); dataStream->WriteEntityHeader(p, -1); n++; n++; } } else { else { // both files exist, check them // both files exist, check them String8 realFilename(base); String8 realFilename(base); realFilename.appendPath(q); realFilename.appendPath(q); const FileState& f = oldSnapshot.valueAt(n); const FileState& f = oldSnapshot.valueAt(n); const FileState& g = newSnapshot.valueAt(m); FileState& g = newSnapshot.editValueAt(m); int fd = open(realFilename.string(), O_RDONLY); if (fd != -1) { // 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 // on restore. } else { g.crc32 = compute_crc32(fd); LOGP("%s\n", q.string()); LOGP("%s\n", q.string()); LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n", LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n", Loading @@ -293,7 +363,10 @@ back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, g.modTime_sec, g.modTime_nsec, g.size, g.crc32); g.modTime_sec, g.modTime_nsec, g.size, g.crc32); if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec || f.size != g.size || f.crc32 != g.crc32) { || f.size != g.size || f.crc32 != g.crc32) { write_update_file(realFilename, p); write_update_file(dataStream, fd, p, realFilename); } close(fd); } } n++; n++; m++; m++; Loading @@ -302,7 +375,7 @@ back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, // these were deleted // these were deleted while (n<N) { while (n<N) { write_delete_file(oldSnapshot.keyAt(n)); dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1); n++; n++; } } Loading @@ -311,7 +384,7 @@ back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, const String8& q = newSnapshot.keyAt(m); const String8& q = newSnapshot.keyAt(m); String8 realFilename(base); String8 realFilename(base); realFilename.appendPath(q); realFilename.appendPath(q); write_update_file(realFilename, q); write_update_file(dataStream, q, realFilename); m++; m++; } } Loading Loading @@ -912,10 +985,14 @@ backup_helper_test_files() return errno; return errno; } } err = back_up_files(-1, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_before, 5); { BackupDataWriter dataStream(dataStreamFD); err = back_up_files(-1, &dataStream, newSnapshotFD, SCRATCH_DIR, files_before, 5); if (err != 0) { if (err != 0) { return err; return err; } } } close(dataStreamFD); close(dataStreamFD); close(newSnapshotFD); close(newSnapshotFD); Loading Loading @@ -968,10 +1045,15 @@ backup_helper_test_files() return errno; return errno; } } err = back_up_files(oldSnapshotFD, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_after, 6); { BackupDataWriter dataStream(dataStreamFD); err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, SCRATCH_DIR, files_after, 6); if (err != 0) { if (err != 0) { return err; return err; } } } close(oldSnapshotFD); close(oldSnapshotFD); close(dataStreamFD); close(dataStreamFD); Loading Loading
include/utils/backup_helpers.h +16 −8 Original line number Original line Diff line number Diff line Loading @@ -22,24 +22,27 @@ namespace android { namespace android { int back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, enum { char const* fileBase, char const* const* files, int fileCount); BACKUP_HEADER_APP_V1 = 0x31707041, // App1 (little endian) BACKUP_HEADER_ENTITY_V1 = 0x61746144, // Data (little endian) BACKUP_FOOTER_APP_V1 = 0x746f6f46, // Foot (little endian) }; // the sizes of all of these match. // the sizes of all of these match. typedef struct { typedef struct { int type; // == APP_MAGIC_V1 int type; // == BACKUP_HEADER_APP_V1 int packageLen; // length of the name of the package that follows, not including the null. int packageLen; // length of the name of the package that follows, not including the null. int cookie; int cookie; } app_header_v1; } app_header_v1; typedef struct { typedef struct { int type; // ENTITY_MAGIC_V1 int type; // BACKUP_HEADER_ENTITY_V1 int keyLen; // length of the key name, not including the null terminator int keyLen; // length of the key name, not including the null terminator int dataSize; // size of the data, not including the padding int dataSize; // size of the data, not including the padding, -1 means delete } entity_header_v1; } entity_header_v1; typedef struct { typedef struct { int type; // FOOTER_MAGIC_V1 int type; // BACKUP_FOOTER_APP_V1 int entityCount; // the number of entities that were written int entityCount; // the number of entities that were written int cookie; int cookie; } app_footer_v1; } app_footer_v1; Loading Loading @@ -89,11 +92,12 @@ public: ~BackupDataReader(); ~BackupDataReader(); status_t Status(); status_t Status(); status_t ReadNextHeader(); status_t ReadNextHeader(int* type = NULL); status_t ReadAppHeader(String8* packageName, int* cookie); status_t ReadAppHeader(String8* packageName, int* cookie); bool HasEntities(); bool HasEntities(); status_t ReadEntityHeader(String8* key, size_t* dataSize); status_t ReadEntityHeader(String8* key, size_t* dataSize); status_t SkipEntityData(); // must be called with the pointer at the begining of the data. status_t ReadEntityData(void* data, size_t size); status_t ReadEntityData(void* data, size_t size); status_t ReadAppFooter(int* cookie); status_t ReadAppFooter(int* cookie); Loading @@ -113,7 +117,11 @@ private: } m_header; } m_header; }; }; #define TEST_BACKUP_HELPERS 0 int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD, char const* fileBase, char const* const* files, int fileCount); #define TEST_BACKUP_HELPERS 1 #if TEST_BACKUP_HELPERS #if TEST_BACKUP_HELPERS int backup_helper_test_empty(); int backup_helper_test_empty(); Loading
libs/utils/backup_data.cpp +32 −21 Original line number Original line Diff line number Diff line Loading @@ -39,10 +39,6 @@ namespace android { * - The value, 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) const static int ROUND_UP[4] = { 0, 3, 2, 1 }; const static int ROUND_UP[4] = { 0, 3, 2, 1 }; static inline size_t static inline size_t Loading Loading @@ -108,7 +104,7 @@ BackupDataWriter::WriteAppHeader(const String8& packageName, int cookie) nameLen = packageName.length(); nameLen = packageName.length(); header.type = tolel(APP_MAGIC_V1); header.type = tolel(BACKUP_HEADER_APP_V1); header.packageLen = tolel(nameLen); header.packageLen = tolel(nameLen); header.cookie = cookie; header.cookie = cookie; Loading Loading @@ -148,7 +144,7 @@ BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize) keyLen = key.length(); keyLen = key.length(); header.type = tolel(ENTITY_MAGIC_V1); header.type = tolel(BACKUP_HEADER_ENTITY_V1); header.keyLen = tolel(keyLen); header.keyLen = tolel(keyLen); header.dataSize = tolel(dataSize); header.dataSize = tolel(dataSize); Loading Loading @@ -209,7 +205,7 @@ BackupDataWriter::WriteAppFooter(int cookie) app_footer_v1 footer; app_footer_v1 footer; ssize_t nameLen; ssize_t nameLen; footer.type = tolel(FOOTER_MAGIC_V1); footer.type = tolel(BACKUP_FOOTER_APP_V1); footer.entityCount = tolel(m_entityCount); footer.entityCount = tolel(m_entityCount); footer.cookie = cookie; footer.cookie = cookie; Loading Loading @@ -264,7 +260,7 @@ BackupDataReader::Status() } while(0) } while(0) status_t status_t BackupDataReader::ReadNextHeader() BackupDataReader::ReadNextHeader(int* type) { { if (m_status != NO_ERROR) { if (m_status != NO_ERROR) { return m_status; return m_status; Loading @@ -280,7 +276,7 @@ BackupDataReader::ReadNextHeader() m_header.type = fromlel(m_header.type); m_header.type = fromlel(m_header.type); switch (m_header.type) switch (m_header.type) { { case APP_MAGIC_V1: case BACKUP_HEADER_APP_V1: m_header.app.packageLen = fromlel(m_header.app.packageLen); m_header.app.packageLen = fromlel(m_header.app.packageLen); if (m_header.app.packageLen < 0) { if (m_header.app.packageLen < 0) { LOGD("App header at %d has packageLen<0: 0x%08x\n", (int)m_pos, LOGD("App header at %d has packageLen<0: 0x%08x\n", (int)m_pos, Loading @@ -289,7 +285,7 @@ BackupDataReader::ReadNextHeader() } } m_header.app.cookie = m_header.app.cookie; m_header.app.cookie = m_header.app.cookie; break; break; case ENTITY_MAGIC_V1: case BACKUP_HEADER_ENTITY_V1: m_header.entity.keyLen = fromlel(m_header.entity.keyLen); m_header.entity.keyLen = fromlel(m_header.entity.keyLen); if (m_header.entity.keyLen <= 0) { if (m_header.entity.keyLen <= 0) { LOGD("Entity header at %d has keyLen<=0: 0x%08x\n", (int)m_pos, LOGD("Entity header at %d has keyLen<=0: 0x%08x\n", (int)m_pos, Loading @@ -297,14 +293,9 @@ BackupDataReader::ReadNextHeader() m_status = EINVAL; m_status = EINVAL; } } m_header.entity.dataSize = fromlel(m_header.entity.dataSize); 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++; m_entityCount++; break; break; case FOOTER_MAGIC_V1: case BACKUP_FOOTER_APP_V1: m_header.footer.entityCount = fromlel(m_header.footer.entityCount); m_header.footer.entityCount = fromlel(m_header.footer.entityCount); if (m_header.footer.entityCount < 0) { if (m_header.footer.entityCount < 0) { LOGD("Entity header at %d has entityCount<0: 0x%08x\n", (int)m_pos, LOGD("Entity header at %d has entityCount<0: 0x%08x\n", (int)m_pos, Loading @@ -318,6 +309,9 @@ BackupDataReader::ReadNextHeader() m_status = EINVAL; m_status = EINVAL; } } m_pos += sizeof(m_header); m_pos += sizeof(m_header); if (type) { *type = m_header.type; } return m_status; return m_status; } } Loading @@ -328,7 +322,7 @@ BackupDataReader::ReadAppHeader(String8* packageName, int* cookie) if (m_status != NO_ERROR) { if (m_status != NO_ERROR) { return m_status; return m_status; } } if (m_header.type != APP_MAGIC_V1) { if (m_header.type != BACKUP_HEADER_APP_V1) { return EINVAL; return EINVAL; } } size_t size = m_header.app.packageLen; size_t size = m_header.app.packageLen; Loading @@ -349,7 +343,7 @@ BackupDataReader::ReadAppHeader(String8* packageName, int* cookie) bool bool BackupDataReader::HasEntities() BackupDataReader::HasEntities() { { return m_status == NO_ERROR && m_header.type == ENTITY_MAGIC_V1; return m_status == NO_ERROR && m_header.type == BACKUP_HEADER_ENTITY_V1; } } status_t status_t Loading @@ -358,10 +352,10 @@ BackupDataReader::ReadEntityHeader(String8* key, size_t* dataSize) if (m_status != NO_ERROR) { if (m_status != NO_ERROR) { return m_status; return m_status; } } if (m_header.type != ENTITY_MAGIC_V1) { if (m_header.type != BACKUP_HEADER_ENTITY_V1) { return EINVAL; return EINVAL; } } size_t size = m_header.app.packageLen; size_t size = m_header.entity.keyLen; char* buf = key->lockBuffer(size); char* buf = key->lockBuffer(size); if (key == NULL) { if (key == NULL) { key->unlockBuffer(); key->unlockBuffer(); Loading @@ -377,6 +371,23 @@ BackupDataReader::ReadEntityHeader(String8* key, size_t* dataSize) return NO_ERROR; return NO_ERROR; } } status_t BackupDataReader::SkipEntityData() { if (m_status != NO_ERROR) { return m_status; } if (m_header.type != BACKUP_HEADER_ENTITY_V1) { return EINVAL; } if (m_header.entity.dataSize > 0) { int pos = lseek(m_fd, m_header.entity.dataSize, SEEK_CUR); return pos == -1 ? (int)errno : (int)NO_ERROR; } else { return NO_ERROR; } } status_t status_t BackupDataReader::ReadEntityData(void* data, size_t size) BackupDataReader::ReadEntityData(void* data, size_t size) { { Loading @@ -395,7 +406,7 @@ BackupDataReader::ReadAppFooter(int* cookie) if (m_status != NO_ERROR) { if (m_status != NO_ERROR) { return m_status; return m_status; } } if (m_header.type != FOOTER_MAGIC_V1) { if (m_header.type != BACKUP_FOOTER_APP_V1) { return EINVAL; return EINVAL; } } if (m_header.footer.entityCount != m_entityCount) { if (m_header.footer.entityCount != m_entityCount) { Loading
libs/utils/backup_helper_file.cpp +117 −35 Original line number Original line Diff line number Diff line Loading @@ -40,7 +40,7 @@ namespace android { #define MAGIC0 0x70616e53 // Snap #define MAGIC0 0x70616e53 // Snap #define MAGIC1 0x656c6946 // File #define MAGIC1 0x656c6946 // File #if TEST_BACKUP_HELPERS #if 0 // TEST_BACKUP_HELPERS #define LOGP(x...) printf(x) #define LOGP(x...) printf(x) #else #else #define LOGP(x...) LOGD(x) #define LOGP(x...) LOGD(x) Loading Loading @@ -181,45 +181,105 @@ write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot) } } static int static int write_delete_file(const String8& key) write_delete_file(BackupDataWriter* dataStream, const String8& key) { { LOGP("write_delete_file %s\n", key.string()); LOGP("write_delete_file %s\n", key.string()); return 0; return dataStream->WriteEntityHeader(key, -1); } } static int static int write_update_file(const String8& realFilename, const String8& key) write_update_file(BackupDataWriter* dataStream, int fd, const String8& key, const String8& realFilename) { { LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string()); LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string()); return 0; } static int compute_crc32(const String8& filename) { const int bufsize = 4*1024; const int bufsize = 4*1024; int err; int amt; int amt; int fileSize; int bytesLeft; char* buf = (char*)malloc(bufsize); int crc = crc32(0L, Z_NULL, 0); bytesLeft = fileSize = lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET); err = dataStream->WriteEntityHeader(key, bytesLeft); if (err != 0) { return err; } while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) { bytesLeft -= amt; if (bytesLeft < 0) { amt += bytesLeft; // Plus a negative is minus. Don't write more than we promised. } err = dataStream->WriteEntityData(buf, amt); if (err != 0) { return err; } } if (bytesLeft != 0) { if (bytesLeft > 0) { // Pad out the space we promised in the buffer. We can't corrupt the buffer, // even though the data we're sending is probably bad. memset(buf, 0, bufsize); while (bytesLeft > 0) { amt = bytesLeft < bufsize ? bytesLeft : bufsize; bytesLeft -= amt; err = dataStream->WriteEntityData(buf, amt); if (err != 0) { return err; } } } LOGE("write_update_file size mismatch for %s. expected=%d actual=%d." " You aren't doing proper locking!", realFilename.string(), fileSize, fileSize-bytesLeft); } free(buf); return NO_ERROR; } int fd = open(filename.string(), O_RDONLY); static int write_update_file(BackupDataWriter* dataStream, const String8& key, const String8& realFilename) { int err; int fd = open(realFilename.string(), O_RDONLY); if (fd == -1) { if (fd == -1) { return -1; return errno; } } err = write_update_file(dataStream, fd, key, realFilename); close(fd); return err; } static int compute_crc32(int fd) { const int bufsize = 4*1024; int amt; char* buf = (char*)malloc(bufsize); char* buf = (char*)malloc(bufsize); int crc = crc32(0L, Z_NULL, 0); int crc = crc32(0L, Z_NULL, 0); lseek(fd, 0, SEEK_SET); while ((amt = read(fd, buf, bufsize)) != 0) { while ((amt = read(fd, buf, bufsize)) != 0) { crc = crc32(crc, (Bytef*)buf, amt); crc = crc32(crc, (Bytef*)buf, amt); } } close(fd); free(buf); free(buf); return crc; return crc; } } int int back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD, char const* fileBase, char const* const* files, int fileCount) char const* fileBase, char const* const* files, int fileCount) { { int err; int err; Loading Loading @@ -252,7 +312,8 @@ back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, s.modTime_nsec = 0; // workaround sim breakage s.modTime_nsec = 0; // workaround sim breakage //s.modTime_nsec = st.st_mtime_nsec; //s.modTime_nsec = st.st_mtime_nsec; s.size = st.st_size; s.size = st.st_size; s.crc32 = compute_crc32(realFilename); // we compute the crc32 later down below, when we already have the file open. newSnapshot.add(name, s); newSnapshot.add(name, s); } } Loading @@ -270,21 +331,30 @@ back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, String8 realFilename(base); String8 realFilename(base); realFilename.appendPath(q); realFilename.appendPath(q); LOGP("file added: %s\n", realFilename.string()); LOGP("file added: %s\n", realFilename.string()); write_update_file(realFilename, q); write_update_file(dataStream, q, realFilename); m++; m++; } } else if (cmp < 0) { else if (cmp < 0) { // file removed // file removed LOGP("file removed: %s\n", p.string()); LOGP("file removed: %s\n", p.string()); write_delete_file(p); dataStream->WriteEntityHeader(p, -1); n++; n++; } } else { else { // both files exist, check them // both files exist, check them String8 realFilename(base); String8 realFilename(base); realFilename.appendPath(q); realFilename.appendPath(q); const FileState& f = oldSnapshot.valueAt(n); const FileState& f = oldSnapshot.valueAt(n); const FileState& g = newSnapshot.valueAt(m); FileState& g = newSnapshot.editValueAt(m); int fd = open(realFilename.string(), O_RDONLY); if (fd != -1) { // 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 // on restore. } else { g.crc32 = compute_crc32(fd); LOGP("%s\n", q.string()); LOGP("%s\n", q.string()); LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n", LOGP(" new: modTime=%d,%d size=%-3d crc32=0x%08x\n", Loading @@ -293,7 +363,10 @@ back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, g.modTime_sec, g.modTime_nsec, g.size, g.crc32); g.modTime_sec, g.modTime_nsec, g.size, g.crc32); if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec || f.size != g.size || f.crc32 != g.crc32) { || f.size != g.size || f.crc32 != g.crc32) { write_update_file(realFilename, p); write_update_file(dataStream, fd, p, realFilename); } close(fd); } } n++; n++; m++; m++; Loading @@ -302,7 +375,7 @@ back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, // these were deleted // these were deleted while (n<N) { while (n<N) { write_delete_file(oldSnapshot.keyAt(n)); dataStream->WriteEntityHeader(oldSnapshot.keyAt(n), -1); n++; n++; } } Loading @@ -311,7 +384,7 @@ back_up_files(int oldSnapshotFD, int oldDataStream, int newSnapshotFD, const String8& q = newSnapshot.keyAt(m); const String8& q = newSnapshot.keyAt(m); String8 realFilename(base); String8 realFilename(base); realFilename.appendPath(q); realFilename.appendPath(q); write_update_file(realFilename, q); write_update_file(dataStream, q, realFilename); m++; m++; } } Loading Loading @@ -912,10 +985,14 @@ backup_helper_test_files() return errno; return errno; } } err = back_up_files(-1, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_before, 5); { BackupDataWriter dataStream(dataStreamFD); err = back_up_files(-1, &dataStream, newSnapshotFD, SCRATCH_DIR, files_before, 5); if (err != 0) { if (err != 0) { return err; return err; } } } close(dataStreamFD); close(dataStreamFD); close(newSnapshotFD); close(newSnapshotFD); Loading Loading @@ -968,10 +1045,15 @@ backup_helper_test_files() return errno; return errno; } } err = back_up_files(oldSnapshotFD, dataStreamFD, newSnapshotFD, SCRATCH_DIR, files_after, 6); { BackupDataWriter dataStream(dataStreamFD); err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, SCRATCH_DIR, files_after, 6); if (err != 0) { if (err != 0) { return err; return err; } } } close(oldSnapshotFD); close(oldSnapshotFD); close(dataStreamFD); close(dataStreamFD); Loading