blob: 8b7dcf166ac6d71fe0686bad9156ca3da8ebf683 [file] [log] [blame]
huangsf953e4072017-07-28 01:16:211// 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 "chrome/installer/zucchini/zucchini_commands.h"
6
Samuel Huange8d07b752017-08-21 16:05:257#include <stddef.h>
8#include <stdint.h>
9
huangs252600a2017-07-31 22:19:4810#include <iostream>
11#include <ostream>
12
13#include "base/command_line.h"
14#include "base/files/file.h"
15#include "base/files/file_path.h"
16#include "base/files/memory_mapped_file.h"
huangsf953e4072017-07-28 01:16:2117#include "base/logging.h"
huangs252600a2017-07-31 22:19:4818#include "base/macros.h"
19#include "chrome/installer/zucchini/buffer_view.h"
20#include "chrome/installer/zucchini/crc32.h"
21#include "chrome/installer/zucchini/io_utils.h"
Etienne Pierre-Doray73ed4232017-08-10 01:28:4122#include "chrome/installer/zucchini/patch_reader.h"
23#include "chrome/installer/zucchini/patch_writer.h"
Samuel Huangd943db62017-08-23 21:46:5724#include "chrome/installer/zucchini/zucchini_tools.h"
huangsf953e4072017-07-28 01:16:2125
26namespace {
27
huangs252600a2017-07-31 22:19:4828/******** MappedFileReader ********/
29
30// A file reader wrapper.
31class MappedFileReader {
32 public:
33 explicit MappedFileReader(const base::FilePath& file_name) {
34 is_ok_ = buffer_.Initialize(file_name);
35 if (!is_ok_) // This is also triggered if |file_name| is an empty file.
36 LOG(ERROR) << "Can't read file: " << file_name.value();
37 }
38 bool is_ok() const { return is_ok_; }
39 const uint8_t* data() const { return buffer_.data(); }
40 size_t length() const { return buffer_.length(); }
41 zucchini::ConstBufferView region() const { return {data(), length()}; }
42
43 private:
44 bool is_ok_;
45 base::MemoryMappedFile buffer_;
46
47 DISALLOW_COPY_AND_ASSIGN(MappedFileReader);
48};
49
50/******** MappedFileWriter ********/
51
52// A file writer wrapper.
53class MappedFileWriter {
54 public:
55 MappedFileWriter(const base::FilePath& file_name, size_t length) {
56 using base::File;
huangs252600a2017-07-31 22:19:4857 is_ok_ = buffer_.Initialize(
58 File(file_name,
59 File::FLAG_CREATE_ALWAYS | File::FLAG_READ | File::FLAG_WRITE),
60 {0, static_cast<int64_t>(length)},
61 base::MemoryMappedFile::READ_WRITE_EXTEND);
62 if (!is_ok_)
63 LOG(ERROR) << "Can't create file: " << file_name.value();
64 }
65 bool is_ok() const { return is_ok_; }
66 uint8_t* data() { return buffer_.data(); }
67 size_t length() const { return buffer_.length(); }
68 zucchini::MutableBufferView region() { return {data(), length()}; }
69
70 private:
71 bool is_ok_;
72 base::MemoryMappedFile buffer_;
73
74 DISALLOW_COPY_AND_ASSIGN(MappedFileWriter);
75};
huangsf953e4072017-07-28 01:16:2176
Etienne Pierre-Doray73ed4232017-08-10 01:28:4177/******** Command-line Switches ********/
78
Samuel Huangd943db62017-08-23 21:46:5779constexpr char kSwitchDump[] = "dump";
80constexpr char kSwitchRaw[] = "raw";
Etienne Pierre-Doray73ed4232017-08-10 01:28:4181
huangsf953e4072017-07-28 01:16:2182} // namespace
83
huangs252600a2017-07-31 22:19:4884zucchini::status::Code MainGen(MainParams params) {
85 CHECK_EQ(3U, params.file_paths.size());
86 MappedFileReader old_image(params.file_paths[0]);
87 if (!old_image.is_ok())
88 return zucchini::status::kStatusFileReadError;
89 MappedFileReader new_image(params.file_paths[1]);
90 if (!new_image.is_ok())
91 return zucchini::status::kStatusFileReadError;
92
Etienne Pierre-Doray73ed4232017-08-10 01:28:4193 zucchini::EnsemblePatchWriter patch_writer(old_image.region(),
94 new_image.region());
huangs252600a2017-07-31 22:19:4895
Etienne Pierre-Doray73ed4232017-08-10 01:28:4196 auto generate = params.command_line.HasSwitch(kSwitchRaw)
97 ? zucchini::GenerateRaw
98 : zucchini::GenerateEnsemble;
99 zucchini::status::Code status =
100 generate(old_image.region(), new_image.region(), &patch_writer);
101 if (status != zucchini::status::kStatusSuccess) {
102 params.out << "Fatal error encountered when generating patch." << std::endl;
103 return status;
104 }
105
106 MappedFileWriter patch(params.file_paths[2], patch_writer.SerializedSize());
huangs252600a2017-07-31 22:19:48107 if (!patch.is_ok())
108 return zucchini::status::kStatusFileWriteError;
109
Etienne Pierre-Doray73ed4232017-08-10 01:28:41110 if (!patch_writer.SerializeInto(patch.region()))
111 return zucchini::status::kStatusPatchWriteError;
112
huangsf953e4072017-07-28 01:16:21113 return zucchini::status::kStatusSuccess;
114}
115
huangs252600a2017-07-31 22:19:48116zucchini::status::Code MainApply(MainParams params) {
117 CHECK_EQ(3U, params.file_paths.size());
118 MappedFileReader old_image(params.file_paths[0]);
119 if (!old_image.is_ok())
120 return zucchini::status::kStatusFileReadError;
121 MappedFileReader patch(params.file_paths[1]);
122 if (!patch.is_ok())
123 return zucchini::status::kStatusFileReadError;
124
Etienne Pierre-Doray73ed4232017-08-10 01:28:41125 auto patch_reader = zucchini::EnsemblePatchReader::Create(patch.region());
126 if (!patch_reader.has_value()) {
127 params.err << "Error reading patch header." << std::endl;
128 return zucchini::status::kStatusPatchReadError;
129 }
130 zucchini::PatchHeader header = patch_reader->header();
huangs252600a2017-07-31 22:19:48131
Etienne Pierre-Doray73ed4232017-08-10 01:28:41132 MappedFileWriter new_image(params.file_paths[2], header.new_size);
huangs252600a2017-07-31 22:19:48133 if (!new_image.is_ok())
134 return zucchini::status::kStatusFileWriteError;
135
Etienne Pierre-Doray73ed4232017-08-10 01:28:41136 zucchini::status::Code status =
137 zucchini::Apply(old_image.region(), *patch_reader, new_image.region());
Samuel Huangd943db62017-08-23 21:46:57138 if (status != zucchini::status::kStatusSuccess)
Etienne Pierre-Doray73ed4232017-08-10 01:28:41139 params.err << "Fatal error encountered while applying patch." << std::endl;
Samuel Huangd943db62017-08-23 21:46:57140 return status;
141}
142
143zucchini::status::Code MainRead(MainParams params) {
144 CHECK_EQ(1U, params.file_paths.size());
145 MappedFileReader input(params.file_paths[0]);
146 if (!input.is_ok())
147 return zucchini::status::kStatusFileReadError;
148
149 bool do_dump = params.command_line.HasSwitch(kSwitchDump);
150 zucchini::status::Code status = zucchini::ReadReferences(
151 {input.data(), input.length()}, do_dump, params.out);
152 if (status != zucchini::status::kStatusSuccess)
153 params.err << "Fatal error found when dumping references." << std::endl;
154 return status;
huangs252600a2017-07-31 22:19:48155}
156
157zucchini::status::Code MainCrc32(MainParams params) {
158 CHECK_EQ(1U, params.file_paths.size());
159 MappedFileReader image(params.file_paths[0]);
160 if (!image.is_ok())
161 return zucchini::status::kStatusFileReadError;
162
163 uint32_t crc =
164 zucchini::CalculateCrc32(image.data(), image.data() + image.length());
165 params.out << "CRC32: " << zucchini::AsHex<8>(crc) << std::endl;
huangsf953e4072017-07-28 01:16:21166 return zucchini::status::kStatusSuccess;
167}