Index: delta_diff_generator.cc |
diff --git a/delta_diff_generator.cc b/delta_diff_generator.cc |
index 676629aa03658b7490bd2e9430245d64ae281a4d..9a5219df20de9dad746ee07f2546b9928343e4b1 100644 |
--- a/delta_diff_generator.cc |
+++ b/delta_diff_generator.cc |
@@ -6,6 +6,7 @@ |
#include <errno.h> |
#include <fcntl.h> |
+#include <inttypes.h> |
#include <sys/stat.h> |
#include <sys/types.h> |
@@ -47,9 +48,10 @@ namespace chromeos_update_engine { |
typedef DeltaDiffGenerator::Block Block; |
namespace { |
-const size_t kBlockSize = 4096; |
+const size_t kBlockSize = 4096; // bytes |
const size_t kRootFSPartitionSize = 1 * 1024 * 1024 * 1024; // 1 GiB |
const uint64_t kVersionNumber = 1; |
+const uint64_t kFullUpdateChunkSize = 128 * 1024; // bytes |
// Stores all Extents for a file into 'out'. Returns true on success. |
bool GatherExtents(const string& path, |
@@ -1119,6 +1121,82 @@ bool DeltaDiffGenerator::ConvertGraphToDag(Graph* graph, |
return true; |
} |
+bool DeltaDiffGenerator::ReadFullUpdateFromDisk( |
+ Graph* graph, |
+ const std::string& new_kernel_part, |
+ const std::string& new_image, |
+ int fd, |
+ off_t* data_file_size, |
+ off_t chunk_size, |
+ vector<DeltaArchiveManifest_InstallOperation>* kernel_ops, |
+ std::vector<Vertex::Index>* final_order) { |
+ TEST_AND_RETURN_FALSE(chunk_size > 0); |
+ TEST_AND_RETURN_FALSE((chunk_size % kBlockSize) == 0); |
+ |
+ // Get the sizes early in the function, so we can fail fast if the user |
+ // passed us bad paths. |
+ const off_t image_size = utils::FileSize(new_image); |
+ TEST_AND_RETURN_FALSE(image_size >= 0); |
+ const off_t kernel_size = utils::FileSize(new_kernel_part); |
+ TEST_AND_RETURN_FALSE(kernel_size >= 0); |
+ |
+ off_t part_sizes[] = { image_size, kernel_size }; |
+ string paths[] = { new_image, new_kernel_part }; |
+ |
+ for (int partition = 0; partition < 2; ++partition) { |
+ const string& path = paths[partition]; |
+ LOG(INFO) << "compressing " << path; |
+ |
+ int in_fd = open(path.c_str(), O_RDONLY, 0); |
+ TEST_AND_RETURN_FALSE(in_fd >= 0); |
+ ScopedFdCloser in_fd_closer(&in_fd); |
+ |
+ for (off_t bytes_left = part_sizes[partition], counter = 0, offset = 0; |
+ bytes_left > 0; |
+ bytes_left -= chunk_size, ++counter, offset += chunk_size) { |
+ LOG(INFO) << "offset = " << offset; |
+ DeltaArchiveManifest_InstallOperation* op = NULL; |
+ if (partition == 0) { |
+ graph->resize(graph->size() + 1); |
+ graph->back().file_name = path + StringPrintf("-%" PRIi64, counter); |
+ op = &graph->back().op; |
+ final_order->push_back(graph->size() - 1); |
+ } else { |
+ kernel_ops->resize(kernel_ops->size() + 1); |
+ op = &kernel_ops->back(); |
+ } |
+ LOG(INFO) << "have an op"; |
+ |
+ vector<char> buf(min(bytes_left, chunk_size)); |
+ LOG(INFO) << "buf size: " << buf.size(); |
+ ssize_t bytes_read = -1; |
+ |
+ TEST_AND_RETURN_FALSE(utils::PReadAll( |
+ in_fd, &buf[0], buf.size(), offset, &bytes_read)); |
+ TEST_AND_RETURN_FALSE(bytes_read == static_cast<ssize_t>(buf.size())); |
+ |
+ vector<char> buf_compressed; |
+ |
+ TEST_AND_RETURN_FALSE(BzipCompress(buf, &buf_compressed)); |
+ const bool compress = buf_compressed.size() < buf.size(); |
+ const vector<char>& use_buf = compress ? buf_compressed : buf; |
+ if (compress) { |
+ op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ); |
+ } else { |
+ op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE); |
+ } |
+ op->set_data_offset(*data_file_size); |
+ *data_file_size += use_buf.size(); |
+ op->set_data_length(use_buf.size()); |
+ Extent* dst_extent = op->add_dst_extents(); |
+ dst_extent->set_start_block(offset / kBlockSize); |
+ dst_extent->set_num_blocks(chunk_size / kBlockSize); |
+ } |
+ } |
+ |
+ return true; |
+} |
+ |
bool DeltaDiffGenerator::GenerateDeltaUpdateFile( |
const string& old_root, |
const string& old_image, |
@@ -1129,18 +1207,23 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile( |
const string& output_path, |
const string& private_key_path) { |
struct stat old_image_stbuf; |
- TEST_AND_RETURN_FALSE_ERRNO(stat(old_image.c_str(), &old_image_stbuf) == 0); |
struct stat new_image_stbuf; |
TEST_AND_RETURN_FALSE_ERRNO(stat(new_image.c_str(), &new_image_stbuf) == 0); |
- LOG_IF(WARNING, new_image_stbuf.st_size != old_image_stbuf.st_size) |
- << "Old and new images are different sizes."; |
+ if (!old_image.empty()) { |
+ TEST_AND_RETURN_FALSE_ERRNO(stat(old_image.c_str(), &old_image_stbuf) == 0); |
+ LOG_IF(WARNING, new_image_stbuf.st_size != old_image_stbuf.st_size) |
+ << "Old and new images are different sizes."; |
+ LOG_IF(FATAL, old_image_stbuf.st_size % kBlockSize) |
+ << "Old image not a multiple of block size " << kBlockSize; |
+ // Sanity check kernel partition arg |
+ TEST_AND_RETURN_FALSE(utils::FileSize(old_kernel_part) >= 0); |
+ } else { |
+ old_image_stbuf.st_size = 0; |
+ } |
LOG_IF(FATAL, new_image_stbuf.st_size % kBlockSize) |
<< "New image not a multiple of block size " << kBlockSize; |
- LOG_IF(FATAL, old_image_stbuf.st_size % kBlockSize) |
- << "Old image not a multiple of block size " << kBlockSize; |
- // Sanity check kernel partition args |
- TEST_AND_RETURN_FALSE(utils::FileSize(old_kernel_part) >= 0); |
+ // Sanity check kernel partition arg |
TEST_AND_RETURN_FALSE(utils::FileSize(new_kernel_part) >= 0); |
vector<Block> blocks(max(old_image_stbuf.st_size / kBlockSize, |
@@ -1163,7 +1246,8 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile( |
vector<DeltaArchiveManifest_InstallOperation> kernel_ops; |
vector<Vertex::Index> final_order; |
- { |
+ if (!old_image.empty()) { |
+ // Delta update |
int fd; |
TEST_AND_RETURN_FALSE( |
utils::MakeTempFile(kTempFileTemplate, &temp_file_path, &fd)); |
@@ -1206,6 +1290,17 @@ bool DeltaDiffGenerator::GenerateDeltaUpdateFile( |
fd, |
&data_file_size, |
&final_order)); |
+ } else { |
+ // Full update |
+ int fd = 0; |
+ TEST_AND_RETURN_FALSE(ReadFullUpdateFromDisk(&graph, |
+ new_kernel_part, |
+ new_image, |
+ fd, |
+ &data_file_size, |
+ kFullUpdateChunkSize, |
+ &kernel_ops, |
+ &final_order)); |
} |
// Convert to protobuf Manifest object |