blob: 53b5bd73edfbe64528dc4d8b647f66edc95b3ab7 [file] [log] [blame]
huangsf953e4072017-07-28 01:16:211// Copyright 2017 The Chromium 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
Samuel Huang577ef6c2018-03-13 18:19:345#include "components/zucchini/zucchini_commands.h"
huangsf953e4072017-07-28 01:16:216
Samuel Huange8d07b752017-08-21 16:05:257#include <stddef.h>
8#include <stdint.h>
9
huangs252600a2017-07-31 22:19:4810#include <ostream>
Samuel Huang577ef6c2018-03-13 18:19:3411#include <utility>
huangs252600a2017-07-31 22:19:4812
13#include "base/command_line.h"
14#include "base/files/file.h"
15#include "base/files/file_path.h"
16#include "base/files/memory_mapped_file.h"
huangsf953e4072017-07-28 01:16:2117#include "base/logging.h"
huangs252600a2017-07-31 22:19:4818#include "base/macros.h"
Samuel Huang577ef6c2018-03-13 18:19:3419#include "components/zucchini/buffer_view.h"
20#include "components/zucchini/crc32.h"
21#include "components/zucchini/io_utils.h"
22#include "components/zucchini/mapped_file.h"
23#include "components/zucchini/patch_writer.h"
24#include "components/zucchini/zucchini_integration.h"
25#include "components/zucchini/zucchini_tools.h"
huangsf953e4072017-07-28 01:16:2126
27namespace {
28
Etienne Pierre-Doray73ed4232017-08-10 01:28:4129/******** Command-line Switches ********/
30
Samuel Huangd943db62017-08-23 21:46:5731constexpr char kSwitchDump[] = "dump";
32constexpr char kSwitchRaw[] = "raw";
Etienne Pierre-Doray73ed4232017-08-10 01:28:4133
huangsf953e4072017-07-28 01:16:2134} // namespace
35
huangs252600a2017-07-31 22:19:4836zucchini::status::Code MainGen(MainParams params) {
37 CHECK_EQ(3U, params.file_paths.size());
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5438
39 // TODO(huangs): Move implementation to zucchini_integration.cc.
Calder Kitagawaab7fbfb2018-02-09 18:06:0240 using base::File;
Calder Kitagawa796f2fb2018-02-12 17:14:4941 File old_file(params.file_paths[0], File::FLAG_OPEN | File::FLAG_READ);
Calder Kitagawaab7fbfb2018-02-09 18:06:0242 zucchini::MappedFileReader old_image(std::move(old_file));
43 if (old_image.HasError()) {
44 LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
45 << old_image.error();
huangs252600a2017-07-31 22:19:4846 return zucchini::status::kStatusFileReadError;
Calder Kitagawaab7fbfb2018-02-09 18:06:0247 }
Calder Kitagawa796f2fb2018-02-12 17:14:4948 File new_file(params.file_paths[1], File::FLAG_OPEN | File::FLAG_READ);
Calder Kitagawaab7fbfb2018-02-09 18:06:0249 zucchini::MappedFileReader new_image(std::move(new_file));
50 if (new_image.HasError()) {
51 LOG(ERROR) << "Error with file " << params.file_paths[1].value() << ": "
52 << new_image.error();
huangs252600a2017-07-31 22:19:4853 return zucchini::status::kStatusFileReadError;
Calder Kitagawaab7fbfb2018-02-09 18:06:0254 }
Etienne Pierre-Doray73ed4232017-08-10 01:28:4155 zucchini::EnsemblePatchWriter patch_writer(old_image.region(),
56 new_image.region());
huangs252600a2017-07-31 22:19:4857
Etienne Pierre-Doray73ed4232017-08-10 01:28:4158 auto generate = params.command_line.HasSwitch(kSwitchRaw)
59 ? zucchini::GenerateRaw
60 : zucchini::GenerateEnsemble;
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5461 zucchini::status::Code result =
Etienne Pierre-Doray73ed4232017-08-10 01:28:4162 generate(old_image.region(), new_image.region(), &patch_writer);
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5463 if (result != zucchini::status::kStatusSuccess) {
Etienne Pierre-Doray73ed4232017-08-10 01:28:4164 params.out << "Fatal error encountered when generating patch." << std::endl;
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5465 return result;
Etienne Pierre-Doray73ed4232017-08-10 01:28:4166 }
67
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5468 // By default, delete patch on destruction, to avoid having lingering files in
69 // case of a failure. On Windows deletion can be done by the OS.
Calder Kitagawaab7fbfb2018-02-09 18:06:0270 File patch_file(params.file_paths[2], File::FLAG_CREATE_ALWAYS |
71 File::FLAG_READ | File::FLAG_WRITE |
72 File::FLAG_SHARE_DELETE |
73 File::FLAG_CAN_DELETE_ON_CLOSE);
74 zucchini::MappedFileWriter patch(params.file_paths[2], std::move(patch_file),
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5475 patch_writer.SerializedSize());
Calder Kitagawaab7fbfb2018-02-09 18:06:0276 if (patch.HasError()) {
77 LOG(ERROR) << "Error with file " << params.file_paths[2].value() << ": "
78 << patch.error();
huangs252600a2017-07-31 22:19:4879 return zucchini::status::kStatusFileWriteError;
Calder Kitagawaab7fbfb2018-02-09 18:06:0280 }
huangs252600a2017-07-31 22:19:4881
Etienne Pierre-Doray73ed4232017-08-10 01:28:4182 if (!patch_writer.SerializeInto(patch.region()))
83 return zucchini::status::kStatusPatchWriteError;
84
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5485 // Successfully created patch. Explicitly request file to be kept.
86 if (!patch.Keep())
87 return zucchini::status::kStatusFileWriteError;
huangsf953e4072017-07-28 01:16:2188 return zucchini::status::kStatusSuccess;
89}
90
huangs252600a2017-07-31 22:19:4891zucchini::status::Code MainApply(MainParams params) {
92 CHECK_EQ(3U, params.file_paths.size());
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5493 return zucchini::Apply(params.file_paths[0], params.file_paths[1],
94 params.file_paths[2]);
Samuel Huangd943db62017-08-23 21:46:5795}
96
97zucchini::status::Code MainRead(MainParams params) {
98 CHECK_EQ(1U, params.file_paths.size());
Calder Kitagawa796f2fb2018-02-12 17:14:4999 base::File input_file(params.file_paths[0],
100 base::File::FLAG_OPEN | base::File::FLAG_READ);
Calder Kitagawaab7fbfb2018-02-09 18:06:02101 zucchini::MappedFileReader input(std::move(input_file));
102 if (input.HasError()) {
103 LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
104 << input.error();
Samuel Huangd943db62017-08-23 21:46:57105 return zucchini::status::kStatusFileReadError;
Calder Kitagawaab7fbfb2018-02-09 18:06:02106 }
Samuel Huangd943db62017-08-23 21:46:57107
108 bool do_dump = params.command_line.HasSwitch(kSwitchDump);
109 zucchini::status::Code status = zucchini::ReadReferences(
110 {input.data(), input.length()}, do_dump, params.out);
111 if (status != zucchini::status::kStatusSuccess)
112 params.err << "Fatal error found when dumping references." << std::endl;
113 return status;
huangs252600a2017-07-31 22:19:48114}
115
Samuel Huangdd90d832017-11-03 18:14:02116zucchini::status::Code MainDetect(MainParams params) {
117 CHECK_EQ(1U, params.file_paths.size());
Calder Kitagawa796f2fb2018-02-12 17:14:49118 base::File input_file(params.file_paths[0],
119 base::File::FLAG_OPEN | base::File::FLAG_READ);
Calder Kitagawaab7fbfb2018-02-09 18:06:02120 zucchini::MappedFileReader input(std::move(input_file));
121 if (input.HasError()) {
122 LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
123 << input.error();
Samuel Huangdd90d832017-11-03 18:14:02124 return zucchini::status::kStatusFileReadError;
Calder Kitagawaab7fbfb2018-02-09 18:06:02125 }
Samuel Huangdd90d832017-11-03 18:14:02126
127 std::vector<zucchini::ConstBufferView> sub_image_list;
128 zucchini::status::Code result = zucchini::DetectAll(
129 {input.data(), input.length()}, params.out, &sub_image_list);
130 if (result != zucchini::status::kStatusSuccess)
131 params.err << "Fatal error found when detecting executables." << std::endl;
132 return result;
133}
134
Samuel Huangfdb2f3a2017-12-20 17:45:14135zucchini::status::Code MainMatch(MainParams params) {
136 CHECK_EQ(2U, params.file_paths.size());
Calder Kitagawaab7fbfb2018-02-09 18:06:02137 using base::File;
Calder Kitagawa796f2fb2018-02-12 17:14:49138 File old_file(params.file_paths[0], File::FLAG_OPEN | File::FLAG_READ);
Calder Kitagawaab7fbfb2018-02-09 18:06:02139 zucchini::MappedFileReader old_image(std::move(old_file));
140 if (old_image.HasError()) {
141 LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
142 << old_image.error();
Samuel Huangfdb2f3a2017-12-20 17:45:14143 return zucchini::status::kStatusFileReadError;
Calder Kitagawaab7fbfb2018-02-09 18:06:02144 }
Calder Kitagawa796f2fb2018-02-12 17:14:49145 File new_file(params.file_paths[1], File::FLAG_OPEN | File::FLAG_READ);
Calder Kitagawaab7fbfb2018-02-09 18:06:02146 zucchini::MappedFileReader new_image(std::move(new_file));
Calder Kitagawa3135d7d12018-03-14 19:28:36147 if (new_image.HasError()) {
Calder Kitagawaab7fbfb2018-02-09 18:06:02148 LOG(ERROR) << "Error with file " << params.file_paths[1].value() << ": "
149 << new_image.error();
Samuel Huangfdb2f3a2017-12-20 17:45:14150 return zucchini::status::kStatusFileReadError;
Calder Kitagawaab7fbfb2018-02-09 18:06:02151 }
Samuel Huangfdb2f3a2017-12-20 17:45:14152 zucchini::status::Code status =
153 zucchini::MatchAll({old_image.data(), old_image.length()},
154 {new_image.data(), new_image.length()}, params.out);
155 if (status != zucchini::status::kStatusSuccess)
156 params.err << "Fatal error found when matching executables." << std::endl;
157 return status;
158}
159
huangs252600a2017-07-31 22:19:48160zucchini::status::Code MainCrc32(MainParams params) {
161 CHECK_EQ(1U, params.file_paths.size());
Calder Kitagawa796f2fb2018-02-12 17:14:49162 base::File image_file(params.file_paths[0],
163 base::File::FLAG_OPEN | base::File::FLAG_READ);
Calder Kitagawaab7fbfb2018-02-09 18:06:02164 zucchini::MappedFileReader image(std::move(image_file));
165 if (image.HasError()) {
166 LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
167 << image.error();
huangs252600a2017-07-31 22:19:48168 return zucchini::status::kStatusFileReadError;
Calder Kitagawaab7fbfb2018-02-09 18:06:02169 }
huangs252600a2017-07-31 22:19:48170
171 uint32_t crc =
172 zucchini::CalculateCrc32(image.data(), image.data() + image.length());
173 params.out << "CRC32: " << zucchini::AsHex<8>(crc) << std::endl;
huangsf953e4072017-07-28 01:16:21174 return zucchini::status::kStatusSuccess;
175}