| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium 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 #include <dirent.h> | 6 #include <dirent.h> |
| 7 #include <endian.h> | 7 #include <endian.h> |
| 8 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <stdio.h> | 9 #include <stdio.h> |
| 10 #include <unistd.h> | 10 #include <unistd.h> |
| 11 #include <algorithm> | 11 #include <algorithm> |
| 12 #include <map> |
| 13 #include <set> |
| 14 #include <string> |
| 12 #include <vector> | 15 #include <vector> |
| 13 #include <tr1/memory> | 16 #include <tr1/memory> |
| 14 #include <zlib.h> | 17 #include <zlib.h> |
| 15 #include "chromeos/obsolete_logging.h" | 18 #include "chromeos/obsolete_logging.h" |
| 16 #include "base/scoped_ptr.h" | 19 #include "base/scoped_ptr.h" |
| 17 #include "update_engine/delta_diff_parser.h" | 20 #include "update_engine/delta_diff_parser.h" |
| 18 #include "update_engine/gzip.h" | 21 #include "update_engine/gzip.h" |
| 19 #include "update_engine/subprocess.h" | 22 #include "update_engine/subprocess.h" |
| 20 #include "update_engine/utils.h" | 23 #include "update_engine/utils.h" |
| 21 | 24 |
| 25 using std::map; |
| 26 using std::set; |
| 27 using std::string; |
| 22 using std::vector; | 28 using std::vector; |
| 23 using std::tr1::shared_ptr; | 29 using std::tr1::shared_ptr; |
| 24 using chromeos_update_engine::DeltaArchiveManifest; | 30 using chromeos_update_engine::DeltaArchiveManifest; |
| 25 | 31 |
| 26 namespace chromeos_update_engine { | 32 namespace chromeos_update_engine { |
| 27 | 33 |
| 28 namespace { | 34 namespace { |
| 35 |
| 36 const char* kBsdiffPath = "/usr/bin/bsdiff"; |
| 37 |
| 29 // These structs and methods are helpers for EncodeDataToDeltaFile() | 38 // These structs and methods are helpers for EncodeDataToDeltaFile() |
| 30 | 39 |
| 31 // Before moving the data into a proto buffer, the data is stored in | 40 // Before moving the data into a proto buffer, the data is stored in |
| 32 // memory in these Node and Child structures. | 41 // memory in these Node and Child structures. |
| 33 | 42 |
| 34 // Each Node struct represents a file on disk (which can be regular file, | 43 // Each Node struct represents a file on disk (which can be regular file, |
| 35 // directory, fifo, socket, symlink, etc). Nodes that contain children | 44 // directory, fifo, socket, symlink, etc). Nodes that contain children |
| 36 // (just directories) will have a vector of Child objects. Each child | 45 // (just directories) will have a vector of Child objects. Each child |
| 37 // object has a filename and a pointer to the associated Node. Thus, | 46 // object has a filename and a pointer to the associated Node. Thus, |
| 38 // filenames for files are stored with their parents, not as part of | 47 // filenames for files are stored with their parents, not as part of |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 } | 202 } |
| 194 | 203 |
| 195 } // namespace {} | 204 } // namespace {} |
| 196 | 205 |
| 197 // For each file in archive, write a delta for it into out_file | 206 // For each file in archive, write a delta for it into out_file |
| 198 // and update 'file' to refer to the delta. | 207 // and update 'file' to refer to the delta. |
| 199 // This is a recursive function. Returns true on success. | 208 // This is a recursive function. Returns true on success. |
| 200 bool DeltaDiffGenerator::WriteFileDiffsToDeltaFile( | 209 bool DeltaDiffGenerator::WriteFileDiffsToDeltaFile( |
| 201 DeltaArchiveManifest* archive, | 210 DeltaArchiveManifest* archive, |
| 202 DeltaArchiveManifest_File* file, | 211 DeltaArchiveManifest_File* file, |
| 203 const std::string& file_name, | 212 const string& file_name, |
| 204 const std::string& old_path, | 213 const string& old_path, |
| 205 const std::string& new_path, | 214 const string& new_path, |
| 206 FileWriter* out_file_writer, | 215 FileWriter* out_file_writer, |
| 207 int* out_file_length, | 216 int* out_file_length, |
| 208 const std::string& force_compress_dev_path) { | 217 set<string> always_full_target_paths, |
| 218 const string& force_compress_dev_path) { |
| 209 TEST_AND_RETURN_FALSE(file->has_mode()); | 219 TEST_AND_RETURN_FALSE(file->has_mode()); |
| 210 | 220 |
| 211 // Stat the actual file, too | 221 // Stat the actual file, too |
| 212 struct stat stbuf; | 222 struct stat stbuf; |
| 213 TEST_AND_RETURN_FALSE_ERRNO(lstat((new_path + "/" + file_name).c_str(), | 223 TEST_AND_RETURN_FALSE_ERRNO(lstat((new_path + "/" + file_name).c_str(), |
| 214 &stbuf) == 0); | 224 &stbuf) == 0); |
| 215 TEST_AND_RETURN_FALSE(stbuf.st_mode == file->mode()); | 225 TEST_AND_RETURN_FALSE(stbuf.st_mode == file->mode()); |
| 216 | 226 |
| 217 // See if we're a directory or not | 227 // See if we're a directory or not |
| 218 if (S_ISDIR(file->mode())) { | 228 if (S_ISDIR(file->mode())) { |
| 219 for (int i = 0; i < file->children_size(); i++) { | 229 for (int i = 0; i < file->children_size(); i++) { |
| 220 DeltaArchiveManifest_File_Child* child = file->mutable_children(i); | 230 DeltaArchiveManifest_File_Child* child = file->mutable_children(i); |
| 221 DeltaArchiveManifest_File* child_file = | 231 DeltaArchiveManifest_File* child_file = |
| 222 archive->mutable_files(child->index()); | 232 archive->mutable_files(child->index()); |
| 233 string recurse_old_path = old_path; |
| 234 string recurse_new_path = new_path; |
| 235 if (!file_name.empty()) { |
| 236 recurse_new_path += "/" + file_name; |
| 237 recurse_old_path += "/" + file_name; |
| 238 } |
| 223 TEST_AND_RETURN_FALSE(WriteFileDiffsToDeltaFile( | 239 TEST_AND_RETURN_FALSE(WriteFileDiffsToDeltaFile( |
| 224 archive, | 240 archive, |
| 225 child_file, | 241 child_file, |
| 226 child->name(), | 242 child->name(), |
| 227 old_path + "/" + file_name, | 243 recurse_old_path, |
| 228 new_path + "/" + file_name, | 244 recurse_new_path, |
| 229 out_file_writer, | 245 out_file_writer, |
| 230 out_file_length, | 246 out_file_length, |
| 247 always_full_target_paths, |
| 231 force_compress_dev_path)); | 248 force_compress_dev_path)); |
| 232 } | 249 } |
| 233 return true; | 250 return true; |
| 234 } | 251 } |
| 235 | 252 |
| 236 if (S_ISFIFO(file->mode()) || S_ISSOCK(file->mode()) || | 253 if (S_ISFIFO(file->mode()) || S_ISSOCK(file->mode()) || |
| 237 file->has_hardlink_path()) { | 254 file->has_hardlink_path()) { |
| 238 // These don't store any additional data | 255 // These don't store any additional data |
| 239 return true; | 256 return true; |
| 240 } | 257 } |
| 241 | 258 |
| 242 vector<char> data; | 259 vector<char> data; |
| 243 bool should_compress = true; | 260 bool should_compress = true; |
| 244 bool format_set = false; | 261 bool format_set = false; |
| 245 DeltaArchiveManifest_File_DataFormat format; | 262 DeltaArchiveManifest_File_DataFormat format; |
| 246 if (S_ISLNK(file->mode())) { | 263 if (S_ISLNK(file->mode())) { |
| 247 TEST_AND_RETURN_FALSE(EncodeLink(new_path + "/" + file_name, &data)); | 264 TEST_AND_RETURN_FALSE(EncodeLink(new_path + "/" + file_name, &data)); |
| 248 } else if (S_ISCHR(file->mode()) || S_ISBLK(file->mode())) { | 265 } else if (S_ISCHR(file->mode()) || S_ISBLK(file->mode())) { |
| 249 TEST_AND_RETURN_FALSE(EncodeDev(stbuf, &data, &format, | 266 TEST_AND_RETURN_FALSE(EncodeDev(stbuf, &data, &format, |
| 250 new_path + "/" + file_name == | 267 new_path + "/" + file_name == |
| 251 force_compress_dev_path)); | 268 force_compress_dev_path)); |
| 252 format_set = true; | 269 format_set = true; |
| 253 } else if (S_ISREG(file->mode())) { | 270 } else if (S_ISREG(file->mode())) { |
| 254 // regular file. We may use a delta here. | 271 // regular file. We may use a delta here. |
| 255 TEST_AND_RETURN_FALSE(EncodeFile(old_path, new_path, file_name, &format, | 272 const bool avoid_diff = utils::SetContainsKey(always_full_target_paths, |
| 256 &data)); | 273 new_path + "/" + file_name); |
| 274 bool no_change = false; |
| 275 TEST_AND_RETURN_FALSE(EncodeFile(old_path, new_path, file_name, |
| 276 avoid_diff, &format, &data, &no_change)); |
| 277 if (no_change) { |
| 278 // No data change. We're done! |
| 279 return true; |
| 280 } |
| 257 should_compress = false; | 281 should_compress = false; |
| 258 format_set = true; | 282 format_set = true; |
| 259 if ((format == DeltaArchiveManifest_File_DataFormat_BSDIFF) || | 283 if ((format == DeltaArchiveManifest_File_DataFormat_BSDIFF) || |
| 260 (format == DeltaArchiveManifest_File_DataFormat_FULL_GZ)) | 284 (format == DeltaArchiveManifest_File_DataFormat_FULL_GZ)) |
| 261 TEST_AND_RETURN_FALSE(!data.empty()); | 285 TEST_AND_RETURN_FALSE(!data.empty()); |
| 262 } else { | 286 } else { |
| 263 // Should never get here; unhandled mode type. | 287 // Should never get here; unhandled mode type. |
| 264 LOG(ERROR) << "Unhandled mode type: " << file->mode(); | 288 LOG(ERROR) << "Unhandled mode type: " << file->mode(); |
| 265 return false; | 289 return false; |
| 266 } | 290 } |
| 267 | 291 |
| 268 if (!format_set) { | 292 if (!format_set) { |
| 269 // Pick a format now | 293 // Pick a format now |
| 270 vector<char> compressed_data; | 294 vector<char> compressed_data; |
| 271 TEST_AND_RETURN_FALSE(GzipCompress(data, &compressed_data)); | 295 TEST_AND_RETURN_FALSE(GzipCompress(data, &compressed_data)); |
| 272 if (compressed_data.size() < data.size()) { | 296 if (compressed_data.size() < data.size()) { |
| 273 format = DeltaArchiveManifest_File_DataFormat_FULL_GZ; | 297 format = DeltaArchiveManifest_File_DataFormat_FULL_GZ; |
| 274 data.swap(compressed_data); | 298 data.swap(compressed_data); |
| 275 } else { | 299 } else { |
| 276 format = DeltaArchiveManifest_File_DataFormat_FULL; | 300 format = DeltaArchiveManifest_File_DataFormat_FULL; |
| 277 } | 301 } |
| 278 format_set = true; | 302 format_set = true; |
| 279 } | 303 } |
| 280 | 304 |
| 281 if (!data.empty()) { | 305 TEST_AND_RETURN_FALSE(format_set); |
| 282 TEST_AND_RETURN_FALSE(format_set); | 306 file->set_data_format(format); |
| 283 file->set_data_format(format); | 307 file->set_data_offset(*out_file_length); |
| 284 file->set_data_offset(*out_file_length); | 308 TEST_AND_RETURN_FALSE(static_cast<ssize_t>(data.size()) == |
| 285 TEST_AND_RETURN_FALSE(static_cast<ssize_t>(data.size()) == | 309 out_file_writer->Write(&data[0], data.size())); |
| 286 out_file_writer->Write(&data[0], data.size())); | 310 file->set_data_length(data.size()); |
| 287 file->set_data_length(data.size()); | 311 *out_file_length += data.size(); |
| 288 *out_file_length += data.size(); | |
| 289 } | |
| 290 return true; | 312 return true; |
| 291 } | 313 } |
| 292 | 314 |
| 293 bool DeltaDiffGenerator::EncodeLink(const std::string& path, | 315 bool DeltaDiffGenerator::EncodeLink(const string& path, vector<char>* out) { |
| 294 std::vector<char>* out) { | |
| 295 // Store symlink path as file data | 316 // Store symlink path as file data |
| 296 vector<char> link_data(4096); | 317 vector<char> link_data(4096); |
| 297 int rc = readlink(path.c_str(), &link_data[0], link_data.size()); | 318 int rc = readlink(path.c_str(), &link_data[0], link_data.size()); |
| 298 TEST_AND_RETURN_FALSE_ERRNO(rc >= 0); | 319 TEST_AND_RETURN_FALSE_ERRNO(rc >= 0); |
| 299 link_data.resize(rc); | 320 link_data.resize(rc); |
| 300 out->swap(link_data); | 321 out->swap(link_data); |
| 301 return true; | 322 return true; |
| 302 } | 323 } |
| 303 | 324 |
| 304 bool DeltaDiffGenerator::EncodeDev( | 325 bool DeltaDiffGenerator::EncodeDev( |
| (...skipping 17 matching lines...) Expand all Loading... |
| 322 return true; | 343 return true; |
| 323 } | 344 } |
| 324 | 345 |
| 325 // Encode the file at new_path + "/" + file_name. It may be a binary diff | 346 // Encode the file at new_path + "/" + file_name. It may be a binary diff |
| 326 // based on old_path + "/" + file_name. out_data_format will be set to | 347 // based on old_path + "/" + file_name. out_data_format will be set to |
| 327 // the format used. out_data_format may not be NULL. | 348 // the format used. out_data_format may not be NULL. |
| 328 bool DeltaDiffGenerator::EncodeFile( | 349 bool DeltaDiffGenerator::EncodeFile( |
| 329 const string& old_dir, | 350 const string& old_dir, |
| 330 const string& new_dir, | 351 const string& new_dir, |
| 331 const string& file_name, | 352 const string& file_name, |
| 353 const bool avoid_diff, |
| 332 DeltaArchiveManifest_File_DataFormat* out_data_format, | 354 DeltaArchiveManifest_File_DataFormat* out_data_format, |
| 333 vector<char>* out) { | 355 vector<char>* out, |
| 356 bool* no_change) { |
| 334 TEST_AND_RETURN_FALSE(out_data_format); | 357 TEST_AND_RETURN_FALSE(out_data_format); |
| 335 // First, see the full length: | 358 vector<char> ret; |
| 336 vector<char> full_data; | 359 vector<char> full_data; |
| 337 TEST_AND_RETURN_FALSE(utils::ReadFile(new_dir + "/" + file_name, &full_data)); | 360 { |
| 338 vector<char> gz_data; | 361 // First, see the full length: |
| 339 if (!full_data.empty()) { | 362 TEST_AND_RETURN_FALSE(utils::ReadFile(new_dir + "/" + file_name, |
| 340 TEST_AND_RETURN_FALSE(GzipCompress(full_data, &gz_data)); | 363 &full_data)); |
| 364 vector<char> gz_data; |
| 365 if (!full_data.empty()) { |
| 366 TEST_AND_RETURN_FALSE(GzipCompress(full_data, &gz_data)); |
| 367 } |
| 368 |
| 369 if (gz_data.size() < full_data.size()) { |
| 370 *out_data_format = DeltaArchiveManifest_File_DataFormat_FULL_GZ; |
| 371 ret.swap(gz_data); |
| 372 } else { |
| 373 *out_data_format = DeltaArchiveManifest_File_DataFormat_FULL; |
| 374 ret = full_data; |
| 375 } |
| 341 } | 376 } |
| 342 vector<char> *ret = NULL; | |
| 343 | 377 |
| 344 if (gz_data.size() < full_data.size()) { | 378 if (avoid_diff) { |
| 345 *out_data_format = DeltaArchiveManifest_File_DataFormat_FULL_GZ; | 379 out->swap(ret); |
| 346 ret = &gz_data; | 380 return true; |
| 347 } else { | |
| 348 *out_data_format = DeltaArchiveManifest_File_DataFormat_FULL; | |
| 349 ret = &full_data; | |
| 350 } | 381 } |
| 351 | 382 |
| 352 struct stat old_stbuf; | 383 struct stat old_stbuf; |
| 353 if ((stat((old_dir + "/" + file_name).c_str(), &old_stbuf) < 0) || | 384 if ((stat((old_dir + "/" + file_name).c_str(), &old_stbuf) < 0) || |
| 354 (!S_ISREG(old_stbuf.st_mode))) { | 385 (!S_ISREG(old_stbuf.st_mode))) { |
| 355 // stat() failed or old file is not a regular file. Just send back the full | 386 // stat() failed or old file is not a regular file. Just send back |
| 356 // contents | 387 // the full contents |
| 357 *out = *ret; | 388 out->swap(ret); |
| 358 return true; | 389 return true; |
| 359 } | 390 } |
| 360 // We have an old file. Do a binary diff. For now use bsdiff. | 391 // We have an old file. |
| 361 const string kPatchFile = "/tmp/delta.patch"; | 392 // First see if the data is _exactly_ the same |
| 393 { |
| 394 vector<char> original_data; |
| 395 TEST_AND_RETURN_FALSE(utils::ReadFile(old_dir + "/" + file_name, |
| 396 &original_data)); |
| 397 if (original_data == full_data) { |
| 398 // Original data unchanged in new file. |
| 399 *no_change = true; |
| 400 return true; |
| 401 } |
| 402 } |
| 403 |
| 404 // Do a binary diff. For now use bsdiff. |
| 405 const string kPatchFile = "/tmp/delta.patchXXXXXX"; |
| 406 vector<char> patch_file_path(kPatchFile.begin(), kPatchFile.end()); |
| 407 patch_file_path.push_back('\0'); |
| 408 |
| 409 int fd = mkstemp(&patch_file_path[0]); |
| 410 if (fd >= 0) |
| 411 close(fd); |
| 412 TEST_AND_RETURN_FALSE(fd != -1); |
| 362 | 413 |
| 363 vector<string> cmd; | 414 vector<string> cmd; |
| 364 cmd.push_back("/usr/bin/bsdiff"); | 415 cmd.push_back(kBsdiffPath); |
| 365 cmd.push_back(old_dir + "/" + file_name); | 416 cmd.push_back(old_dir + "/" + file_name); |
| 366 cmd.push_back(new_dir + "/" + file_name); | 417 cmd.push_back(new_dir + "/" + file_name); |
| 367 cmd.push_back(kPatchFile); | 418 cmd.push_back(&patch_file_path[0]); |
| 368 | 419 |
| 369 int rc = 1; | 420 int rc = 1; |
| 421 vector<char> patch_file; |
| 370 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &rc)); | 422 TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &rc)); |
| 371 TEST_AND_RETURN_FALSE(rc == 0); | 423 TEST_AND_RETURN_FALSE(rc == 0); |
| 372 vector<char> patch_file; | 424 TEST_AND_RETURN_FALSE(utils::ReadFile(&patch_file_path[0], &patch_file)); |
| 373 TEST_AND_RETURN_FALSE(utils::ReadFile(kPatchFile, &patch_file)); | 425 unlink(&patch_file_path[0]); |
| 374 unlink(kPatchFile.c_str()); | |
| 375 | 426 |
| 376 if (patch_file.size() < ret->size()) { | 427 if (patch_file.size() < ret.size()) { |
| 377 *out_data_format = DeltaArchiveManifest_File_DataFormat_BSDIFF; | 428 *out_data_format = DeltaArchiveManifest_File_DataFormat_BSDIFF; |
| 378 ret = &patch_file; | 429 ret.swap(patch_file); |
| 379 } | 430 } |
| 380 | 431 out->swap(ret); |
| 381 *out = *ret; | |
| 382 return true; | 432 return true; |
| 383 } | 433 } |
| 384 | 434 |
| 385 DeltaArchiveManifest* DeltaDiffGenerator::EncodeMetadataToProtoBuffer( | 435 DeltaArchiveManifest* DeltaDiffGenerator::EncodeMetadataToProtoBuffer( |
| 386 const char* new_path) { | 436 const char* new_path) { |
| 387 Node node; | 437 Node node; |
| 388 if (!UpdateNodeFromPath(new_path, &node)) | 438 if (!UpdateNodeFromPath(new_path, &node)) |
| 389 return NULL; | 439 return NULL; |
| 390 int index = 0; | 440 int index = 0; |
| 391 PopulateChildIndexes(&node, &index); | 441 PopulateChildIndexes(&node, &index); |
| 392 DeltaArchiveManifest *ret = new DeltaArchiveManifest; | 442 DeltaArchiveManifest *ret = new DeltaArchiveManifest; |
| 393 map<ino_t, string> hard_links; // inode -> first found path for inode | 443 map<ino_t, string> hard_links; // inode -> first found path for inode |
| 394 NodeToDeltaArchiveManifest(&node, ret, &hard_links, ""); | 444 NodeToDeltaArchiveManifest(&node, ret, &hard_links, ""); |
| 395 return ret; | 445 return ret; |
| 396 } | 446 } |
| 397 | 447 |
| 398 bool DeltaDiffGenerator::EncodeDataToDeltaFile( | 448 bool DeltaDiffGenerator::EncodeDataToDeltaFile( |
| 399 DeltaArchiveManifest* archive, | 449 DeltaArchiveManifest* archive, |
| 400 const std::string& old_path, | 450 const string& old_path, |
| 401 const std::string& new_path, | 451 const string& new_path, |
| 402 const std::string& out_file, | 452 const string& out_file, |
| 403 const std::string& force_compress_dev_path) { | 453 const set<string>& nondiff_paths, |
| 454 const string& force_compress_dev_path) { |
| 404 DirectFileWriter out_writer; | 455 DirectFileWriter out_writer; |
| 405 int r = out_writer.Open(out_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666); | 456 int r = out_writer.Open(out_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666); |
| 406 TEST_AND_RETURN_FALSE_ERRNO(r >= 0); | 457 TEST_AND_RETURN_FALSE_ERRNO(r >= 0); |
| 407 ScopedFileWriterCloser closer(&out_writer); | 458 ScopedFileWriterCloser closer(&out_writer); |
| 408 TEST_AND_RETURN_FALSE(out_writer.Write(DeltaDiffParser::kFileMagic, | 459 TEST_AND_RETURN_FALSE(out_writer.Write(DeltaDiffParser::kFileMagic, |
| 409 strlen(DeltaDiffParser::kFileMagic)) | 460 strlen(DeltaDiffParser::kFileMagic)) |
| 410 == static_cast<ssize_t>( | 461 == static_cast<ssize_t>( |
| 411 strlen(DeltaDiffParser::kFileMagic))); | 462 strlen(DeltaDiffParser::kFileMagic))); |
| 412 // Write 8 null bytes. This will be filled in w/ the offset of | 463 // Write 8 null bytes. This will be filled in w/ the offset of |
| 413 // the protobuf. | 464 // the protobuf. |
| 414 TEST_AND_RETURN_FALSE(out_writer.Write("\0\0\0\0\0\0\0\0", 8) == 8); | 465 TEST_AND_RETURN_FALSE(out_writer.Write("\0\0\0\0\0\0\0\0", 8) == 8); |
| 415 // 8 more bytes will be filled w/ the protobuf length. | 466 // 8 more bytes will be filled w/ the protobuf length. |
| 416 TEST_AND_RETURN_FALSE(out_writer.Write("\0\0\0\0\0\0\0\0", 8) == 8); | 467 TEST_AND_RETURN_FALSE(out_writer.Write("\0\0\0\0\0\0\0\0", 8) == 8); |
| 417 int out_file_length = strlen(DeltaDiffParser::kFileMagic) + 16; | 468 int out_file_length = strlen(DeltaDiffParser::kFileMagic) + 16; |
| 418 | 469 |
| 419 TEST_AND_RETURN_FALSE(archive->files_size() > 0); | 470 TEST_AND_RETURN_FALSE(archive->files_size() > 0); |
| 420 DeltaArchiveManifest_File* file = archive->mutable_files(0); | 471 DeltaArchiveManifest_File* file = archive->mutable_files(0); |
| 421 | 472 |
| 473 // nondiff_paths is passed in w/ paths relative to the installed |
| 474 // system (e.g. /etc/fstab), but WriteFileDiffsToDeltaFile requires them |
| 475 // to be the entire path of the new file. We create a new set |
| 476 // here with nondiff_paths expanded. |
| 477 set<string> always_full_target_paths; |
| 478 for (set<string>::const_iterator it = nondiff_paths.begin(); |
| 479 it != nondiff_paths.end(); ++it) { |
| 480 always_full_target_paths.insert(new_path + *it); |
| 481 } |
| 482 |
| 422 TEST_AND_RETURN_FALSE(WriteFileDiffsToDeltaFile(archive, | 483 TEST_AND_RETURN_FALSE(WriteFileDiffsToDeltaFile(archive, |
| 423 file, | 484 file, |
| 424 "", | 485 "", |
| 425 old_path, | 486 old_path, |
| 426 new_path, | 487 new_path, |
| 427 &out_writer, | 488 &out_writer, |
| 428 &out_file_length, | 489 &out_file_length, |
| 490 always_full_target_paths, |
| 429 force_compress_dev_path)); | 491 force_compress_dev_path)); |
| 430 | 492 |
| 431 // Finally, write the protobuf to the end of the file | 493 // Finally, write the protobuf to the end of the file |
| 432 string encoded_archive; | 494 string encoded_archive; |
| 433 TEST_AND_RETURN_FALSE(archive->SerializeToString(&encoded_archive)); | 495 TEST_AND_RETURN_FALSE(archive->SerializeToString(&encoded_archive)); |
| 434 | 496 |
| 435 // Compress the protobuf (which contains filenames) | 497 // Compress the protobuf (which contains filenames) |
| 436 vector<char> compressed_encoded_archive; | 498 vector<char> compressed_encoded_archive; |
| 437 TEST_AND_RETURN_FALSE(GzipCompressString(encoded_archive, | 499 TEST_AND_RETURN_FALSE(GzipCompressString(encoded_archive, |
| 438 &compressed_encoded_archive)); | 500 &compressed_encoded_archive)); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 454 TEST_AND_RETURN_FALSE(pwrite(out_writer.fd(), | 516 TEST_AND_RETURN_FALSE(pwrite(out_writer.fd(), |
| 455 &pb_length, | 517 &pb_length, |
| 456 sizeof(pb_length), | 518 sizeof(pb_length), |
| 457 strlen(DeltaDiffParser::kFileMagic) + | 519 strlen(DeltaDiffParser::kFileMagic) + |
| 458 sizeof(big_endian_protobuf_offset)) == | 520 sizeof(big_endian_protobuf_offset)) == |
| 459 sizeof(pb_length)); | 521 sizeof(pb_length)); |
| 460 return true; | 522 return true; |
| 461 } | 523 } |
| 462 | 524 |
| 463 } // namespace chromeos_update_engine | 525 } // namespace chromeos_update_engine |
| OLD | NEW |