Merge "applypatch: Use unique_fd to avoid leaking FDs." am: 2e5cf3c0bc
am: d2cd8b4d30
Change-Id: I57228be65dfc37f853c3902ad8c5f65c0e3f1018
This commit is contained in:
commit
776ea9b464
2 changed files with 288 additions and 290 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue