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 |