1*a03ca8b9SKrzysztof Kosiński // Copyright 2017 The Chromium Authors. All rights reserved.
2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be
3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file.
4*a03ca8b9SKrzysztof Kosiński
5*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/zucchini_integration.h"
6*a03ca8b9SKrzysztof Kosiński
7*a03ca8b9SKrzysztof Kosiński #include <utility>
8*a03ca8b9SKrzysztof Kosiński
9*a03ca8b9SKrzysztof Kosiński #include "base/logging.h"
10*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/buffer_view.h"
11*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/mapped_file.h"
12*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/patch_reader.h"
13*a03ca8b9SKrzysztof Kosiński
14*a03ca8b9SKrzysztof Kosiński namespace zucchini {
15*a03ca8b9SKrzysztof Kosiński
16*a03ca8b9SKrzysztof Kosiński namespace {
17*a03ca8b9SKrzysztof Kosiński
18*a03ca8b9SKrzysztof Kosiński struct FileNames {
FileNameszucchini::__anondc9f2f870111::FileNames19*a03ca8b9SKrzysztof Kosiński FileNames() : is_dummy(true) {
20*a03ca8b9SKrzysztof Kosiński // Use fake names.
21*a03ca8b9SKrzysztof Kosiński old_name = old_name.AppendASCII("old_name");
22*a03ca8b9SKrzysztof Kosiński new_name = new_name.AppendASCII("new_name");
23*a03ca8b9SKrzysztof Kosiński patch_name = patch_name.AppendASCII("patch_name");
24*a03ca8b9SKrzysztof Kosiński }
25*a03ca8b9SKrzysztof Kosiński
FileNameszucchini::__anondc9f2f870111::FileNames26*a03ca8b9SKrzysztof Kosiński FileNames(const base::FilePath& old_name,
27*a03ca8b9SKrzysztof Kosiński const base::FilePath& new_name,
28*a03ca8b9SKrzysztof Kosiński const base::FilePath& patch_name)
29*a03ca8b9SKrzysztof Kosiński : old_name(old_name),
30*a03ca8b9SKrzysztof Kosiński new_name(new_name),
31*a03ca8b9SKrzysztof Kosiński patch_name(patch_name),
32*a03ca8b9SKrzysztof Kosiński is_dummy(false) {}
33*a03ca8b9SKrzysztof Kosiński
34*a03ca8b9SKrzysztof Kosiński base::FilePath old_name;
35*a03ca8b9SKrzysztof Kosiński base::FilePath new_name;
36*a03ca8b9SKrzysztof Kosiński base::FilePath patch_name;
37*a03ca8b9SKrzysztof Kosiński
38*a03ca8b9SKrzysztof Kosiński // A flag to decide whether the filenames are only for error output.
39*a03ca8b9SKrzysztof Kosiński const bool is_dummy;
40*a03ca8b9SKrzysztof Kosiński };
41*a03ca8b9SKrzysztof Kosiński
GenerateCommon(base::File old_file,base::File new_file,base::File patch_file,const FileNames & names,bool force_keep,bool is_raw,std::string imposed_matches)42*a03ca8b9SKrzysztof Kosiński status::Code GenerateCommon(base::File old_file,
43*a03ca8b9SKrzysztof Kosiński base::File new_file,
44*a03ca8b9SKrzysztof Kosiński base::File patch_file,
45*a03ca8b9SKrzysztof Kosiński const FileNames& names,
46*a03ca8b9SKrzysztof Kosiński bool force_keep,
47*a03ca8b9SKrzysztof Kosiński bool is_raw,
48*a03ca8b9SKrzysztof Kosiński std::string imposed_matches) {
49*a03ca8b9SKrzysztof Kosiński MappedFileReader mapped_old(std::move(old_file));
50*a03ca8b9SKrzysztof Kosiński if (mapped_old.HasError()) {
51*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Error with file " << names.old_name.value() << ": "
52*a03ca8b9SKrzysztof Kosiński << mapped_old.error();
53*a03ca8b9SKrzysztof Kosiński return status::kStatusFileReadError;
54*a03ca8b9SKrzysztof Kosiński }
55*a03ca8b9SKrzysztof Kosiński
56*a03ca8b9SKrzysztof Kosiński MappedFileReader mapped_new(std::move(new_file));
57*a03ca8b9SKrzysztof Kosiński if (mapped_new.HasError()) {
58*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Error with file " << names.new_name.value() << ": "
59*a03ca8b9SKrzysztof Kosiński << mapped_new.error();
60*a03ca8b9SKrzysztof Kosiński return status::kStatusFileReadError;
61*a03ca8b9SKrzysztof Kosiński }
62*a03ca8b9SKrzysztof Kosiński
63*a03ca8b9SKrzysztof Kosiński status::Code result = status::kStatusSuccess;
64*a03ca8b9SKrzysztof Kosiński EnsemblePatchWriter patch_writer(mapped_old.region(), mapped_new.region());
65*a03ca8b9SKrzysztof Kosiński if (is_raw) {
66*a03ca8b9SKrzysztof Kosiński result = GenerateBufferRaw(mapped_old.region(), mapped_new.region(),
67*a03ca8b9SKrzysztof Kosiński &patch_writer);
68*a03ca8b9SKrzysztof Kosiński } else {
69*a03ca8b9SKrzysztof Kosiński result = GenerateBufferImposed(mapped_old.region(), mapped_new.region(),
70*a03ca8b9SKrzysztof Kosiński std::move(imposed_matches), &patch_writer);
71*a03ca8b9SKrzysztof Kosiński }
72*a03ca8b9SKrzysztof Kosiński if (result != status::kStatusSuccess) {
73*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Fatal error encountered when generating patch.";
74*a03ca8b9SKrzysztof Kosiński return result;
75*a03ca8b9SKrzysztof Kosiński }
76*a03ca8b9SKrzysztof Kosiński
77*a03ca8b9SKrzysztof Kosiński // By default, delete patch on destruction, to avoid having lingering files in
78*a03ca8b9SKrzysztof Kosiński // case of a failure. On Windows deletion can be done by the OS.
79*a03ca8b9SKrzysztof Kosiński MappedFileWriter mapped_patch(names.patch_name, std::move(patch_file),
80*a03ca8b9SKrzysztof Kosiński patch_writer.SerializedSize());
81*a03ca8b9SKrzysztof Kosiński if (mapped_patch.HasError()) {
82*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Error with file " << names.patch_name.value() << ": "
83*a03ca8b9SKrzysztof Kosiński << mapped_patch.error();
84*a03ca8b9SKrzysztof Kosiński return status::kStatusFileWriteError;
85*a03ca8b9SKrzysztof Kosiński }
86*a03ca8b9SKrzysztof Kosiński if (force_keep)
87*a03ca8b9SKrzysztof Kosiński mapped_patch.Keep();
88*a03ca8b9SKrzysztof Kosiński
89*a03ca8b9SKrzysztof Kosiński if (!patch_writer.SerializeInto(mapped_patch.region()))
90*a03ca8b9SKrzysztof Kosiński return status::kStatusPatchWriteError;
91*a03ca8b9SKrzysztof Kosiński
92*a03ca8b9SKrzysztof Kosiński // Successfully created patch. Explicitly request file to be kept.
93*a03ca8b9SKrzysztof Kosiński if (!mapped_patch.Keep())
94*a03ca8b9SKrzysztof Kosiński return status::kStatusFileWriteError;
95*a03ca8b9SKrzysztof Kosiński return status::kStatusSuccess;
96*a03ca8b9SKrzysztof Kosiński }
97*a03ca8b9SKrzysztof Kosiński
ApplyCommon(base::File old_file,base::File patch_file,base::File new_file,const FileNames & names,bool force_keep)98*a03ca8b9SKrzysztof Kosiński status::Code ApplyCommon(base::File old_file,
99*a03ca8b9SKrzysztof Kosiński base::File patch_file,
100*a03ca8b9SKrzysztof Kosiński base::File new_file,
101*a03ca8b9SKrzysztof Kosiński const FileNames& names,
102*a03ca8b9SKrzysztof Kosiński bool force_keep) {
103*a03ca8b9SKrzysztof Kosiński MappedFileReader mapped_patch(std::move(patch_file));
104*a03ca8b9SKrzysztof Kosiński if (mapped_patch.HasError()) {
105*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Error with file " << names.patch_name.value() << ": "
106*a03ca8b9SKrzysztof Kosiński << mapped_patch.error();
107*a03ca8b9SKrzysztof Kosiński return status::kStatusFileReadError;
108*a03ca8b9SKrzysztof Kosiński }
109*a03ca8b9SKrzysztof Kosiński
110*a03ca8b9SKrzysztof Kosiński auto patch_reader = EnsemblePatchReader::Create(mapped_patch.region());
111*a03ca8b9SKrzysztof Kosiński if (!patch_reader.has_value()) {
112*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Error reading patch header.";
113*a03ca8b9SKrzysztof Kosiński return status::kStatusPatchReadError;
114*a03ca8b9SKrzysztof Kosiński }
115*a03ca8b9SKrzysztof Kosiński
116*a03ca8b9SKrzysztof Kosiński MappedFileReader mapped_old(std::move(old_file));
117*a03ca8b9SKrzysztof Kosiński if (mapped_old.HasError()) {
118*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Error with file " << names.old_name.value() << ": "
119*a03ca8b9SKrzysztof Kosiński << mapped_old.error();
120*a03ca8b9SKrzysztof Kosiński return status::kStatusFileReadError;
121*a03ca8b9SKrzysztof Kosiński }
122*a03ca8b9SKrzysztof Kosiński
123*a03ca8b9SKrzysztof Kosiński PatchHeader header = patch_reader->header();
124*a03ca8b9SKrzysztof Kosiński // By default, delete output on destruction, to avoid having lingering files
125*a03ca8b9SKrzysztof Kosiński // in case of a failure. On Windows deletion can be done by the OS.
126*a03ca8b9SKrzysztof Kosiński MappedFileWriter mapped_new(names.new_name, std::move(new_file),
127*a03ca8b9SKrzysztof Kosiński header.new_size);
128*a03ca8b9SKrzysztof Kosiński if (mapped_new.HasError()) {
129*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Error with file " << names.new_name.value() << ": "
130*a03ca8b9SKrzysztof Kosiński << mapped_new.error();
131*a03ca8b9SKrzysztof Kosiński return status::kStatusFileWriteError;
132*a03ca8b9SKrzysztof Kosiński }
133*a03ca8b9SKrzysztof Kosiński if (force_keep)
134*a03ca8b9SKrzysztof Kosiński mapped_new.Keep();
135*a03ca8b9SKrzysztof Kosiński
136*a03ca8b9SKrzysztof Kosiński status::Code result =
137*a03ca8b9SKrzysztof Kosiński ApplyBuffer(mapped_old.region(), *patch_reader, mapped_new.region());
138*a03ca8b9SKrzysztof Kosiński if (result != status::kStatusSuccess) {
139*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Fatal error encountered while applying patch.";
140*a03ca8b9SKrzysztof Kosiński return result;
141*a03ca8b9SKrzysztof Kosiński }
142*a03ca8b9SKrzysztof Kosiński
143*a03ca8b9SKrzysztof Kosiński // Successfully patch |mapped_new|. Explicitly request file to be kept.
144*a03ca8b9SKrzysztof Kosiński if (!mapped_new.Keep())
145*a03ca8b9SKrzysztof Kosiński return status::kStatusFileWriteError;
146*a03ca8b9SKrzysztof Kosiński return status::kStatusSuccess;
147*a03ca8b9SKrzysztof Kosiński }
148*a03ca8b9SKrzysztof Kosiński
VerifyPatchCommon(base::File patch_file,base::FilePath patch_name)149*a03ca8b9SKrzysztof Kosiński status::Code VerifyPatchCommon(base::File patch_file,
150*a03ca8b9SKrzysztof Kosiński base::FilePath patch_name) {
151*a03ca8b9SKrzysztof Kosiński MappedFileReader mapped_patch(std::move(patch_file));
152*a03ca8b9SKrzysztof Kosiński if (mapped_patch.HasError()) {
153*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Error with file " << patch_name.value() << ": "
154*a03ca8b9SKrzysztof Kosiński << mapped_patch.error();
155*a03ca8b9SKrzysztof Kosiński return status::kStatusFileReadError;
156*a03ca8b9SKrzysztof Kosiński }
157*a03ca8b9SKrzysztof Kosiński auto patch_reader = EnsemblePatchReader::Create(mapped_patch.region());
158*a03ca8b9SKrzysztof Kosiński if (!patch_reader.has_value()) {
159*a03ca8b9SKrzysztof Kosiński LOG(ERROR) << "Error reading patch header.";
160*a03ca8b9SKrzysztof Kosiński return status::kStatusPatchReadError;
161*a03ca8b9SKrzysztof Kosiński }
162*a03ca8b9SKrzysztof Kosiński return status::kStatusSuccess;
163*a03ca8b9SKrzysztof Kosiński }
164*a03ca8b9SKrzysztof Kosiński
165*a03ca8b9SKrzysztof Kosiński } // namespace
166*a03ca8b9SKrzysztof Kosiński
Generate(base::File old_file,base::File new_file,base::File patch_file,bool force_keep,bool is_raw,std::string imposed_matches)167*a03ca8b9SKrzysztof Kosiński status::Code Generate(base::File old_file,
168*a03ca8b9SKrzysztof Kosiński base::File new_file,
169*a03ca8b9SKrzysztof Kosiński base::File patch_file,
170*a03ca8b9SKrzysztof Kosiński bool force_keep,
171*a03ca8b9SKrzysztof Kosiński bool is_raw,
172*a03ca8b9SKrzysztof Kosiński std::string imposed_matches) {
173*a03ca8b9SKrzysztof Kosiński const FileNames file_names;
174*a03ca8b9SKrzysztof Kosiński return GenerateCommon(std::move(old_file), std::move(new_file),
175*a03ca8b9SKrzysztof Kosiński std::move(patch_file), file_names, force_keep, is_raw,
176*a03ca8b9SKrzysztof Kosiński std::move(imposed_matches));
177*a03ca8b9SKrzysztof Kosiński }
178*a03ca8b9SKrzysztof Kosiński
Generate(const base::FilePath & old_path,const base::FilePath & new_path,const base::FilePath & patch_path,bool force_keep,bool is_raw,std::string imposed_matches)179*a03ca8b9SKrzysztof Kosiński status::Code Generate(const base::FilePath& old_path,
180*a03ca8b9SKrzysztof Kosiński const base::FilePath& new_path,
181*a03ca8b9SKrzysztof Kosiński const base::FilePath& patch_path,
182*a03ca8b9SKrzysztof Kosiński bool force_keep,
183*a03ca8b9SKrzysztof Kosiński bool is_raw,
184*a03ca8b9SKrzysztof Kosiński std::string imposed_matches) {
185*a03ca8b9SKrzysztof Kosiński using base::File;
186*a03ca8b9SKrzysztof Kosiński File old_file(old_path, File::FLAG_OPEN | File::FLAG_READ |
187*a03ca8b9SKrzysztof Kosiński base::File::FLAG_WIN_SHARE_DELETE);
188*a03ca8b9SKrzysztof Kosiński File new_file(new_path, File::FLAG_OPEN | File::FLAG_READ |
189*a03ca8b9SKrzysztof Kosiński base::File::FLAG_WIN_SHARE_DELETE);
190*a03ca8b9SKrzysztof Kosiński File patch_file(patch_path, File::FLAG_CREATE_ALWAYS | File::FLAG_READ |
191*a03ca8b9SKrzysztof Kosiński File::FLAG_WRITE |
192*a03ca8b9SKrzysztof Kosiński File::FLAG_WIN_SHARE_DELETE |
193*a03ca8b9SKrzysztof Kosiński File::FLAG_CAN_DELETE_ON_CLOSE);
194*a03ca8b9SKrzysztof Kosiński const FileNames file_names(old_path, new_path, patch_path);
195*a03ca8b9SKrzysztof Kosiński return GenerateCommon(std::move(old_file), std::move(new_file),
196*a03ca8b9SKrzysztof Kosiński std::move(patch_file), file_names, force_keep, is_raw,
197*a03ca8b9SKrzysztof Kosiński std::move(imposed_matches));
198*a03ca8b9SKrzysztof Kosiński }
199*a03ca8b9SKrzysztof Kosiński
Apply(base::File old_file,base::File patch_file,base::File new_file,bool force_keep)200*a03ca8b9SKrzysztof Kosiński status::Code Apply(base::File old_file,
201*a03ca8b9SKrzysztof Kosiński base::File patch_file,
202*a03ca8b9SKrzysztof Kosiński base::File new_file,
203*a03ca8b9SKrzysztof Kosiński bool force_keep) {
204*a03ca8b9SKrzysztof Kosiński const FileNames file_names;
205*a03ca8b9SKrzysztof Kosiński return ApplyCommon(std::move(old_file), std::move(patch_file),
206*a03ca8b9SKrzysztof Kosiński std::move(new_file), file_names, force_keep);
207*a03ca8b9SKrzysztof Kosiński }
208*a03ca8b9SKrzysztof Kosiński
Apply(const base::FilePath & old_path,const base::FilePath & patch_path,const base::FilePath & new_path,bool force_keep)209*a03ca8b9SKrzysztof Kosiński status::Code Apply(const base::FilePath& old_path,
210*a03ca8b9SKrzysztof Kosiński const base::FilePath& patch_path,
211*a03ca8b9SKrzysztof Kosiński const base::FilePath& new_path,
212*a03ca8b9SKrzysztof Kosiński bool force_keep) {
213*a03ca8b9SKrzysztof Kosiński using base::File;
214*a03ca8b9SKrzysztof Kosiński File old_file(old_path, File::FLAG_OPEN | File::FLAG_READ |
215*a03ca8b9SKrzysztof Kosiński base::File::FLAG_WIN_SHARE_DELETE);
216*a03ca8b9SKrzysztof Kosiński File patch_file(patch_path, File::FLAG_OPEN | File::FLAG_READ |
217*a03ca8b9SKrzysztof Kosiński base::File::FLAG_WIN_SHARE_DELETE);
218*a03ca8b9SKrzysztof Kosiński File new_file(new_path, File::FLAG_CREATE_ALWAYS | File::FLAG_READ |
219*a03ca8b9SKrzysztof Kosiński File::FLAG_WRITE | File::FLAG_WIN_SHARE_DELETE |
220*a03ca8b9SKrzysztof Kosiński File::FLAG_CAN_DELETE_ON_CLOSE);
221*a03ca8b9SKrzysztof Kosiński const FileNames file_names(old_path, new_path, patch_path);
222*a03ca8b9SKrzysztof Kosiński return ApplyCommon(std::move(old_file), std::move(patch_file),
223*a03ca8b9SKrzysztof Kosiński std::move(new_file), file_names, force_keep);
224*a03ca8b9SKrzysztof Kosiński }
225*a03ca8b9SKrzysztof Kosiński
VerifyPatch(base::File patch_file)226*a03ca8b9SKrzysztof Kosiński status::Code VerifyPatch(base::File patch_file) {
227*a03ca8b9SKrzysztof Kosiński return VerifyPatchCommon(std::move(patch_file), base::FilePath());
228*a03ca8b9SKrzysztof Kosiński }
229*a03ca8b9SKrzysztof Kosiński
VerifyPatch(const base::FilePath & patch_path)230*a03ca8b9SKrzysztof Kosiński status::Code VerifyPatch(const base::FilePath& patch_path) {
231*a03ca8b9SKrzysztof Kosiński using base::File;
232*a03ca8b9SKrzysztof Kosiński File patch_file(patch_path, File::FLAG_OPEN | File::FLAG_READ |
233*a03ca8b9SKrzysztof Kosiński base::File::FLAG_SHARE_DELETE);
234*a03ca8b9SKrzysztof Kosiński return VerifyPatchCommon(std::move(patch_file), patch_path);
235*a03ca8b9SKrzysztof Kosiński }
236*a03ca8b9SKrzysztof Kosiński
237*a03ca8b9SKrzysztof Kosiński } // namespace zucchini
238