• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "bsdiff/diff_encoder.h"
6 
7 #include <vector>
8 
9 #include "bsdiff/logging.h"
10 
11 namespace {
12 
13 // The maximum positive number that we should encode. A number larger than this
14 // for unsigned fields will be interpreted as a negative value and thus a
15 // corrupt patch.
16 const uint64_t kMaxEncodedUint64Value = (1ULL << 63) - 1;
17 
18 }  // namespace
19 
20 namespace bsdiff {
21 
Init()22 bool DiffEncoder::Init() {
23   return patch_->Init(new_size_);
24 }
25 
AddControlEntry(const ControlEntry & entry)26 bool DiffEncoder::AddControlEntry(const ControlEntry& entry) {
27   if (entry.diff_size > kMaxEncodedUint64Value) {
28     LOG(ERROR) << "Encoding value out of range " << entry.diff_size;
29     return false;
30   }
31 
32   if (entry.extra_size > kMaxEncodedUint64Value) {
33     LOG(ERROR) << "Encoding value out of range " << entry.extra_size;
34     return false;
35   }
36 
37   // entry.diff_size + entry.extra_size don't overflow in uint64_t since we
38   // checked the kMaxEncodedUint64Value limit before.
39   if (entry.diff_size + entry.extra_size > new_size_ - written_output_) {
40     LOG(ERROR) << "Wrote more output than the declared new_size";
41     return false;
42   }
43 
44   if (entry.diff_size > 0 &&
45       (old_pos_ < 0 ||
46        static_cast<uint64_t>(old_pos_) + entry.diff_size > old_size_)) {
47     LOG(ERROR) << "The pointer in the old stream [" << old_pos_ << ", "
48                << (static_cast<uint64_t>(old_pos_) + entry.diff_size)
49                << ") is out of bounds [0, " << old_size_ << ")";
50     return false;
51   }
52 
53   // Pass down the control entry.
54   if (!patch_->AddControlEntry(entry))
55     return false;
56 
57   // Generate the diff stream.
58   std::vector<uint8_t> diff(entry.diff_size);
59   for (uint64_t i = 0; i < entry.diff_size; ++i) {
60     diff[i] = new_buf_[written_output_ + i] - old_buf_[old_pos_ + i];
61   }
62   if (!patch_->WriteDiffStream(diff.data(), diff.size())) {
63     LOG(ERROR) << "Writing " << diff.size() << " bytes to the diff stream";
64     return false;
65   }
66 
67   if (!patch_->WriteExtraStream(new_buf_ + written_output_ + entry.diff_size,
68                                 entry.extra_size)) {
69     LOG(ERROR) << "Writing " << entry.extra_size
70                << " bytes to the extra stream";
71     return false;
72   }
73 
74   old_pos_ += entry.diff_size + entry.offset_increment;
75   written_output_ += entry.diff_size + entry.extra_size;
76 
77   return true;
78 }
79 
Close()80 bool DiffEncoder::Close() {
81   if (written_output_ != new_size_) {
82     LOG(ERROR) << "Close() called but not all the output was written";
83     return false;
84   }
85   return patch_->Close();
86 }
87 
88 }  // namespace bsdiff
89