blob: c654a08735a4f83474d590bbb3b2e53d86aec7e9 [file] [log] [blame]
Samuel Huang06f1ae92018-03-13 18:19:34 +00001// 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_integration.h"
6
7#include <utility>
8
9#include "base/logging.h"
10#include "components/zucchini/buffer_view.h"
11#include "components/zucchini/mapped_file.h"
12#include "components/zucchini/patch_reader.h"
13
14namespace zucchini {
15
16namespace {
17
18struct FileNames {
19 FileNames() : is_dummy(true) {
Calder Kitagawa63974a22018-03-14 19:28:36 +000020 // Use fake names.
Samuel Huang06f1ae92018-03-13 18:19:34 +000021 old_name = old_name.AppendASCII("old_name");
Samuel Huang06f1ae92018-03-13 18:19:34 +000022 new_name = new_name.AppendASCII("new_name");
Samuel Huangf35146e2018-06-21 15:50:22 +000023 patch_name = patch_name.AppendASCII("patch_name");
Samuel Huang06f1ae92018-03-13 18:19:34 +000024 }
25
26 FileNames(const base::FilePath& old_name,
Samuel Huangf35146e2018-06-21 15:50:22 +000027 const base::FilePath& new_name,
28 const base::FilePath& patch_name)
Samuel Huang06f1ae92018-03-13 18:19:34 +000029 : old_name(old_name),
Samuel Huang06f1ae92018-03-13 18:19:34 +000030 new_name(new_name),
Samuel Huangf35146e2018-06-21 15:50:22 +000031 patch_name(patch_name),
Samuel Huang06f1ae92018-03-13 18:19:34 +000032 is_dummy(false) {}
33
34 base::FilePath old_name;
Samuel Huang06f1ae92018-03-13 18:19:34 +000035 base::FilePath new_name;
Samuel Huangf35146e2018-06-21 15:50:22 +000036 base::FilePath patch_name;
Calder Kitagawa63974a22018-03-14 19:28:36 +000037
38 // A flag to decide whether the filenames are only for error output.
Samuel Huang06f1ae92018-03-13 18:19:34 +000039 const bool is_dummy;
40};
41
Samuel Huangf35146e2018-06-21 15:50:22 +000042status::Code GenerateCommon(base::File old_file,
43 base::File new_file,
44 base::File patch_file,
45 const FileNames& names,
46 bool force_keep,
47 bool is_raw,
48 std::string imposed_matches) {
49 MappedFileReader mapped_old(std::move(old_file));
50 if (mapped_old.HasError()) {
51 LOG(ERROR) << "Error with file " << names.old_name.value() << ": "
52 << mapped_old.error();
Samuel Huang06f1ae92018-03-13 18:19:34 +000053 return status::kStatusFileReadError;
54 }
55
Samuel Huangf35146e2018-06-21 15:50:22 +000056 MappedFileReader mapped_new(std::move(new_file));
57 if (mapped_new.HasError()) {
58 LOG(ERROR) << "Error with file " << names.new_name.value() << ": "
59 << mapped_new.error();
60 return status::kStatusFileReadError;
61 }
62
63 status::Code result = status::kStatusSuccess;
64 EnsemblePatchWriter patch_writer(mapped_old.region(), mapped_new.region());
65 if (is_raw) {
66 result = GenerateBufferRaw(mapped_old.region(), mapped_new.region(),
67 &patch_writer);
68 } else {
69 result = GenerateBufferImposed(mapped_old.region(), mapped_new.region(),
70 std::move(imposed_matches), &patch_writer);
71 }
72 if (result != status::kStatusSuccess) {
73 LOG(ERROR) << "Fatal error encountered when generating patch.";
74 return result;
75 }
76
77 // By default, delete patch on destruction, to avoid having lingering files in
78 // case of a failure. On Windows deletion can be done by the OS.
79 MappedFileWriter mapped_patch(names.patch_name, std::move(patch_file),
80 patch_writer.SerializedSize());
81 if (mapped_patch.HasError()) {
82 LOG(ERROR) << "Error with file " << names.patch_name.value() << ": "
83 << mapped_patch.error();
84 return status::kStatusFileWriteError;
85 }
86 if (force_keep)
87 mapped_patch.Keep();
88
89 if (!patch_writer.SerializeInto(mapped_patch.region()))
90 return status::kStatusPatchWriteError;
91
92 // Successfully created patch. Explicitly request file to be kept.
93 if (!mapped_patch.Keep())
94 return status::kStatusFileWriteError;
95 return status::kStatusSuccess;
96}
97
98status::Code ApplyCommon(base::File old_file,
99 base::File patch_file,
100 base::File new_file,
101 const FileNames& names,
102 bool force_keep) {
103 MappedFileReader mapped_patch(std::move(patch_file));
104 if (mapped_patch.HasError()) {
105 LOG(ERROR) << "Error with file " << names.patch_name.value() << ": "
106 << mapped_patch.error();
107 return status::kStatusFileReadError;
108 }
109
110 auto patch_reader = EnsemblePatchReader::Create(mapped_patch.region());
Samuel Huang06f1ae92018-03-13 18:19:34 +0000111 if (!patch_reader.has_value()) {
112 LOG(ERROR) << "Error reading patch header.";
113 return status::kStatusPatchReadError;
114 }
115
Samuel Huangf35146e2018-06-21 15:50:22 +0000116 MappedFileReader mapped_old(std::move(old_file));
117 if (mapped_old.HasError()) {
Samuel Huang06f1ae92018-03-13 18:19:34 +0000118 LOG(ERROR) << "Error with file " << names.old_name.value() << ": "
Samuel Huangf35146e2018-06-21 15:50:22 +0000119 << mapped_old.error();
Samuel Huang06f1ae92018-03-13 18:19:34 +0000120 return status::kStatusFileReadError;
121 }
Samuel Huang06f1ae92018-03-13 18:19:34 +0000122
Samuel Huangf35146e2018-06-21 15:50:22 +0000123 PatchHeader header = patch_reader->header();
Samuel Huang06f1ae92018-03-13 18:19:34 +0000124 // By default, delete output on destruction, to avoid having lingering files
125 // in case of a failure. On Windows deletion can be done by the OS.
Samuel Huangf35146e2018-06-21 15:50:22 +0000126 MappedFileWriter mapped_new(names.new_name, std::move(new_file),
127 header.new_size);
128 if (mapped_new.HasError()) {
Samuel Huang06f1ae92018-03-13 18:19:34 +0000129 LOG(ERROR) << "Error with file " << names.new_name.value() << ": "
Samuel Huangf35146e2018-06-21 15:50:22 +0000130 << mapped_new.error();
Samuel Huang06f1ae92018-03-13 18:19:34 +0000131 return status::kStatusFileWriteError;
132 }
Samuel Huang1bb3b652018-03-21 18:54:03 +0000133 if (force_keep)
Samuel Huangf35146e2018-06-21 15:50:22 +0000134 mapped_new.Keep();
Samuel Huang1bb3b652018-03-21 18:54:03 +0000135
Samuel Huangf35146e2018-06-21 15:50:22 +0000136 status::Code result =
137 ApplyBuffer(mapped_old.region(), *patch_reader, mapped_new.region());
Samuel Huang06f1ae92018-03-13 18:19:34 +0000138 if (result != status::kStatusSuccess) {
139 LOG(ERROR) << "Fatal error encountered while applying patch.";
140 return result;
141 }
142
Samuel Huangf35146e2018-06-21 15:50:22 +0000143 // Successfully patch |mapped_new|. Explicitly request file to be kept.
144 if (!mapped_new.Keep())
Samuel Huang06f1ae92018-03-13 18:19:34 +0000145 return status::kStatusFileWriteError;
146 return status::kStatusSuccess;
147}
148
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +0000149status::Code VerifyPatchCommon(base::File patch_file,
150 base::FilePath patch_name) {
151 MappedFileReader mapped_patch(std::move(patch_file));
152 if (mapped_patch.HasError()) {
153 LOG(ERROR) << "Error with file " << patch_name.value() << ": "
154 << mapped_patch.error();
155 return status::kStatusFileReadError;
156 }
157 auto patch_reader = EnsemblePatchReader::Create(mapped_patch.region());
158 if (!patch_reader.has_value()) {
159 LOG(ERROR) << "Error reading patch header.";
160 return status::kStatusPatchReadError;
161 }
162 return status::kStatusSuccess;
163}
164
Samuel Huang06f1ae92018-03-13 18:19:34 +0000165} // namespace
166
Samuel Huangf35146e2018-06-21 15:50:22 +0000167status::Code Generate(base::File old_file,
168 base::File new_file,
169 base::File patch_file,
170 bool force_keep,
171 bool is_raw,
172 std::string imposed_matches) {
173 const FileNames file_names;
174 return GenerateCommon(std::move(old_file), std::move(new_file),
175 std::move(patch_file), file_names, force_keep, is_raw,
176 std::move(imposed_matches));
177}
178
179status::Code Generate(const base::FilePath& old_path,
180 const base::FilePath& new_path,
181 const base::FilePath& patch_path,
182 bool force_keep,
183 bool is_raw,
184 std::string imposed_matches) {
185 using base::File;
Greg Thompsonf16a0ed2020-07-18 01:29:39 +0000186 File old_file(old_path, File::FLAG_OPEN | File::FLAG_READ |
Alexei Svitkine261f4df2021-11-16 22:01:32 +0000187 base::File::FLAG_WIN_SHARE_DELETE);
Greg Thompsonf16a0ed2020-07-18 01:29:39 +0000188 File new_file(new_path, File::FLAG_OPEN | File::FLAG_READ |
Alexei Svitkine261f4df2021-11-16 22:01:32 +0000189 base::File::FLAG_WIN_SHARE_DELETE);
Samuel Huangf35146e2018-06-21 15:50:22 +0000190 File patch_file(patch_path, File::FLAG_CREATE_ALWAYS | File::FLAG_READ |
Alexei Svitkine261f4df2021-11-16 22:01:32 +0000191 File::FLAG_WRITE |
192 File::FLAG_WIN_SHARE_DELETE |
Samuel Huangf35146e2018-06-21 15:50:22 +0000193 File::FLAG_CAN_DELETE_ON_CLOSE);
194 const FileNames file_names(old_path, new_path, patch_path);
195 return GenerateCommon(std::move(old_file), std::move(new_file),
196 std::move(patch_file), file_names, force_keep, is_raw,
197 std::move(imposed_matches));
198}
199
200status::Code Apply(base::File old_file,
201 base::File patch_file,
202 base::File new_file,
Samuel Huang1bb3b652018-03-21 18:54:03 +0000203 bool force_keep) {
Calder Kitagawa63974a22018-03-14 19:28:36 +0000204 const FileNames file_names;
Samuel Huangf35146e2018-06-21 15:50:22 +0000205 return ApplyCommon(std::move(old_file), std::move(patch_file),
206 std::move(new_file), file_names, force_keep);
Samuel Huang06f1ae92018-03-13 18:19:34 +0000207}
208
209status::Code Apply(const base::FilePath& old_path,
210 const base::FilePath& patch_path,
Samuel Huang1bb3b652018-03-21 18:54:03 +0000211 const base::FilePath& new_path,
212 bool force_keep) {
Samuel Huang06f1ae92018-03-13 18:19:34 +0000213 using base::File;
Greg Thompsonf16a0ed2020-07-18 01:29:39 +0000214 File old_file(old_path, File::FLAG_OPEN | File::FLAG_READ |
Alexei Svitkine261f4df2021-11-16 22:01:32 +0000215 base::File::FLAG_WIN_SHARE_DELETE);
Greg Thompsonf16a0ed2020-07-18 01:29:39 +0000216 File patch_file(patch_path, File::FLAG_OPEN | File::FLAG_READ |
Alexei Svitkine261f4df2021-11-16 22:01:32 +0000217 base::File::FLAG_WIN_SHARE_DELETE);
Samuel Huang06f1ae92018-03-13 18:19:34 +0000218 File new_file(new_path, File::FLAG_CREATE_ALWAYS | File::FLAG_READ |
Alexei Svitkine261f4df2021-11-16 22:01:32 +0000219 File::FLAG_WRITE | File::FLAG_WIN_SHARE_DELETE |
Samuel Huang06f1ae92018-03-13 18:19:34 +0000220 File::FLAG_CAN_DELETE_ON_CLOSE);
Samuel Huangf35146e2018-06-21 15:50:22 +0000221 const FileNames file_names(old_path, new_path, patch_path);
Samuel Huang06f1ae92018-03-13 18:19:34 +0000222 return ApplyCommon(std::move(old_file), std::move(patch_file),
Samuel Huang1bb3b652018-03-21 18:54:03 +0000223 std::move(new_file), file_names, force_keep);
Samuel Huang06f1ae92018-03-13 18:19:34 +0000224}
225
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +0000226status::Code VerifyPatch(base::File patch_file) {
227 return VerifyPatchCommon(std::move(patch_file), base::FilePath());
228}
229
230status::Code VerifyPatch(const base::FilePath& patch_path) {
231 using base::File;
232 File patch_file(patch_path, File::FLAG_OPEN | File::FLAG_READ |
233 base::File::FLAG_SHARE_DELETE);
234 return VerifyPatchCommon(std::move(patch_file), patch_path);
235}
236
Samuel Huang06f1ae92018-03-13 18:19:34 +0000237} // namespace zucchini