blob: 2d4b1564746491a1c3bbca4d156c9e67ebad11ef [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";
Samuel Huang21879c32018-03-21 18:54:0332constexpr char kSwitchKeep[] = "keep";
Samuel Huangd943db62017-08-23 21:46:5733constexpr char kSwitchRaw[] = "raw";
Etienne Pierre-Doray73ed4232017-08-10 01:28:4134
huangsf953e4072017-07-28 01:16:2135} // namespace
36
huangs252600a2017-07-31 22:19:4837zucchini::status::Code MainGen(MainParams params) {
38 CHECK_EQ(3U, params.file_paths.size());
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5439
40 // TODO(huangs): Move implementation to zucchini_integration.cc.
Calder Kitagawaab7fbfb2018-02-09 18:06:0241 using base::File;
Calder Kitagawa796f2fb2018-02-12 17:14:4942 File old_file(params.file_paths[0], File::FLAG_OPEN | File::FLAG_READ);
Calder Kitagawaab7fbfb2018-02-09 18:06:0243 zucchini::MappedFileReader old_image(std::move(old_file));
44 if (old_image.HasError()) {
45 LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
46 << old_image.error();
huangs252600a2017-07-31 22:19:4847 return zucchini::status::kStatusFileReadError;
Calder Kitagawaab7fbfb2018-02-09 18:06:0248 }
Calder Kitagawa796f2fb2018-02-12 17:14:4949 File new_file(params.file_paths[1], File::FLAG_OPEN | File::FLAG_READ);
Calder Kitagawaab7fbfb2018-02-09 18:06:0250 zucchini::MappedFileReader new_image(std::move(new_file));
51 if (new_image.HasError()) {
52 LOG(ERROR) << "Error with file " << params.file_paths[1].value() << ": "
53 << new_image.error();
huangs252600a2017-07-31 22:19:4854 return zucchini::status::kStatusFileReadError;
Calder Kitagawaab7fbfb2018-02-09 18:06:0255 }
Etienne Pierre-Doray73ed4232017-08-10 01:28:4156 zucchini::EnsemblePatchWriter patch_writer(old_image.region(),
57 new_image.region());
huangs252600a2017-07-31 22:19:4858
Etienne Pierre-Doray73ed4232017-08-10 01:28:4159 auto generate = params.command_line.HasSwitch(kSwitchRaw)
60 ? zucchini::GenerateRaw
61 : zucchini::GenerateEnsemble;
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5462 zucchini::status::Code result =
Etienne Pierre-Doray73ed4232017-08-10 01:28:4163 generate(old_image.region(), new_image.region(), &patch_writer);
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5464 if (result != zucchini::status::kStatusSuccess) {
Etienne Pierre-Doray73ed4232017-08-10 01:28:4165 params.out << "Fatal error encountered when generating patch." << std::endl;
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5466 return result;
Etienne Pierre-Doray73ed4232017-08-10 01:28:4167 }
68
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5469 // By default, delete patch on destruction, to avoid having lingering files in
70 // case of a failure. On Windows deletion can be done by the OS.
Calder Kitagawaab7fbfb2018-02-09 18:06:0271 File patch_file(params.file_paths[2], File::FLAG_CREATE_ALWAYS |
72 File::FLAG_READ | File::FLAG_WRITE |
73 File::FLAG_SHARE_DELETE |
74 File::FLAG_CAN_DELETE_ON_CLOSE);
75 zucchini::MappedFileWriter patch(params.file_paths[2], std::move(patch_file),
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5476 patch_writer.SerializedSize());
Calder Kitagawaab7fbfb2018-02-09 18:06:0277 if (patch.HasError()) {
78 LOG(ERROR) << "Error with file " << params.file_paths[2].value() << ": "
79 << patch.error();
huangs252600a2017-07-31 22:19:4880 return zucchini::status::kStatusFileWriteError;
Calder Kitagawaab7fbfb2018-02-09 18:06:0281 }
huangs252600a2017-07-31 22:19:4882
Samuel Huang21879c32018-03-21 18:54:0383 if (params.command_line.HasSwitch(kSwitchKeep))
84 patch.Keep();
85
Etienne Pierre-Doray73ed4232017-08-10 01:28:4186 if (!patch_writer.SerializeInto(patch.region()))
87 return zucchini::status::kStatusPatchWriteError;
88
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5489 // Successfully created patch. Explicitly request file to be kept.
90 if (!patch.Keep())
91 return zucchini::status::kStatusFileWriteError;
huangsf953e4072017-07-28 01:16:2192 return zucchini::status::kStatusSuccess;
93}
94
huangs252600a2017-07-31 22:19:4895zucchini::status::Code MainApply(MainParams params) {
96 CHECK_EQ(3U, params.file_paths.size());
Etienne Pierre-Doray455d1ae2017-08-24 01:17:5497 return zucchini::Apply(params.file_paths[0], params.file_paths[1],
Samuel Huang21879c32018-03-21 18:54:0398 params.file_paths[2],
99 params.command_line.HasSwitch(kSwitchKeep));
Samuel Huangd943db62017-08-23 21:46:57100}
101
102zucchini::status::Code MainRead(MainParams params) {
103 CHECK_EQ(1U, params.file_paths.size());
Calder Kitagawa796f2fb2018-02-12 17:14:49104 base::File input_file(params.file_paths[0],
105 base::File::FLAG_OPEN | base::File::FLAG_READ);
Calder Kitagawaab7fbfb2018-02-09 18:06:02106 zucchini::MappedFileReader input(std::move(input_file));
107 if (input.HasError()) {
108 LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
109 << input.error();
Samuel Huangd943db62017-08-23 21:46:57110 return zucchini::status::kStatusFileReadError;
Calder Kitagawaab7fbfb2018-02-09 18:06:02111 }
Samuel Huangd943db62017-08-23 21:46:57112
113 bool do_dump = params.command_line.HasSwitch(kSwitchDump);
114 zucchini::status::Code status = zucchini::ReadReferences(
115 {input.data(), input.length()}, do_dump, params.out);
116 if (status != zucchini::status::kStatusSuccess)
117 params.err << "Fatal error found when dumping references." << std::endl;
118 return status;
huangs252600a2017-07-31 22:19:48119}
120
Samuel Huangdd90d832017-11-03 18:14:02121zucchini::status::Code MainDetect(MainParams params) {
122 CHECK_EQ(1U, params.file_paths.size());
Calder Kitagawa796f2fb2018-02-12 17:14:49123 base::File input_file(params.file_paths[0],
124 base::File::FLAG_OPEN | base::File::FLAG_READ);
Calder Kitagawaab7fbfb2018-02-09 18:06:02125 zucchini::MappedFileReader input(std::move(input_file));
126 if (input.HasError()) {
127 LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
128 << input.error();
Samuel Huangdd90d832017-11-03 18:14:02129 return zucchini::status::kStatusFileReadError;
Calder Kitagawaab7fbfb2018-02-09 18:06:02130 }
Samuel Huangdd90d832017-11-03 18:14:02131
132 std::vector<zucchini::ConstBufferView> sub_image_list;
133 zucchini::status::Code result = zucchini::DetectAll(
134 {input.data(), input.length()}, params.out, &sub_image_list);
135 if (result != zucchini::status::kStatusSuccess)
136 params.err << "Fatal error found when detecting executables." << std::endl;
137 return result;
138}
139
Samuel Huangfdb2f3a2017-12-20 17:45:14140zucchini::status::Code MainMatch(MainParams params) {
141 CHECK_EQ(2U, params.file_paths.size());
Calder Kitagawaab7fbfb2018-02-09 18:06:02142 using base::File;
Calder Kitagawa796f2fb2018-02-12 17:14:49143 File old_file(params.file_paths[0], File::FLAG_OPEN | File::FLAG_READ);
Calder Kitagawaab7fbfb2018-02-09 18:06:02