Index: src/platform/update_engine/delta_performer.cc |
diff --git a/src/platform/update_engine/delta_performer.cc b/src/platform/update_engine/delta_performer.cc |
index 765fc1e923da153136ab9763f5c7211ef83e6d06..1f8d8e428f53f84d5d848ab73d461d5f7743da91 100644 |
--- a/src/platform/update_engine/delta_performer.cc |
+++ b/src/platform/update_engine/delta_performer.cc |
@@ -59,12 +59,18 @@ string ExtentsToString(const RepeatedPtrField<Extent>& extents) { |
// LOGs a DeltaArchiveManifest object. Useful for debugging. |
void DumpUpdateProto(const DeltaArchiveManifest& manifest) { |
LOG(INFO) << "Update Proto:"; |
- LOG(INFO) << " src_checksum: " << manifest.src_checksum(); |
- LOG(INFO) << " dst_checksum: " << manifest.dst_checksum(); |
LOG(INFO) << " block_size: " << manifest.block_size(); |
- for (int i = 0; i < manifest.install_operations_size(); i++) { |
+ for (int i = 0; i < (manifest.install_operations_size() + |
+ manifest.kernel_install_operations_size()); i++) { |
const DeltaArchiveManifest_InstallOperation& op = |
- manifest.install_operations(i); |
+ i < manifest.install_operations_size() ? |
+ manifest.install_operations(i) : |
+ manifest.kernel_install_operations( |
+ i - manifest.install_operations_size()); |
+ if (i == 0) |
+ LOG(INFO) << " Rootfs ops:"; |
+ else if (i == manifest.install_operations_size()) |
+ LOG(INFO) << " Kernel ops:"; |
LOG(INFO) << " operation(" << i << ")"; |
LOG(INFO) << " type: " |
<< DeltaArchiveManifest_InstallOperation_Type_Name(op.type()); |
@@ -80,18 +86,40 @@ void DumpUpdateProto(const DeltaArchiveManifest& manifest) { |
LOG(INFO) << " dst_length: " << op.dst_length(); |
} |
} |
+ |
+// Opens path for read/write, put the fd into *fd. On success returns true |
+// and sets *err to 0. On failure, returns false and sets *err to errno. |
+bool OpenFile(const char* path, int* fd, int* err) { |
+ if (*fd != -1) { |
+ LOG(ERROR) << "Can't open(" << path << "), *fd != -1 (it's " << *fd << ")"; |
+ *err = EINVAL; |
+ return false; |
+ } |
+ *fd = open(path, O_RDWR, 000); |
+ if (*fd < 0) { |
+ *err = errno; |
+ PLOG(ERROR) << "Unable to open file " << path; |
+ return false; |
+ } |
+ *err = 0; |
+ return true; |
+} |
+ |
} // namespace {} |
int DeltaPerformer::Open(const char* path, int flags, mode_t mode) { |
- if (fd_ != -1) { |
- LOG(ERROR) << "Can't Open(), fd_ != -1 (it's " << fd_ << ")"; |
- return -EINVAL; |
- } |
- path_ = path; |
- fd_ = open(path, O_RDWR, 000); |
- if (fd_ < 0) |
- return -errno; |
- return 0; |
+ int err; |
+ if (OpenFile(path, &fd_, &err)) |
+ path_ = path; |
+ return -err; |
+} |
+ |
+bool DeltaPerformer::OpenKernel(const char* kernel_path) { |
+ int err; |
+ bool success = OpenFile(kernel_path, &kernel_fd_, &err); |
+ if (success) |
+ kernel_path_ = kernel_path; |
+ return success; |
} |
int DeltaPerformer::Close() { |
@@ -99,11 +127,18 @@ int DeltaPerformer::Close() { |
LOG(ERROR) << "Called Close() while buffer not empty!"; |
return -1; |
} |
- if (close(fd_) == -1) |
- return -errno; |
+ int err = 0; |
+ if (close(kernel_fd_) == -1) { |
+ err = errno; |
+ PLOG(ERROR) << "Unable to close kernel fd:"; |
+ } |
+ if (close(fd_) == -1) { |
+ err = errno; |
+ PLOG(ERROR) << "Unable to close rootfs fd:"; |
+ } |
fd_ = -2; // Set so that isn't not valid AND calls to Open() will fail. |
path_ = ""; |
- return 0; |
+ return -err; |
} |
// Wrapper around write. Returns bytes written on success or |
@@ -148,29 +183,39 @@ ssize_t DeltaPerformer::Write(const void* bytes, size_t count) { |
manifest_valid_ = true; |
block_size_ = manifest_.block_size(); |
} |
- while (next_operation_ < manifest_.install_operations_size() && |
- CanPerformInstallOperation( |
- manifest_.install_operations(next_operation_))) { |
+ ssize_t total_operations = manifest_.install_operations_size() + |
+ manifest_.kernel_install_operations_size(); |
+ while (next_operation_num_ < total_operations) { |
const DeltaArchiveManifest_InstallOperation &op = |
- manifest_.install_operations(next_operation_); |
+ next_operation_num_ < manifest_.install_operations_size() ? |
+ manifest_.install_operations(next_operation_num_) : |
+ manifest_.kernel_install_operations( |
+ next_operation_num_ - manifest_.install_operations_size()); |
+ if (!CanPerformInstallOperation(op)) |
+ break; |
+ bool is_kernel_partition = |
+ (next_operation_num_ >= manifest_.install_operations_size()); |
if (op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE || |
op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) { |
- if (!PerformReplaceOperation(op)) { |
- LOG(ERROR) << "Failed to perform replace operation " << next_operation_; |
+ if (!PerformReplaceOperation(op, is_kernel_partition)) { |
+ LOG(ERROR) << "Failed to perform replace operation " |
+ << next_operation_num_; |
return -EINVAL; |
} |
} else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE) { |
- if (!PerformMoveOperation(op)) { |
- LOG(ERROR) << "Failed to perform move operation " << next_operation_; |
+ if (!PerformMoveOperation(op, is_kernel_partition)) { |
+ LOG(ERROR) << "Failed to perform move operation " |
+ << next_operation_num_; |
return -EINVAL; |
} |
} else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_BSDIFF) { |
- if (!PerformBsdiffOperation(op)) { |
- LOG(ERROR) << "Failed to perform bsdiff operation " << next_operation_; |
+ if (!PerformBsdiffOperation(op, is_kernel_partition)) { |
+ LOG(ERROR) << "Failed to perform bsdiff operation " |
+ << next_operation_num_; |
return -EINVAL; |
} |
} |
- next_operation_++; |
+ next_operation_num_++; |
} |
return count; |
} |
@@ -194,7 +239,8 @@ bool DeltaPerformer::CanPerformInstallOperation( |
} |
bool DeltaPerformer::PerformReplaceOperation( |
- const DeltaArchiveManifest_InstallOperation& operation) { |
+ const DeltaArchiveManifest_InstallOperation& operation, |
+ bool is_kernel_partition) { |
CHECK(operation.type() == \ |
DeltaArchiveManifest_InstallOperation_Type_REPLACE || \ |
operation.type() == \ |
@@ -228,7 +274,9 @@ bool DeltaPerformer::PerformReplaceOperation( |
extents.push_back(operation.dst_extents(i)); |
} |
- TEST_AND_RETURN_FALSE(writer->Init(fd_, extents, block_size_)); |
+ int fd = is_kernel_partition ? kernel_fd_ : fd_; |
+ |
+ TEST_AND_RETURN_FALSE(writer->Init(fd, extents, block_size_)); |
TEST_AND_RETURN_FALSE(writer->Write(&buffer_[0], operation.data_length())); |
TEST_AND_RETURN_FALSE(writer->End()); |
@@ -239,7 +287,8 @@ bool DeltaPerformer::PerformReplaceOperation( |
} |
bool DeltaPerformer::PerformMoveOperation( |
- const DeltaArchiveManifest_InstallOperation& operation) { |
+ const DeltaArchiveManifest_InstallOperation& operation, |
+ bool is_kernel_partition) { |
// Calculate buffer size. Note, this function doesn't do a sliding |
// window to copy in case the source and destination blocks overlap. |
// If we wanted to do a sliding window, we could program the server |
@@ -255,13 +304,15 @@ bool DeltaPerformer::PerformMoveOperation( |
DCHECK_EQ(blocks_to_write, blocks_to_read); |
vector<char> buf(blocks_to_write * block_size_); |
- |
+ |
+ int fd = is_kernel_partition ? kernel_fd_ : fd_; |
+ |
// Read in bytes. |
ssize_t bytes_read = 0; |
for (int i = 0; i < operation.src_extents_size(); i++) { |
ssize_t bytes_read_this_iteration = 0; |
const Extent& extent = operation.src_extents(i); |
- TEST_AND_RETURN_FALSE(utils::PReadAll(fd_, |
+ TEST_AND_RETURN_FALSE(utils::PReadAll(fd, |
&buf[bytes_read], |
extent.num_blocks() * block_size_, |
extent.start_block() * block_size_, |
@@ -276,7 +327,7 @@ bool DeltaPerformer::PerformMoveOperation( |
ssize_t bytes_written = 0; |
for (int i = 0; i < operation.dst_extents_size(); i++) { |
const Extent& extent = operation.dst_extents(i); |
- TEST_AND_RETURN_FALSE(utils::PWriteAll(fd_, |
+ TEST_AND_RETURN_FALSE(utils::PWriteAll(fd, |
&buf[bytes_written], |
extent.num_blocks() * block_size_, |
extent.start_block() * block_size_)); |
@@ -314,7 +365,8 @@ bool DeltaPerformer::ExtentsToBsdiffPositionsString( |
} |
bool DeltaPerformer::PerformBsdiffOperation( |
- const DeltaArchiveManifest_InstallOperation& operation) { |
+ const DeltaArchiveManifest_InstallOperation& operation, |
+ bool is_kernel_partition) { |
// Since we delete data off the beginning of the buffer as we use it, |
// the data we need should be exactly at the beginning of the buffer. |
CHECK_EQ(buffer_offset_, operation.data_offset()); |
@@ -342,10 +394,14 @@ bool DeltaPerformer::PerformBsdiffOperation( |
TEST_AND_RETURN_FALSE( |
utils::WriteAll(fd, &buffer_[0], operation.data_length())); |
} |
+ |
+ int fd = is_kernel_partition ? kernel_fd_ : fd_; |
+ const string& path = is_kernel_partition ? kernel_path_ : path_; |
+ |
vector<string> cmd; |
cmd.push_back(kBspatchPath); |
- cmd.push_back(path_); |
- cmd.push_back(path_); |
+ cmd.push_back(path); |
+ cmd.push_back(path); |
cmd.push_back(temp_filename); |
cmd.push_back(input_positions); |
cmd.push_back(output_positions); |
@@ -364,7 +420,7 @@ bool DeltaPerformer::PerformBsdiffOperation( |
end_byte - (block_size_ - operation.dst_length() % block_size_); |
vector<char> zeros(end_byte - begin_byte); |
TEST_AND_RETURN_FALSE( |
- utils::PWriteAll(fd_, &zeros[0], end_byte - begin_byte, begin_byte)); |
+ utils::PWriteAll(fd, &zeros[0], end_byte - begin_byte, begin_byte)); |
} |
// Update buffer. |