zucchini_integration.cc 8.8 KB

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