1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This file contains the code to apply a Courgette patch.
7 #include "courgette/ensemble.h"
15 #include "base/check.h"
16 #include "base/files/file.h"
17 #include "base/files/file_util.h"
18 #include "base/files/memory_mapped_file.h"
19 #include "courgette/crc.h"
20 #include "courgette/patcher_x86_32.h"
21 #include "courgette/region.h"
22 #include "courgette/simple_delta.h"
23 #include "courgette/streams.h"
27 // EnsemblePatchApplication is all the logic and data required to apply the
29 class EnsemblePatchApplication {
31 EnsemblePatchApplication();
33 EnsemblePatchApplication(const EnsemblePatchApplication&) = delete;
34 EnsemblePatchApplication& operator=(const EnsemblePatchApplication&) = delete;
36 ~EnsemblePatchApplication() = default;
38 Status ReadHeader(SourceStream* header_stream);
40 Status InitBase(const Region& region);
42 Status ValidateBase();
44 Status ReadInitialParameters(SourceStream* initial_parameters);
46 Status PredictTransformParameters(SinkStreamSet* predicted_parameters);
48 Status SubpatchTransformParameters(SinkStreamSet* prediction,
49 SourceStream* correction,
50 SourceStreamSet* corrected_parameters);
52 Status TransformUp(SourceStreamSet* parameters,
53 SinkStreamSet* transformed_elements);
55 Status SubpatchTransformedElements(SinkStreamSet* elements,
56 SourceStream* correction,
57 SourceStreamSet* corrected_elements);
59 Status TransformDown(SourceStreamSet* transformed_elements,
60 SinkStream* basic_elements);
62 Status SubpatchFinalOutput(SourceStream* original,
63 SourceStream* correction,
64 SinkStream* corrected_ensemble);
67 Status SubpatchStreamSets(SinkStreamSet* predicted_items,
68 SourceStream* correction,
69 SourceStreamSet* corrected_items,
70 SinkStream* corrected_items_storage);
72 Region base_region_; // Location of in-memory copy of 'old' version.
74 uint32_t source_checksum_;
75 uint32_t target_checksum_;
76 uint32_t final_patch_input_size_prediction_;
78 std::vector<std::unique_ptr<TransformationPatcher>> patchers_;
80 SinkStream corrected_parameters_storage_;
81 SinkStream corrected_elements_storage_;
84 EnsemblePatchApplication::EnsemblePatchApplication()
85 : source_checksum_(0), target_checksum_(0),
86 final_patch_input_size_prediction_(0) {
89 Status EnsemblePatchApplication::ReadHeader(SourceStream* header_stream) {
91 if (!header_stream->ReadVarint32(&magic))
92 return C_BAD_ENSEMBLE_MAGIC;
94 if (magic != CourgettePatchFile::kMagic)
95 return C_BAD_ENSEMBLE_MAGIC;
98 if (!header_stream->ReadVarint32(&version))
99 return C_BAD_ENSEMBLE_VERSION;
101 if (version != CourgettePatchFile::kVersion)
102 return C_BAD_ENSEMBLE_VERSION;
104 if (!header_stream->ReadVarint32(&source_checksum_))
105 return C_BAD_ENSEMBLE_HEADER;
107 if (!header_stream->ReadVarint32(&target_checksum_))
108 return C_BAD_ENSEMBLE_HEADER;
110 if (!header_stream->ReadVarint32(&final_patch_input_size_prediction_))
111 return C_BAD_ENSEMBLE_HEADER;
116 Status EnsemblePatchApplication::InitBase(const Region& region) {
117 base_region_.assign(region);
121 Status EnsemblePatchApplication::ValidateBase() {
122 uint32_t checksum = CalculateCrc(base_region_.start(), base_region_.length());
123 if (source_checksum_ != checksum)
124 return C_BAD_ENSEMBLE_CRC;
129 Status EnsemblePatchApplication::ReadInitialParameters(
130 SourceStream* transformation_parameters) {
131 uint32_t number_of_transformations = 0;
132 if (!transformation_parameters->ReadVarint32(&number_of_transformations))
133 return C_BAD_ENSEMBLE_HEADER;
135 for (size_t i = 0; i < number_of_transformations; ++i) {
137 if (!transformation_parameters->ReadVarint32(&kind))
138 return C_BAD_ENSEMBLE_HEADER;
140 std::unique_ptr<TransformationPatcher> patcher;
143 case EXE_WIN_32_X86: // Fall through.
146 patcher = std::make_unique<PatcherX86_32>(base_region_);
149 return C_BAD_ENSEMBLE_HEADER;
153 patchers_.push_back(std::move(patcher));
156 for (size_t i = 0; i < patchers_.size(); ++i) {
157 Status status = patchers_[i]->Init(transformation_parameters);
162 // All transformation_parameters should have been consumed by the above loop.
163 if (!transformation_parameters->Empty())
164 return C_BAD_ENSEMBLE_HEADER;
169 Status EnsemblePatchApplication::PredictTransformParameters(
170 SinkStreamSet* all_predicted_parameters) {
171 for (size_t i = 0; i < patchers_.size(); ++i) {
172 SinkStreamSet single_predicted_parameters;
174 patchers_[i]->PredictTransformParameters(&single_predicted_parameters);
177 if (!all_predicted_parameters->WriteSet(&single_predicted_parameters))
178 return C_STREAM_ERROR;
183 Status EnsemblePatchApplication::SubpatchTransformParameters(
184 SinkStreamSet* predicted_parameters,
185 SourceStream* correction,
186 SourceStreamSet* corrected_parameters) {
187 return SubpatchStreamSets(predicted_parameters,
189 corrected_parameters,
190 &corrected_parameters_storage_);
193 Status EnsemblePatchApplication::TransformUp(
194 SourceStreamSet* parameters,
195 SinkStreamSet* transformed_elements) {
196 for (size_t i = 0; i < patchers_.size(); ++i) {
197 SourceStreamSet single_parameters;
198 if (!parameters->ReadSet(&single_parameters))
199 return C_STREAM_ERROR;
200 SinkStreamSet single_transformed_element;
201 Status status = patchers_[i]->Transform(&single_parameters,
202 &single_transformed_element);
205 if (!single_parameters.Empty())
206 return C_STREAM_NOT_CONSUMED;
207 if (!transformed_elements->WriteSet(&single_transformed_element))
208 return C_STREAM_ERROR;
211 if (!parameters->Empty())
212 return C_STREAM_NOT_CONSUMED;
216 Status EnsemblePatchApplication::SubpatchTransformedElements(
217 SinkStreamSet* predicted_elements,
218 SourceStream* correction,
219 SourceStreamSet* corrected_elements) {
220 return SubpatchStreamSets(predicted_elements,
223 &corrected_elements_storage_);
226 Status EnsemblePatchApplication::TransformDown(
227 SourceStreamSet* transformed_elements,
228 SinkStream* basic_elements) {
229 // Construct blob of original input followed by reformed elements.
231 if (!basic_elements->Reserve(final_patch_input_size_prediction_)) {
232 return C_STREAM_ERROR;
235 // The original input:
236 if (!basic_elements->Write(base_region_.start(), base_region_.length()))
237 return C_STREAM_ERROR;
239 for (size_t i = 0; i < patchers_.size(); ++i) {
240 SourceStreamSet single_corrected_element;
241 if (!transformed_elements->ReadSet(&single_corrected_element))
242 return C_STREAM_ERROR;
243 Status status = patchers_[i]->Reform(&single_corrected_element,
247 if (!single_corrected_element.Empty())
248 return C_STREAM_NOT_CONSUMED;
251 if (!transformed_elements->Empty())
252 return C_STREAM_NOT_CONSUMED;
253 // We have totally consumed transformed_elements, so can free the
254 // storage to which it referred.
255 corrected_elements_storage_.Retire();
260 Status EnsemblePatchApplication::SubpatchFinalOutput(
261 SourceStream* original,
262 SourceStream* correction,
263 SinkStream* corrected_ensemble) {
264 Status delta_status = ApplySimpleDelta(original, correction,
266 if (delta_status != C_OK)
269 if (CalculateCrc(corrected_ensemble->Buffer(),
270 corrected_ensemble->Length()) != target_checksum_)
271 return C_BAD_ENSEMBLE_CRC;
276 Status EnsemblePatchApplication::SubpatchStreamSets(
277 SinkStreamSet* predicted_items,
278 SourceStream* correction,
279 SourceStreamSet* corrected_items,
280 SinkStream* corrected_items_storage) {
281 SinkStream linearized_predicted_items;
282 if (!predicted_items->CopyTo(&linearized_predicted_items))
283 return C_STREAM_ERROR;
285 SourceStream prediction;
286 prediction.Init(linearized_predicted_items);
288 Status status = ApplySimpleDelta(&prediction,
290 corrected_items_storage);
294 if (!corrected_items->Init(corrected_items_storage->Buffer(),
295 corrected_items_storage->Length()))
296 return C_STREAM_ERROR;
301 Status ApplyEnsemblePatch(SourceStream* base,
303 SinkStream* output) {
305 EnsemblePatchApplication patch_process;
307 status = patch_process.ReadHeader(patch);
311 status = patch_process.InitBase(Region(base->Buffer(), base->Remaining()));
315 status = patch_process.ValidateBase();
319 // The rest of the patch stream is a StreamSet.
320 SourceStreamSet patch_streams;
321 patch_streams.Init(patch);
323 SourceStream* transformation_descriptions = patch_streams.stream(0);
324 SourceStream* parameter_correction = patch_streams.stream(1);
325 SourceStream* transformed_elements_correction = patch_streams.stream(2);
326 SourceStream* ensemble_correction = patch_streams.stream(3);
328 status = patch_process.ReadInitialParameters(transformation_descriptions);
332 SinkStreamSet predicted_parameters;
333 status = patch_process.PredictTransformParameters(&predicted_parameters);
337 SourceStreamSet corrected_parameters;
338 status = patch_process.SubpatchTransformParameters(&predicted_parameters,
339 parameter_correction,
340 &corrected_parameters);
344 SinkStreamSet transformed_elements;
345 status = patch_process.TransformUp(&corrected_parameters,
346 &transformed_elements);
350 SourceStreamSet corrected_transformed_elements;
351 status = patch_process.SubpatchTransformedElements(
352 &transformed_elements,
353 transformed_elements_correction,
354 &corrected_transformed_elements);
358 SinkStream original_ensemble_and_corrected_base_elements;
359 status = patch_process.TransformDown(
360 &corrected_transformed_elements,
361 &original_ensemble_and_corrected_base_elements);
365 SourceStream final_patch_prediction;
366 final_patch_prediction.Init(original_ensemble_and_corrected_base_elements);
367 status = patch_process.SubpatchFinalOutput(&final_patch_prediction,
368 ensemble_correction, output);
375 Status ApplyEnsemblePatch(base::File old_file,
376 base::File patch_file,
377 base::File new_file) {
378 base::MemoryMappedFile patch_file_mem;
379 if (!patch_file_mem.Initialize(std::move(patch_file)))
380 return C_READ_OPEN_ERROR;
382 // 'Dry-run' the first step of the patch process to validate format of header.
383 SourceStream patch_header_stream;
384 patch_header_stream.Init(patch_file_mem.data(), patch_file_mem.length());
385 EnsemblePatchApplication patch_process;
386 Status status = patch_process.ReadHeader(&patch_header_stream);
390 // Read the old_file.
391 base::MemoryMappedFile old_file_mem;
392 if (!old_file_mem.Initialize(std::move(old_file)))
395 // Apply patch on streams.
396 SourceStream old_source_stream;
397 SourceStream patch_source_stream;
398 old_source_stream.Init(old_file_mem.data(), old_file_mem.length());
399 patch_source_stream.Init(patch_file_mem.data(), patch_file_mem.length());
400 SinkStream new_sink_stream;
401 status = ApplyEnsemblePatch(&old_source_stream, &patch_source_stream,
406 // Write the patched data to |new_file_name|.
407 int written = new_file.Write(
409 reinterpret_cast<const char*>(new_sink_stream.Buffer()),
410 static_cast<int>(new_sink_stream.Length()));
412 return C_WRITE_OPEN_ERROR;
413 if (static_cast<size_t>(written) != new_sink_stream.Length())
414 return C_WRITE_ERROR;
419 Status ApplyEnsemblePatch(const base::FilePath::CharType* old_file_name,
420 const base::FilePath::CharType* patch_file_name,
421 const base::FilePath::CharType* new_file_name) {
422 Status result = ApplyEnsemblePatch(
423 base::File(base::FilePath(old_file_name),
424 base::File::FLAG_OPEN | base::File::FLAG_READ |
425 base::File::FLAG_WIN_SHARE_DELETE),
426 base::File(base::FilePath(patch_file_name),
427 base::File::FLAG_OPEN | base::File::FLAG_READ |
428 base::File::FLAG_WIN_SHARE_DELETE),
429 base::File(base::FilePath(new_file_name),
430 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
431 base::File::FLAG_WIN_EXCLUSIVE_WRITE |
432 base::File::FLAG_WIN_SHARE_DELETE));
434 base::DeleteFile(base::FilePath(new_file_name));
438 } // namespace courgette