OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "update_engine/delta_diff_generator.h" | 5 #include "update_engine/delta_diff_generator.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <inttypes.h> |
9 #include <sys/stat.h> | 10 #include <sys/stat.h> |
10 #include <sys/types.h> | 11 #include <sys/types.h> |
11 | 12 |
12 #include <algorithm> | 13 #include <algorithm> |
13 #include <map> | 14 #include <map> |
14 #include <set> | 15 #include <set> |
15 #include <string> | 16 #include <string> |
16 #include <utility> | 17 #include <utility> |
17 #include <vector> | 18 #include <vector> |
18 | 19 |
(...skipping 21 matching lines...) Expand all Loading... |
40 using std::min; | 41 using std::min; |
41 using std::set; | 42 using std::set; |
42 using std::string; | 43 using std::string; |
43 using std::vector; | 44 using std::vector; |
44 | 45 |
45 namespace chromeos_update_engine { | 46 namespace chromeos_update_engine { |
46 | 47 |
47 typedef DeltaDiffGenerator::Block Block; | 48 typedef DeltaDiffGenerator::Block Block; |
48 | 49 |
49 namespace { | 50 namespace { |
50 const size_t kBlockSize = 4096; | 51 const size_t kBlockSize = 4096; // bytes |
51 const size_t kRootFSPartitionSize = 1 * 1024 * 1024 * 1024; // 1 GiB | 52 const size_t kRootFSPartitionSize = 1 * 1024 * 1024 * 1024; // 1 GiB |
52 const uint64_t kVersionNumber = 1; | 53 const uint64_t kVersionNumber = 1; |
| 54 const uint64_t kFullUpdateChunkSize = 128 * 1024; // bytes |
53 | 55 |
54 // Stores all Extents for a file into 'out'. Returns true on success. | 56 // Stores all Extents for a file into 'out'. Returns true on success. |
55 bool GatherExtents(const string& path, | 57 bool GatherExtents(const string& path, |
56 google::protobuf::RepeatedPtrField<Extent>* out) { | 58 google::protobuf::RepeatedPtrField<Extent>* out) { |
57 vector<Extent> extents; | 59 vector<Extent> extents; |
58 TEST_AND_RETURN_FALSE(extent_mapper::ExtentsForFileFibmap(path, &extents)); | 60 TEST_AND_RETURN_FALSE(extent_mapper::ExtentsForFileFibmap(path, &extents)); |
59 DeltaDiffGenerator::StoreExtents(extents, out); | 61 DeltaDiffGenerator::StoreExtents(extents, out); |
60 return true; | 62 return true; |
61 } | 63 } |
62 | 64 |
(...skipping 1049 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1112 final_order, | 1114 final_order, |
1113 &inverse_final_order, | 1115 &inverse_final_order, |
1114 cuts)); | 1116 cuts)); |
1115 LOG(INFO) << "Making sure all temp blocks have been allocated"; | 1117 LOG(INFO) << "Making sure all temp blocks have been allocated"; |
1116 graph_utils::DumpGraph(*graph); | 1118 graph_utils::DumpGraph(*graph); |
1117 CHECK(NoTempBlocksRemain(*graph)); | 1119 CHECK(NoTempBlocksRemain(*graph)); |
1118 LOG(INFO) << "done making sure all temp blocks are allocated"; | 1120 LOG(INFO) << "done making sure all temp blocks are allocated"; |
1119 return true; | 1121 return true; |
1120 } | 1122 } |
1121 | 1123 |
| 1124 bool DeltaDiffGenerator::ReadFullUpdateFromDisk( |
| 1125 Graph* graph, |
| 1126 const std::string& new_kernel_part, |
| 1127 const std::string& new_image, |
| 1128 int fd, |
| 1129 off_t* data_file_size, |
| 1130 off_t chunk_size, |
| 1131 vector<DeltaArchiveManifest_InstallOperation>* kernel_ops, |
| 1132 std::vector<Vertex::Index>* final_order) { |
| 1133 TEST_AND_RETURN_FALSE(chunk_size > 0); |
| 1134 TEST_AND_RETURN_FALSE((chunk_size % kBlockSize) == 0); |
| 1135 |
| 1136 // Get the sizes early in the function, so we can fail fast if the user |
| 1137 // passed us bad paths. |
| 1138 const off_t image_size = utils::FileSize(new_image); |
| 1139 TEST_AND_RETURN_FALSE(image_size >= 0); |
| 1140 const off_t kernel_size = utils::FileSize(new_kernel_part); |
| 1141 TEST_AND_RETURN_FALSE(kernel_size >= 0); |
| 1142 |
| 1143 off_t part_sizes[] = { image_size, kernel_size }; |
| 1144 string paths[] = { new_image, new_kernel_part }; |
| 1145 |
| 1146 for (int partition = 0; partition < 2; ++partition) { |
| 1147 const string& path = paths[partition]; |
| 1148 LOG(INFO) << "compressing " << path; |
| 1149 |
| 1150 int in_fd = open(path.c_str(), O_RDONLY, 0); |
| 1151 TEST_AND_RETURN_FALSE(in_fd >= 0); |
| 1152 ScopedFdCloser in_fd_closer(&in_fd); |
| 1153 |
| 1154 for (off_t bytes_left = part_sizes[partition], counter = 0, offset = 0; |
| 1155 bytes_left > 0; |
| 1156 bytes_left -= chunk_size, ++counter, offset += chunk_size) { |
| 1157 LOG(INFO) << "offset = " << offset; |
| 1158 DeltaArchiveManifest_InstallOperation* op = NULL; |
| 1159 if (partition == 0) { |
| 1160 graph->resize(graph->size() + 1); |
| 1161 graph->back().file_name = path + StringPrintf("-%" PRIi64, counter); |
| 1162 op = &graph->back().op; |
| 1163 final_order->push_back(graph->size() - 1); |
| 1164 } else { |
| 1165 kernel_ops->resize(kernel_ops->size() + 1); |
| 1166 op = &kernel_ops->back(); |
| 1167 } |
| 1168 LOG(INFO) << "have an op"; |
| 1169 |
| 1170 vector<char> buf(min(bytes_left, chunk_size)); |
| 1171 LOG(INFO) << "buf size: " << buf.size(); |
| 1172 ssize_t bytes_read = -1; |
| 1173 |
| 1174 TEST_AND_RETURN_FALSE(utils::PReadAll( |
| 1175 in_fd, &buf[0], buf.size(), offset, &bytes_read)); |
| 1176 TEST_AND_RETURN_FALSE(bytes_read == static_cast<ssize_t>(buf.size())); |
| 1177 |
| 1178 vector<char> buf_compressed; |
| 1179 |
| 1180 TEST_AND_RETURN_FALSE(BzipCompress(buf, &buf_compressed)); |
| 1181 const bool compress = buf_compressed.size() < buf.size(); |
| 1182 const vector<char>& use_buf = compress ? buf_compressed : buf; |
| 1183 if (compress) { |
| 1184 op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ); |
| 1185 } else { |
| 1186 op->set_type(DeltaArchiveManifest_InstallOperation_Type_REPLACE); |
| 1187 } |
| 1188 op->set_data_offset(*data_file_size); |
| 1189 *data_file_size += use_buf.size(); |
| 1190 op->set_data_length(use_buf.size()); |
| 1191 Extent* dst_extent = op->add_dst_extents(); |
| 1192 dst_extent->set_start_block(offset / kBlockSize); |
| 1193 dst_extent->set_num_blocks(chunk_size / kBlockSize); |
| 1194 } |
| 1195 } |
| 1196 |
| 1197 return true; |
| 1198 } |
| 1199 |
1122 bool DeltaDiffGenerator::GenerateDeltaUpdateFile( | 1200 bool DeltaDiffGenerator::GenerateDeltaUpdateFile( |
1123 const string& old_root, | 1201 const string& old_root, |
1124 const string& old_image, | 1202 const string& old_image, |
1125 const string& new_root, | 1203 const string& new_root, |
1126 const string& new_image, | 1204 const string& new_image, |
1127 const string& old_kernel_part, | 1205 const string& old_kernel_part, |
1128 const string& new_kernel_part, | 1206 const string& new_kernel_part, |
1129 const string& output_path, | 1207 const string& output_path, |
1130 const string& private_key_path) { | 1208 const string& private_key_path) { |
1131 struct stat old_image_stbuf; | 1209 struct stat old_image_stbuf; |
1132 TEST_AND_RETURN_FALSE_ERRNO(stat(old_image.c_str(), &old_image_stbuf) == 0); | |
1133 struct stat new_image_stbuf; | 1210 struct stat new_image_stbuf; |
1134 TEST_AND_RETURN_FALSE_ERRNO(stat(new_image.c_str(), &new_image_stbuf) == 0); | 1211 TEST_AND_RETURN_FALSE_ERRNO(stat(new_image.c_str(), &new_image_stbuf) == 0); |
1135 LOG_IF(WARNING, new_image_stbuf.st_size != old_image_stbuf.st_size) | 1212 if (!old_image.empty()) { |
1136 << "Old and new images are different sizes."; | 1213 TEST_AND_RETURN_FALSE_ERRNO(stat(old_image.c_str(), &old_image_stbuf) == 0); |
| 1214 LOG_IF(WARNING, new_image_stbuf.st_size != old_image_stbuf.st_size) |
| 1215 << "Old and new images are different sizes."; |
| 1216 LOG_IF(FATAL, old_image_stbuf.st_size % kBlockSize) |
| 1217 << "Old image not a multiple of block size " << kBlockSize; |
| 1218 // Sanity check kernel partition arg |
| 1219 TEST_AND_RETURN_FALSE(utils::FileSize(old_kernel_part) >= 0); |
| 1220 } else { |
| 1221 old_image_stbuf.st_size = 0; |
| 1222 } |
1137 LOG_IF(FATAL, new_image_stbuf.st_size % kBlockSize) | 1223 LOG_IF(FATAL, new_image_stbuf.st_size % kBlockSize) |
1138 << "New image not a multiple of block size " << kBlockSize; | 1224 << "New image not a multiple of block size " << kBlockSize; |
1139 LOG_IF(FATAL, old_image_stbuf.st_size % kBlockSize) | |
1140 << "Old image not a multiple of block size " << kBlockSize; | |
1141 | 1225 |
1142 // Sanity check kernel partition args | 1226 // Sanity check kernel partition arg |
1143 TEST_AND_RETURN_FALSE(utils::FileSize(old_kernel_part) >= 0); | |
1144 TEST_AND_RETURN_FALSE(utils::FileSize(new_kernel_part) >= 0); | 1227 TEST_AND_RETURN_FALSE(utils::FileSize(new_kernel_part) >= 0); |
1145 | 1228 |
1146 vector<Block> blocks(max(old_image_stbuf.st_size / kBlockSize, | 1229 vector<Block> blocks(max(old_image_stbuf.st_size / kBlockSize, |
1147 new_image_stbuf.st_size / kBlockSize)); | 1230 new_image_stbuf.st_size / kBlockSize)); |
1148 LOG(INFO) << "invalid: " << Vertex::kInvalidIndex; | 1231 LOG(INFO) << "invalid: " << Vertex::kInvalidIndex; |
1149 LOG(INFO) << "len: " << blocks.size(); | 1232 LOG(INFO) << "len: " << blocks.size(); |
1150 for (vector<Block>::size_type i = 0; i < blocks.size(); i++) { | 1233 for (vector<Block>::size_type i = 0; i < blocks.size(); i++) { |
1151 CHECK(blocks[i].reader == Vertex::kInvalidIndex); | 1234 CHECK(blocks[i].reader == Vertex::kInvalidIndex); |
1152 CHECK(blocks[i].writer == Vertex::kInvalidIndex); | 1235 CHECK(blocks[i].writer == Vertex::kInvalidIndex); |
1153 } | 1236 } |
1154 Graph graph; | 1237 Graph graph; |
1155 CheckGraph(graph); | 1238 CheckGraph(graph); |
1156 | 1239 |
1157 const string kTempFileTemplate("/tmp/CrAU_temp_data.XXXXXX"); | 1240 const string kTempFileTemplate("/tmp/CrAU_temp_data.XXXXXX"); |
1158 string temp_file_path; | 1241 string temp_file_path; |
1159 off_t data_file_size = 0; | 1242 off_t data_file_size = 0; |
1160 | 1243 |
1161 LOG(INFO) << "Reading files..."; | 1244 LOG(INFO) << "Reading files..."; |
1162 | 1245 |
1163 vector<DeltaArchiveManifest_InstallOperation> kernel_ops; | 1246 vector<DeltaArchiveManifest_InstallOperation> kernel_ops; |
1164 | 1247 |
1165 vector<Vertex::Index> final_order; | 1248 vector<Vertex::Index> final_order; |
1166 { | 1249 if (!old_image.empty()) { |
| 1250 // Delta update |
1167 int fd; | 1251 int fd; |
1168 TEST_AND_RETURN_FALSE( | 1252 TEST_AND_RETURN_FALSE( |
1169 utils::MakeTempFile(kTempFileTemplate, &temp_file_path, &fd)); | 1253 utils::MakeTempFile(kTempFileTemplate, &temp_file_path, &fd)); |
1170 TEST_AND_RETURN_FALSE(fd >= 0); | 1254 TEST_AND_RETURN_FALSE(fd >= 0); |
1171 ScopedFdCloser fd_closer(&fd); | 1255 ScopedFdCloser fd_closer(&fd); |
1172 | 1256 |
1173 TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph, | 1257 TEST_AND_RETURN_FALSE(DeltaReadFiles(&graph, |
1174 &blocks, | 1258 &blocks, |
1175 old_root, | 1259 old_root, |
1176 new_root, | 1260 new_root, |
(...skipping 22 matching lines...) Expand all Loading... |
1199 LOG(INFO) << "Creating edges..."; | 1283 LOG(INFO) << "Creating edges..."; |
1200 CreateEdges(&graph, blocks); | 1284 CreateEdges(&graph, blocks); |
1201 LOG(INFO) << "Done creating edges"; | 1285 LOG(INFO) << "Done creating edges"; |
1202 CheckGraph(graph); | 1286 CheckGraph(graph); |
1203 | 1287 |
1204 TEST_AND_RETURN_FALSE(ConvertGraphToDag(&graph, | 1288 TEST_AND_RETURN_FALSE(ConvertGraphToDag(&graph, |
1205 new_root, | 1289 new_root, |
1206 fd, | 1290 fd, |
1207 &data_file_size, | 1291 &data_file_size, |
1208 &final_order)); | 1292 &final_order)); |
| 1293 } else { |
| 1294 // Full update |
| 1295 int fd = 0; |
| 1296 TEST_AND_RETURN_FALSE(ReadFullUpdateFromDisk(&graph, |
| 1297 new_kernel_part, |
| 1298 new_image, |
| 1299 fd, |
| 1300 &data_file_size, |
| 1301 kFullUpdateChunkSize, |
| 1302 &kernel_ops, |
| 1303 &final_order)); |
1209 } | 1304 } |
1210 | 1305 |
1211 // Convert to protobuf Manifest object | 1306 // Convert to protobuf Manifest object |
1212 DeltaArchiveManifest manifest; | 1307 DeltaArchiveManifest manifest; |
1213 CheckGraph(graph); | 1308 CheckGraph(graph); |
1214 InstallOperationsToManifest(graph, final_order, kernel_ops, &manifest); | 1309 InstallOperationsToManifest(graph, final_order, kernel_ops, &manifest); |
1215 | 1310 |
1216 CheckGraph(graph); | 1311 CheckGraph(graph); |
1217 manifest.set_block_size(kBlockSize); | 1312 manifest.set_block_size(kBlockSize); |
1218 | 1313 |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1350 | 1445 |
1351 LOG(INFO) << "All done. Successfully created delta file."; | 1446 LOG(INFO) << "All done. Successfully created delta file."; |
1352 return true; | 1447 return true; |
1353 } | 1448 } |
1354 | 1449 |
1355 const char* const kBsdiffPath = "/usr/bin/bsdiff"; | 1450 const char* const kBsdiffPath = "/usr/bin/bsdiff"; |
1356 const char* const kBspatchPath = "/usr/bin/bspatch"; | 1451 const char* const kBspatchPath = "/usr/bin/bspatch"; |
1357 const char* const kDeltaMagic = "CrAU"; | 1452 const char* const kDeltaMagic = "CrAU"; |
1358 | 1453 |
1359 }; // namespace chromeos_update_engine | 1454 }; // namespace chromeos_update_engine |
OLD | NEW |