1 // 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
5 #include "components/zucchini/zucchini_commands.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <ostream>
11 #include <string>
12 #include <utility>
13
14 #include "base/command_line.h"
15 #include "base/files/file.h"
16 #include "base/files/file_path.h"
17 #include "base/files/memory_mapped_file.h"
18 #include "base/logging.h"
19 #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"
26
27 namespace {
28
29 /******** Command-line Switches ********/
30
31 constexpr char kSwitchDump[] = "dump";
32 constexpr char kSwitchImpose[] = "impose";
33 constexpr char kSwitchKeep[] = "keep";
34 constexpr char kSwitchRaw[] = "raw";
35
36 } // namespace
37
MainGen(MainParams params)38 zucchini::status::Code MainGen(MainParams params) {
39 CHECK_EQ(3U, params.file_paths.size());
40 return zucchini::Generate(
41 params.file_paths[0], params.file_paths[1], params.file_paths[2],
42 params.command_line.HasSwitch(kSwitchKeep),
43 params.command_line.HasSwitch(kSwitchRaw),
44 params.command_line.GetSwitchValueASCII(kSwitchImpose));
45 }
46
MainApply(MainParams params)47 zucchini::status::Code MainApply(MainParams params) {
48 CHECK_EQ(3U, params.file_paths.size());
49 return zucchini::Apply(params.file_paths[0], params.file_paths[1],
50 params.file_paths[2],
51 params.command_line.HasSwitch(kSwitchKeep));
52 }
53
MainVerify(MainParams params)54 zucchini::status::Code MainVerify(MainParams params) {
55 CHECK_EQ(1U, params.file_paths.size());
56 return zucchini::VerifyPatch(params.file_paths[0]);
57 }
58
MainRead(MainParams params)59 zucchini::status::Code MainRead(MainParams params) {
60 CHECK_EQ(1U, params.file_paths.size());
61 base::File input_file(params.file_paths[0],
62 base::File::FLAG_OPEN | base::File::FLAG_READ |
63 base::File::FLAG_WIN_SHARE_DELETE);
64 zucchini::MappedFileReader input(std::move(input_file));
65 if (input.HasError()) {
66 LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
67 << input.error();
68 return zucchini::status::kStatusFileReadError;
69 }
70
71 bool do_dump = params.command_line.HasSwitch(kSwitchDump);
72 zucchini::status::Code status = zucchini::ReadReferences(
73 {input.data(), input.length()}, do_dump, params.out);
74 if (status != zucchini::status::kStatusSuccess)
75 params.err << "Fatal error found when dumping references." << std::endl;
76 return status;
77 }
78
MainDetect(MainParams params)79 zucchini::status::Code MainDetect(MainParams params) {
80 CHECK_EQ(1U, params.file_paths.size());
81 base::File input_file(params.file_paths[0],
82 base::File::FLAG_OPEN | base::File::FLAG_READ |
83 base::File::FLAG_WIN_SHARE_DELETE);
84 zucchini::MappedFileReader input(std::move(input_file));
85 if (input.HasError()) {
86 LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
87 << input.error();
88 return zucchini::status::kStatusFileReadError;
89 }
90
91 std::vector<zucchini::ConstBufferView> sub_image_list;
92 zucchini::status::Code result = zucchini::DetectAll(
93 {input.data(), input.length()}, params.out, &sub_image_list);
94 if (result != zucchini::status::kStatusSuccess)
95 params.err << "Fatal error found when detecting executables." << std::endl;
96 return result;
97 }
98
MainMatch(MainParams params)99 zucchini::status::Code MainMatch(MainParams params) {
100 CHECK_EQ(2U, params.file_paths.size());
101 using base::File;
102 File old_file(params.file_paths[0], File::FLAG_OPEN | File::FLAG_READ |
103 base::File::FLAG_WIN_SHARE_DELETE);
104 zucchini::MappedFileReader old_image(std::move(old_file));
105 if (old_image.HasError()) {
106 LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
107 << old_image.error();
108 return zucchini::status::kStatusFileReadError;
109 }
110 File new_file(params.file_paths[1], File::FLAG_OPEN | File::FLAG_READ |
111 base::File::FLAG_WIN_SHARE_DELETE);
112 zucchini::MappedFileReader new_image(std::move(new_file));
113 if (new_image.HasError()) {
114 LOG(ERROR) << "Error with file " << params.file_paths[1].value() << ": "
115 << new_image.error();
116 return zucchini::status::kStatusFileReadError;
117 }
118
119 std::string imposed_matches =
120 params.command_line.GetSwitchValueASCII(kSwitchImpose);
121 zucchini::status::Code status =
122 zucchini::MatchAll({old_image.data(), old_image.length()},
123 {new_image.data(), new_image.length()},
124 std::move(imposed_matches), params.out);
125 if (status != zucchini::status::kStatusSuccess)
126 params.err << "Fatal error found when matching executables." << std::endl;
127 return status;
128 }
129
MainCrc32(MainParams params)130 zucchini::status::Code MainCrc32(MainParams params) {
131 CHECK_EQ(1U, params.file_paths.size());
132 base::File image_file(params.file_paths[0],
133 base::File::FLAG_OPEN | base::File::FLAG_READ |
134 base::File::FLAG_WIN_SHARE_DELETE);
135 zucchini::MappedFileReader image(std::move(image_file));
136 if (image.HasError()) {
137 LOG(ERROR) << "Error with file " << params.file_paths[0].value() << ": "
138 << image.error();
139 return zucchini::status::kStatusFileReadError;
140 }
141
142 uint32_t crc =
143 zucchini::CalculateCrc32(image.data(), image.data() + image.length());
144 params.out << "CRC32: " << zucchini::AsHex<8>(crc) << std::endl;
145 return zucchini::status::kStatusSuccess;
146 }
147