Merge "applypatch: Use unique_fd to avoid leaking FDs."

This commit is contained in:
Tao Bao 2016-11-18 02:02:42 +00:00 committed by Gerrit Code Review
commit 2e5cf3c0bc
2 changed files with 288 additions and 290 deletions

View file

@ -194,17 +194,16 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file
// Save the contents of the given FileContents object under the given
// filename. Return 0 on success.
int SaveFileContents(const char* filename, const FileContents* file) {
int fd = ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR);
if (fd < 0) {
unique_fd fd(ota_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR));
if (fd == -1) {
printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno));
return -1;
}
ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd);
if (bytes_written != static_cast<ssize_t>(file->data.size())) {
printf("short write of \"%s\" (%zd bytes of %zu) (%s)\n",
filename, bytes_written, file->data.size(), strerror(errno));
ota_close(fd);
printf("short write of \"%s\" (%zd bytes of %zu): %s\n", filename, bytes_written,
file->data.size(), strerror(errno));
return -1;
}
if (ota_fsync(fd) != 0) {
@ -232,24 +231,22 @@ int SaveFileContents(const char* filename, const FileContents* file) {
// "EMMC:<partition_device>[:...]". The target name
// might contain multiple colons, but WriteToPartition() only uses the first
// two and ignores the rest. Return 0 on success.
int WriteToPartition(const unsigned char* data, size_t len, const char* target) {
std::vector<std::string> pieces = android::base::Split(std::string(target), ":");
int WriteToPartition(const unsigned char* data, size_t len, const std::string& target) {
std::vector<std::string> pieces = android::base::Split(target, ":");
if (pieces.size() < 2 || pieces[0] != "EMMC") {
printf("WriteToPartition called with bad target (%s)\n", target);
printf("WriteToPartition called with bad target (%s)\n", target.c_str());
return -1;
}
const char* partition = pieces[1].c_str();
size_t start = 0;
bool success = false;
int fd = ota_open(partition, O_RDWR | O_SYNC);
if (fd < 0) {
unique_fd fd(ota_open(partition, O_RDWR));
if (fd == -1) {
printf("failed to open %s: %s\n", partition, strerror(errno));
return -1;
}
size_t start = 0;
bool success = false;
for (size_t attempt = 0; attempt < 2; ++attempt) {
if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) {
printf("failed seek on %s: %s\n", partition, strerror(errno));
@ -268,23 +265,23 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target)
}
if (ota_fsync(fd) != 0) {
printf("failed to sync to %s (%s)\n", partition, strerror(errno));
printf("failed to sync to %s: %s\n", partition, strerror(errno));
return -1;
}
if (ota_close(fd) != 0) {
printf("failed to close %s (%s)\n", partition, strerror(errno));
printf("failed to close %s: %s\n", partition, strerror(errno));
return -1;
}
fd = ota_open(partition, O_RDONLY);
if (fd < 0) {
printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno));
fd.reset(ota_open(partition, O_RDONLY));
if (fd == -1) {
printf("failed to reopen %s for verify: %s\n", partition, strerror(errno));
return -1;
}
// Drop caches so our subsequent verification read won't just be reading the cache.
sync();
int dc = ota_open("/proc/sys/vm/drop_caches", O_WRONLY);
unique_fd dc(ota_open("/proc/sys/vm/drop_caches", O_WRONLY));
if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) {
printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno));
} else {
@ -293,7 +290,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target)
ota_close(dc);
sleep(1);
// verify
// Verify.
if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) {
printf("failed to seek back to beginning of %s: %s\n", partition, strerror(errno));
return -1;
@ -318,8 +315,7 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target)
return -1;
}
if (static_cast<size_t>(read_count) < to_read) {
printf("short verify read %s at %zu: %zd %zu %s\n", partition, p, read_count, to_read,
strerror(errno));
printf("short verify read %s at %zu: %zd %zu\n", partition, p, read_count, to_read);
}
so_far += read_count;
}
@ -343,8 +339,8 @@ int WriteToPartition(const unsigned char* data, size_t len, const char* target)
return -1;
}
if (ota_close(fd) != 0) {
printf("error closing %s (%s)\n", partition, strerror(errno));
if (ota_close(fd) == -1) {
printf("error closing %s: %s\n", partition, strerror(errno));
return -1;
}
sync();
@ -595,7 +591,6 @@ int applypatch_flash(const char* source_filename, const char* target_filename,
}
std::string target_str(target_filename);
std::vector<std::string> pieces = android::base::Split(target_str, ":");
if (pieces.size() != 2 || pieces[0] != "EMMC") {
printf("invalid target name \"%s\"", target_filename);
@ -641,15 +636,6 @@ static int GenerateTarget(FileContents* source_file,
const uint8_t target_sha1[SHA_DIGEST_LENGTH],
size_t target_size,
const Value* bonus_data) {
int retry = 1;
SHA_CTX ctx;
std::string memory_sink_str;
FileContents* source_to_use;
int made_copy = 0;
bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0);
const std::string tmp_target_filename = std::string(target_filename) + ".patch";
// assume that target_filename (eg "/system/app/Foo.apk") is located
// on the same filesystem as its top-level directory ("/system").
// We need something that exists for calling statfs().
@ -659,18 +645,21 @@ static int GenerateTarget(FileContents* source_file,
target_fs.resize(slash_pos);
}
FileContents* source_to_use;
const Value* patch;
if (source_patch_value != NULL) {
if (source_patch_value != nullptr) {
source_to_use = source_file;
patch = source_patch_value;
} else {
source_to_use = copy_file;
patch = copy_patch_value;
}
if (patch->type != VAL_BLOB) {
printf("patch is not a blob\n");
return 1;
}
const char* header = &patch->data[0];
size_t header_bytes_read = patch->data.size();
bool use_bsdiff = false;
@ -683,9 +672,15 @@ static int GenerateTarget(FileContents* source_file,
return 1;
}
bool target_is_partition = (strncmp(target_filename, "EMMC:", 5) == 0);
const std::string tmp_target_filename = std::string(target_filename) + ".patch";
int retry = 1;
bool made_copy = false;
SHA_CTX ctx;
std::string memory_sink_str; // Don't need to reserve space.
do {
// Is there enough room in the target filesystem to hold the patched
// file?
// Is there enough room in the target filesystem to hold the patched file?
if (target_is_partition) {
// If the target is a partition, we're actually going to
@ -704,18 +699,17 @@ static int GenerateTarget(FileContents* source_file,
printf("failed to back up source file\n");
return 1;
}
made_copy = 1;
made_copy = true;
retry = 0;
} else {
int enough_space = 0;
bool enough_space = false;
if (retry > 0) {
size_t free_space = FreeSpaceForFile(target_fs.c_str());
enough_space =
(free_space > (256 << 10)) && // 256k (two-block) minimum
enough_space = (free_space > (256 << 10)) && // 256k (two-block) minimum
(free_space > (target_size * 3 / 2)); // 50% margin of error
if (!enough_space) {
printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n",
target_size, free_space, retry, enough_space);
printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n", target_size,
free_space, retry, enough_space);
}
}
@ -723,7 +717,7 @@ static int GenerateTarget(FileContents* source_file,
retry = 0;
}
if (!enough_space && source_patch_value != NULL) {
if (!enough_space && source_patch_value != nullptr) {
// Using the original source, but not enough free space. First
// copy the source file to cache, then delete it from the original
// location.
@ -745,7 +739,7 @@ static int GenerateTarget(FileContents* source_file,
printf("failed to back up source file\n");
return 1;
}
made_copy = 1;
made_copy = true;
unlink(source_filename);
size_t free_space = FreeSpaceForFile(target_fs.c_str());
@ -753,48 +747,43 @@ static int GenerateTarget(FileContents* source_file,
}
}
SinkFn sink = NULL;
void* token = NULL;
int output_fd = -1;
SinkFn sink = nullptr;
void* token = nullptr;
unique_fd output_fd;
if (target_is_partition) {
// We store the decoded output in memory.
sink = MemorySink;
token = &memory_sink_str;
} else {
// We write the decoded output to "<tgt-file>.patch".
output_fd = ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
S_IRUSR | S_IWUSR);
if (output_fd < 0) {
printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(),
strerror(errno));
output_fd.reset(ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
S_IRUSR | S_IWUSR));
if (output_fd == -1) {
printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(), strerror(errno));
return 1;
}
sink = FileSink;
token = &output_fd;
}
SHA1_Init(&ctx);
int result;
if (use_bsdiff) {
result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(),
patch, 0, sink, token, &ctx);
result = ApplyBSDiffPatch(source_to_use->data.data(), source_to_use->data.size(), patch, 0,
sink, token, &ctx);
} else {
result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(),
patch, sink, token, &ctx, bonus_data);
result = ApplyImagePatch(source_to_use->data.data(), source_to_use->data.size(), patch, sink,
token, &ctx, bonus_data);
}
if (!target_is_partition) {
if (ota_fsync(output_fd) != 0) {
printf("failed to fsync file \"%s\" (%s)\n", tmp_target_filename.c_str(),
strerror(errno));
printf("failed to fsync file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno));
result = 1;
}
if (ota_close(output_fd) != 0) {
printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(),
strerror(errno));
printf("failed to close file \"%s\": %s\n", tmp_target_filename.c_str(), strerror(errno));
result = 1;
}
}
@ -802,7 +791,7 @@ static int GenerateTarget(FileContents* source_file,
if (result != 0) {
if (retry == 0) {
printf("applying patch failed\n");
return result != 0;
return 1;
} else {
printf("applying patch failed; retrying\n");
}
@ -832,13 +821,13 @@ static int GenerateTarget(FileContents* source_file,
return 1;
}
} else {
// Give the .patch file the same owner, group, and mode of the
// original source file.
// Give the .patch file the same owner, group, and mode of the original source file.
if (chmod(tmp_target_filename.c_str(), source_to_use->st.st_mode) != 0) {
printf("chmod of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno));
return 1;
}
if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) {
if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid,
source_to_use->st.st_gid) != 0) {
printf("chown of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno));
return 1;
}
@ -850,8 +839,7 @@ static int GenerateTarget(FileContents* source_file,
}
}
// If this run of applypatch created the copy, and we're here, we
// can delete it.
// If this run of applypatch created the copy, and we're here, we can delete it.
if (made_copy) {
unlink(CACHE_TEMP_SOURCE);
}

View file

@ -26,6 +26,8 @@
#include <stdio.h>
#include <sys/stat.h>
#include <android-base/unique_fd.h>
#define OTAIO_CACHE_FNAME "/cache/saved.file"
void ota_set_fault_files();
@ -50,4 +52,12 @@ ssize_t ota_write(int fd, const void* buf, size_t nbyte);
int ota_fsync(int fd);
struct OtaCloser {
static void Close(int fd) {
ota_close(fd);
}
};
using unique_fd = android::base::unique_fd_impl<OtaCloser>;
#endif