xref: /aosp_15_r20/external/zucchini/zucchini_integration.cc (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
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_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 
14 namespace zucchini {
15 
16 namespace {
17 
18 struct FileNames {
FileNameszucchini::__anondc9f2f870111::FileNames19   FileNames() : is_dummy(true) {
20     // Use fake names.
21     old_name = old_name.AppendASCII("old_name");
22     new_name = new_name.AppendASCII("new_name");
23     patch_name = patch_name.AppendASCII("patch_name");
24   }
25 
FileNameszucchini::__anondc9f2f870111::FileNames26   FileNames(const base::FilePath& old_name,
27             const base::FilePath& new_name,
28             const base::FilePath& patch_name)
29       : old_name(old_name),
30         new_name(new_name),
31         patch_name(patch_name),
32         is_dummy(false) {}
33 
34   base::FilePath old_name;
35   base::FilePath new_name;
36   base::FilePath patch_name;
37 
38   // A flag to decide whether the filenames are only for error output.
39   const bool is_dummy;
40 };
41 
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 status::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();
53     return status::kStatusFileReadError;
54   }
55 
56   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 
ApplyCommon(base::File old_file,base::File patch_file,base::File new_file,const FileNames & names,bool force_keep)98 status::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());
111   if (!patch_reader.has_value()) {
112     LOG(ERROR) << "Error reading patch header.";
113     return status::kStatusPatchReadError;
114   }
115 
116   MappedFileReader mapped_old(std::move(old_file));
117   if (mapped_old.HasError()) {
118     LOG(ERROR) << "Error with file " << names.old_name.value() << ": "
119                << mapped_old.error();
120     return status::kStatusFileReadError;
121   }
122 
123   PatchHeader header = patch_reader->header();
124   // 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.
126   MappedFileWriter mapped_new(names.new_name, std::move(new_file),
127                               header.new_size);
128   if (mapped_new.HasError()) {
129     LOG(ERROR) << "Error with file " << names.new_name.value() << ": "
130                << mapped_new.error();
131     return status::kStatusFileWriteError;
132   }
133   if (force_keep)
134     mapped_new.Keep();
135 
136   status::Code result =
137       ApplyBuffer(mapped_old.region(), *patch_reader, mapped_new.region());
138   if (result != status::kStatusSuccess) {
139     LOG(ERROR) << "Fatal error encountered while applying patch.";
140     return result;
141   }
142 
143   // Successfully patch |mapped_new|. Explicitly request file to be kept.
144   if (!mapped_new.Keep())
145     return status::kStatusFileWriteError;
146   return status::kStatusSuccess;
147 }
148 
VerifyPatchCommon(base::File patch_file,base::FilePath patch_name)149 status::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 
165 }  // namespace
166 
Generate(base::File old_file,base::File new_file,base::File patch_file,bool force_keep,bool is_raw,std::string imposed_matches)167 status::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 
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 status::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;
186   File old_file(old_path, File::FLAG_OPEN | File::FLAG_READ |
187                               base::File::FLAG_WIN_SHARE_DELETE);
188   File new_file(new_path, File::FLAG_OPEN | File::FLAG_READ |
189                               base::File::FLAG_WIN_SHARE_DELETE);
190   File patch_file(patch_path, File::FLAG_CREATE_ALWAYS | File::FLAG_READ |
191                                   File::FLAG_WRITE |
192                                   File::FLAG_WIN_SHARE_DELETE |
193                                   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 
Apply(base::File old_file,base::File patch_file,base::File new_file,bool force_keep)200 status::Code Apply(base::File old_file,
201                    base::File patch_file,
202                    base::File new_file,
203                    bool force_keep) {
204   const FileNames file_names;
205   return ApplyCommon(std::move(old_file), std::move(patch_file),
206                      std::move(new_file), file_names, force_keep);
207 }
208 
Apply(const base::FilePath & old_path,const base::FilePath & patch_path,const base::FilePath & new_path,bool force_keep)209 status::Code Apply(const base::FilePath& old_path,
210                    const base::FilePath& patch_path,
211                    const base::FilePath& new_path,
212                    bool force_keep) {
213   using base::File;
214   File old_file(old_path, File::FLAG_OPEN | File::FLAG_READ |
215                               base::File::FLAG_WIN_SHARE_DELETE);
216   File patch_file(patch_path, File::FLAG_OPEN | File::FLAG_READ |
217                                   base::File::FLAG_WIN_SHARE_DELETE);
218   File new_file(new_path, File::FLAG_CREATE_ALWAYS | File::FLAG_READ |
219                               File::FLAG_WRITE | File::FLAG_WIN_SHARE_DELETE |
220                               File::FLAG_CAN_DELETE_ON_CLOSE);
221   const FileNames file_names(old_path, new_path, patch_path);
222   return ApplyCommon(std::move(old_file), std::move(patch_file),
223                      std::move(new_file), file_names, force_keep);
224 }
225 
VerifyPatch(base::File patch_file)226 status::Code VerifyPatch(base::File patch_file) {
227   return VerifyPatchCommon(std::move(patch_file), base::FilePath());
228 }
229 
VerifyPatch(const base::FilePath & patch_path)230 status::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 
237 }  // namespace zucchini
238