Commit 252600a1 authored by huangs's avatar huangs Committed by Commit Bot

[Zucchini] Add file read/write functions in zucchini_commands.c; add Zucchini-crc32.

More details:
- Injecting std::cout and std::cerr into Main*() functions.
- Add MainParams to simplify interfaces of Main*() functions.
- Add skeletal file reads and dummy file write to Zucchini-gen and
  Zucchini-apply.

Bug: 729154
Change-Id: I35d11e99b1863e77dee084635589022a6862d6e8
Reviewed-on: https://chromium-review.googlesource.com/592053
Commit-Queue: Samuel Huang <huangs@chromium.org>
Reviewed-by: default avatarGreg Thompson <grt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#490807}
parent 6a19f321
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <stddef.h> #include <stddef.h>
#include <memory> #include <memory>
#include <ostream>
#include <vector> #include <vector>
#include "base/command_line.h" #include "base/command_line.h"
...@@ -50,8 +51,9 @@ struct Command { ...@@ -50,8 +51,9 @@ struct Command {
/******** List of Zucchini commands ********/ /******** List of Zucchini commands ********/
constexpr Command kCommands[] = { constexpr Command kCommands[] = {
{"gen", "-gen <old_file> <new_file> <patch_file>", 3, MainGen}, {"gen", "-gen <old_file> <new_file> <patch_file>", 3, &MainGen},
{"apply", "-apply <old_file> <patch_file> <new_file>", 3, MainApply}, {"apply", "-apply <old_file> <patch_file> <new_file>", 3, &MainApply},
{"crc32", "-crc32 <file>", 1, &MainCrc32},
}; };
/******** ScopedResourceUsageTracker ********/ /******** ScopedResourceUsageTracker ********/
...@@ -128,10 +130,10 @@ bool CheckAndGetFilePathParams(const base::CommandLine& command_line, ...@@ -128,10 +130,10 @@ bool CheckAndGetFilePathParams(const base::CommandLine& command_line,
} }
// Prints main Zucchini usage text. // Prints main Zucchini usage text.
void PrintUsage(std::ostream& out) { void PrintUsage(std::ostream& err) {
out << "Usage:" << std::endl; err << "Usage:" << std::endl;
for (const Command& command : kCommands) for (const Command& command : kCommands)
out << " zucchini " << command.usage << std::endl; err << " zucchini " << command.usage << std::endl;
} }
} // namespace } // namespace
...@@ -139,7 +141,8 @@ void PrintUsage(std::ostream& out) { ...@@ -139,7 +141,8 @@ void PrintUsage(std::ostream& out) {
/******** Exported Functions ********/ /******** Exported Functions ********/
zucchini::status::Code RunZucchiniCommand(const base::CommandLine& command_line, zucchini::status::Code RunZucchiniCommand(const base::CommandLine& command_line,
std::ostream& out) { std::ostream& out,
std::ostream& err) {
// Look for a command with name that matches input. // Look for a command with name that matches input.
const Command* command_use = nullptr; const Command* command_use = nullptr;
for (const Command& command : kCommands) { for (const Command& command : kCommands) {
...@@ -154,24 +157,24 @@ zucchini::status::Code RunZucchiniCommand(const base::CommandLine& command_line, ...@@ -154,24 +157,24 @@ zucchini::status::Code RunZucchiniCommand(const base::CommandLine& command_line,
// Expect exactly 1 matching command. If 0 or >= 2, print usage and quit. // Expect exactly 1 matching command. If 0 or >= 2, print usage and quit.
if (!command_use) { if (!command_use) {
out << "Must have exactly one of:" << std::endl; err << "Must have exactly one of:" << std::endl;
out << " ["; err << " [";
zucchini::PrefixSep sep(", "); zucchini::PrefixSep sep(", ");
for (const Command& command : kCommands) for (const Command& command : kCommands)
out << sep << "-" << command.name; err << sep << "-" << command.name;
out << "]" << std::endl; err << "]" << std::endl;
PrintUsage(out); PrintUsage(err);
return zucchini::status::kStatusInvalidParam; return zucchini::status::kStatusInvalidParam;
} }
// Try to parse filename arguments. On failure, print usage and quit. // Try to parse filename arguments. On failure, print usage and quit.
std::vector<base::FilePath> paths; std::vector<base::FilePath> paths;
if (!CheckAndGetFilePathParams(command_line, command_use->num_args, &paths)) { if (!CheckAndGetFilePathParams(command_line, command_use->num_args, &paths)) {
out << command_use->usage << std::endl; err << command_use->usage << std::endl;
PrintUsage(out); PrintUsage(err);
return zucchini::status::kStatusInvalidParam; return zucchini::status::kStatusInvalidParam;
} }
ScopedResourceUsageTracker resource_usage_tracker; ScopedResourceUsageTracker resource_usage_tracker;
return command_use->command_function(command_line, paths); return command_use->command_function({command_line, paths, out, err});
} }
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#ifndef CHROME_INSTALLER_ZUCCHINI_MAIN_UTILS_H_ #ifndef CHROME_INSTALLER_ZUCCHINI_MAIN_UTILS_H_
#define CHROME_INSTALLER_ZUCCHINI_MAIN_UTILS_H_ #define CHROME_INSTALLER_ZUCCHINI_MAIN_UTILS_H_
#include <ostream> #include <iosfwd>
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "chrome/installer/zucchini/zucchini.h" #include "chrome/installer/zucchini/zucchini.h"
...@@ -26,9 +26,10 @@ class CommandLine; ...@@ -26,9 +26,10 @@ class CommandLine;
// 3. Add a new entry into |kCommands| in main_utils.cc. // 3. Add a new entry into |kCommands| in main_utils.cc.
// Searches |command_line| for Zucchini commands. If a unique command is found, // Searches |command_line| for Zucchini commands. If a unique command is found,
// runs it and logs resource usage. Otherwise prints help message to |out|. // runs it (passes |out| and |err|), and logs resource usage. Otherwise prints
// Returns Zucchini status code for error handling. // help message to |err|. Returns Zucchini status code for error handling.
zucchini::status::Code RunZucchiniCommand(const base::CommandLine& command_line, zucchini::status::Code RunZucchiniCommand(const base::CommandLine& command_line,
std::ostream& out); std::ostream& out,
std::ostream& err);
#endif // CHROME_INSTALLER_ZUCCHINI_MAIN_UTILS_H_ #endif // CHROME_INSTALLER_ZUCCHINI_MAIN_UTILS_H_
...@@ -16,6 +16,8 @@ namespace status { ...@@ -16,6 +16,8 @@ namespace status {
enum Code { enum Code {
kStatusSuccess = 0, kStatusSuccess = 0,
kStatusInvalidParam = 1, kStatusInvalidParam = 1,
kStatusFileReadError = 2,
kStatusFileWriteError = 3,
}; };
} // namespace status } // namespace status
......
...@@ -4,24 +4,119 @@ ...@@ -4,24 +4,119 @@
#include "chrome/installer/zucchini/zucchini_commands.h" #include "chrome/installer/zucchini/zucchini_commands.h"
#include <iostream>
#include <ostream>
#include "base/command_line.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/memory_mapped_file.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h"
#include "chrome/installer/zucchini/buffer_view.h"
#include "chrome/installer/zucchini/crc32.h"
#include "chrome/installer/zucchini/io_utils.h"
namespace { namespace {
// TODO(huangs): File I/O utilities. /******** MappedFileReader ********/
// A file reader wrapper.
class MappedFileReader {
public:
explicit MappedFileReader(const base::FilePath& file_name) {
is_ok_ = buffer_.Initialize(file_name);
if (!is_ok_) // This is also triggered if |file_name| is an empty file.
LOG(ERROR) << "Can't read file: " << file_name.value();
}
bool is_ok() const { return is_ok_; }
const uint8_t* data() const { return buffer_.data(); }
size_t length() const { return buffer_.length(); }
zucchini::ConstBufferView region() const { return {data(), length()}; }
private:
bool is_ok_;
base::MemoryMappedFile buffer_;
DISALLOW_COPY_AND_ASSIGN(MappedFileReader);
};
/******** MappedFileWriter ********/
// A file writer wrapper.
class MappedFileWriter {
public:
MappedFileWriter(const base::FilePath& file_name, size_t length) {
using base::File;
CHECK_LE(length, static_cast<uint64_t>(INT64_MAX));
is_ok_ = buffer_.Initialize(
File(file_name,
File::FLAG_CREATE_ALWAYS | File::FLAG_READ | File::FLAG_WRITE),
{0, static_cast<int64_t>(length)},
base::MemoryMappedFile::READ_WRITE_EXTEND);
if (!is_ok_)
LOG(ERROR) << "Can't create file: " << file_name.value();
}
bool is_ok() const { return is_ok_; }
uint8_t* data() { return buffer_.data(); }
size_t length() const { return buffer_.length(); }
zucchini::MutableBufferView region() { return {data(), length()}; }
private:
bool is_ok_;
base::MemoryMappedFile buffer_;
DISALLOW_COPY_AND_ASSIGN(MappedFileWriter);
};
} // namespace } // namespace
zucchini::status::Code MainGen(const base::CommandLine& command_line, zucchini::status::Code MainGen(MainParams params) {
const std::vector<base::FilePath>& fnames) { CHECK_EQ(3U, params.file_paths.size());
CHECK_EQ(3U, fnames.size()); MappedFileReader old_image(params.file_paths[0]);
if (!old_image.is_ok())
return zucchini::status::kStatusFileReadError;
MappedFileReader new_image(params.file_paths[1]);
if (!new_image.is_ok())
return zucchini::status::kStatusFileReadError;
// TODO(etiennep): Implement. // TODO(etiennep): Implement.
// Dummy output as placeholder.
MappedFileWriter patch(params.file_paths[2], 256);
if (!patch.is_ok())
return zucchini::status::kStatusFileWriteError;
return zucchini::status::kStatusSuccess; return zucchini::status::kStatusSuccess;
} }
zucchini::status::Code MainApply(const base::CommandLine& command_line, zucchini::status::Code MainApply(MainParams params) {
const std::vector<base::FilePath>& fnames) { CHECK_EQ(3U, params.file_paths.size());
CHECK_EQ(3U, fnames.size()); MappedFileReader old_image(params.file_paths[0]);
if (!old_image.is_ok())
return zucchini::status::kStatusFileReadError;
MappedFileReader patch(params.file_paths[1]);
if (!patch.is_ok())
return zucchini::status::kStatusFileReadError;
// TODO(etiennep): Implement. // TODO(etiennep): Implement.
// Dummy output as placeholder.
MappedFileWriter new_image(params.file_paths[2], 256);
if (!new_image.is_ok())
return zucchini::status::kStatusFileWriteError;
return zucchini::status::kStatusSuccess;
}
zucchini::status::Code MainCrc32(MainParams params) {
CHECK_EQ(1U, params.file_paths.size());
MappedFileReader image(params.file_paths[0]);
if (!image.is_ok())
return zucchini::status::kStatusFileReadError;
uint32_t crc =
zucchini::CalculateCrc32(image.data(), image.data() + image.length());
params.out << "CRC32: " << zucchini::AsHex<8>(crc) << std::endl;
return zucchini::status::kStatusSuccess; return zucchini::status::kStatusSuccess;
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef CHROME_INSTALLER_ZUCCHINI_ZUCCHINI_COMMANDS_H_ #ifndef CHROME_INSTALLER_ZUCCHINI_ZUCCHINI_COMMANDS_H_
#define CHROME_INSTALLER_ZUCCHINI_ZUCCHINI_COMMANDS_H_ #define CHROME_INSTALLER_ZUCCHINI_ZUCCHINI_COMMANDS_H_
#include <iosfwd>
#include <vector> #include <vector>
#include "base/files/file_path.h" #include "base/files/file_path.h"
...@@ -18,17 +19,24 @@ class CommandLine; ...@@ -18,17 +19,24 @@ class CommandLine;
} // namespace base } // namespace base
// Aggregated parameter for Main*() functions, to simplify interface.
struct MainParams {
const base::CommandLine& command_line;
const std::vector<base::FilePath>& file_paths;
std::ostream& out;
std::ostream& err;
};
// Signature of a Zucchini Command Function. // Signature of a Zucchini Command Function.
using CommandFunction = using CommandFunction = zucchini::status::Code (*)(MainParams);
zucchini::status::Code (*)(const base::CommandLine&,
const std::vector<base::FilePath>&);
// Command Function: Patch generation. // Command Function: Patch generation.
zucchini::status::Code MainGen(const base::CommandLine& command_line, zucchini::status::Code MainGen(MainParams params);
const std::vector<base::FilePath>& fnames);
// Command Function: Patch application. // Command Function: Patch application.
zucchini::status::Code MainApply(const base::CommandLine& command_line, zucchini::status::Code MainApply(MainParams params);
const std::vector<base::FilePath>& fnames);
// Command Function: Compute CRC-32 of a file.
zucchini::status::Code MainCrc32(MainParams params);
#endif // CHROME_INSTALLER_ZUCCHINI_ZUCCHINI_COMMANDS_H_ #endif // CHROME_INSTALLER_ZUCCHINI_ZUCCHINI_COMMANDS_H_
...@@ -44,5 +44,6 @@ int main(int argc, const char* argv[]) { ...@@ -44,5 +44,6 @@ int main(int argc, const char* argv[]) {
*base::CommandLine::ForCurrentProcess(); *base::CommandLine::ForCurrentProcess();
InitLogging(); InitLogging();
InitErrorHandling(command_line); InitErrorHandling(command_line);
return static_cast<int>(RunZucchiniCommand(command_line, std::cerr)); return static_cast<int>(
RunZucchiniCommand(command_line, std::cout, std::cerr));
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment