xref: /aosp_15_r20/external/zucchini/zucchini_integration.cc (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
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