Merge change 5162 into donut
* changes: Preserve file access mode when backing up / restoring files
This commit is contained in:
@@ -41,7 +41,43 @@ namespace android {
|
|||||||
#define MAGIC0 0x70616e53 // Snap
|
#define MAGIC0 0x70616e53 // Snap
|
||||||
#define MAGIC1 0x656c6946 // File
|
#define MAGIC1 0x656c6946 // File
|
||||||
|
|
||||||
#if 1 // TEST_BACKUP_HELPERS
|
/*
|
||||||
|
* File entity data format (v1):
|
||||||
|
*
|
||||||
|
* - 4-byte version number of the metadata, little endian (0x00000001 for v1)
|
||||||
|
* - 12 bytes of metadata
|
||||||
|
* - the file data itself
|
||||||
|
*
|
||||||
|
* i.e. a 16-byte metadata header followed by the raw file data. If the
|
||||||
|
* restore code does not recognize the metadata version, it can still
|
||||||
|
* interpret the file data itself correctly.
|
||||||
|
*
|
||||||
|
* file_metadata_v1:
|
||||||
|
*
|
||||||
|
* - 4 byte version number === 0x00000001 (little endian)
|
||||||
|
* - 4-byte access mode (little-endian)
|
||||||
|
* - undefined (8 bytes)
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct file_metadata_v1 {
|
||||||
|
int version;
|
||||||
|
int mode;
|
||||||
|
int undefined_1;
|
||||||
|
int undefined_2;
|
||||||
|
};
|
||||||
|
|
||||||
|
const static int CURRENT_METADATA_VERSION = 1;
|
||||||
|
|
||||||
|
// auto-free buffer management object
|
||||||
|
class StAutoFree {
|
||||||
|
public:
|
||||||
|
StAutoFree(void* buffer) { mBuf = buffer; }
|
||||||
|
~StAutoFree() { free(mBuf); }
|
||||||
|
private:
|
||||||
|
void* mBuf;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if 0 // TEST_BACKUP_HELPERS
|
||||||
#define LOGP(f, x...) printf(f "\n", x)
|
#define LOGP(f, x...) printf(f "\n", x)
|
||||||
#else
|
#else
|
||||||
#define LOGP(x...) LOGD(x)
|
#define LOGP(x...) LOGD(x)
|
||||||
@@ -181,29 +217,48 @@ write_delete_file(BackupDataWriter* dataStream, const String8& key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
|
write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
|
||||||
char const* realFilename)
|
char const* realFilename)
|
||||||
{
|
{
|
||||||
LOGP("write_update_file %s (%s)\n", realFilename, key.string());
|
LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
|
||||||
|
|
||||||
const int bufsize = 4*1024;
|
const int bufsize = 4*1024;
|
||||||
int err;
|
int err;
|
||||||
int amt;
|
int amt;
|
||||||
int fileSize;
|
int fileSize;
|
||||||
int bytesLeft;
|
int bytesLeft;
|
||||||
|
file_metadata_v1 metadata;
|
||||||
|
|
||||||
char* buf = (char*)malloc(bufsize);
|
char* buf = (char*)malloc(bufsize);
|
||||||
|
StAutoFree _autoFree(buf);
|
||||||
|
|
||||||
int crc = crc32(0L, Z_NULL, 0);
|
int crc = crc32(0L, Z_NULL, 0);
|
||||||
|
|
||||||
|
|
||||||
bytesLeft = fileSize = lseek(fd, 0, SEEK_END);
|
fileSize = lseek(fd, 0, SEEK_END);
|
||||||
lseek(fd, 0, SEEK_SET);
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
|
||||||
|
if (sizeof(metadata) != 16) {
|
||||||
|
LOGE("ERROR: metadata block is the wrong size!");
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesLeft = fileSize + sizeof(metadata);
|
||||||
err = dataStream->WriteEntityHeader(key, bytesLeft);
|
err = dataStream->WriteEntityHeader(key, bytesLeft);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// store the file metadata first
|
||||||
|
metadata.version = tolel(CURRENT_METADATA_VERSION);
|
||||||
|
metadata.mode = tolel(mode);
|
||||||
|
metadata.undefined_1 = metadata.undefined_2 = 0;
|
||||||
|
err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
|
||||||
|
if (err != 0) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
|
||||||
|
|
||||||
|
// now store the file content
|
||||||
while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
|
while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
|
||||||
bytesLeft -= amt;
|
bytesLeft -= amt;
|
||||||
if (bytesLeft < 0) {
|
if (bytesLeft < 0) {
|
||||||
@@ -232,8 +287,6 @@ write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
|
|||||||
" You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
|
" You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,11 +294,19 @@ static int
|
|||||||
write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
|
write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
err = stat(realFilename, &st);
|
||||||
|
if (err < 0) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
int fd = open(realFilename, O_RDONLY);
|
int fd = open(realFilename, O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
err = write_update_file(dataStream, fd, key, realFilename);
|
|
||||||
|
err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
|
||||||
close(fd);
|
close(fd);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -257,6 +318,8 @@ compute_crc32(int fd)
|
|||||||
int amt;
|
int amt;
|
||||||
|
|
||||||
char* buf = (char*)malloc(bufsize);
|
char* buf = (char*)malloc(bufsize);
|
||||||
|
StAutoFree _autoFree(buf);
|
||||||
|
|
||||||
int crc = crc32(0L, Z_NULL, 0);
|
int crc = crc32(0L, Z_NULL, 0);
|
||||||
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
lseek(fd, 0, SEEK_SET);
|
||||||
@@ -265,8 +328,6 @@ compute_crc32(int fd)
|
|||||||
crc = crc32(crc, (Bytef*)buf, amt);
|
crc = crc32(crc, (Bytef*)buf, amt);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,7 +417,7 @@ back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD
|
|||||||
g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
|
g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
|
||||||
if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
|
if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
|
||||||
|| f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
|
|| f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
|
||||||
write_update_file(dataStream, fd, p, g.file.string());
|
write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
@@ -416,8 +477,22 @@ RestoreHelperBase::WriteFile(const String8& filename, BackupDataReader* in)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: World readable/writable for now.
|
// Get the metadata block off the head of the file entity and use that to
|
||||||
mode = 0666;
|
// set up the output file
|
||||||
|
file_metadata_v1 metadata;
|
||||||
|
amt = in->ReadEntityData(&metadata, sizeof(metadata));
|
||||||
|
if (amt != sizeof(metadata)) {
|
||||||
|
LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
|
||||||
|
(long)amt, strerror(errno));
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
metadata.version = fromlel(metadata.version);
|
||||||
|
metadata.mode = fromlel(metadata.mode);
|
||||||
|
if (metadata.version > CURRENT_METADATA_VERSION) {
|
||||||
|
LOGW("Restoring file with unsupported metadata version %d (currently %d)",
|
||||||
|
metadata.version, CURRENT_METADATA_VERSION);
|
||||||
|
}
|
||||||
|
mode = metadata.mode;
|
||||||
|
|
||||||
// Write the file and compute the crc
|
// Write the file and compute the crc
|
||||||
crc = crc32(0L, Z_NULL, 0);
|
crc = crc32(0L, Z_NULL, 0);
|
||||||
@@ -512,6 +587,7 @@ compare_file(const char* path, const unsigned char* data, int len)
|
|||||||
fprintf(stderr, "malloc(%d) failed\n", len);
|
fprintf(stderr, "malloc(%d) failed\n", len);
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
StAutoFree _autoFree(contents);
|
||||||
|
|
||||||
bool sizesMatch = true;
|
bool sizesMatch = true;
|
||||||
amt = lseek(fd, 0, SEEK_END);
|
amt = lseek(fd, 0, SEEK_END);
|
||||||
@@ -843,6 +919,7 @@ test_read_header_and_entity(BackupDataReader& reader, const char* str)
|
|||||||
int err;
|
int err;
|
||||||
int bufSize = strlen(str)+1;
|
int bufSize = strlen(str)+1;
|
||||||
char* buf = (char*)malloc(bufSize);
|
char* buf = (char*)malloc(bufSize);
|
||||||
|
StAutoFree _autoFree(buf);
|
||||||
String8 string;
|
String8 string;
|
||||||
int cookie = 0x11111111;
|
int cookie = 0x11111111;
|
||||||
size_t actualSize;
|
size_t actualSize;
|
||||||
@@ -904,7 +981,6 @@ finished:
|
|||||||
if (err != NO_ERROR) {
|
if (err != NO_ERROR) {
|
||||||
fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
|
fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
|
||||||
}
|
}
|
||||||
free(buf);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user