Chromium Code Reviews| Index: chrome/browser/component_updater/component_patcher_operation.cc |
| diff --git a/chrome/browser/component_updater/component_patcher_operation.cc b/chrome/browser/component_updater/component_patcher_operation.cc |
| index 6b86d9fc8a6dc241caa3db8eced617f6e5887f3b..74d27351499f5fa17acf3e2c7b89c82e4ea2bc35 100644 |
| --- a/chrome/browser/component_updater/component_patcher_operation.cc |
| +++ b/chrome/browser/component_updater/component_patcher_operation.cc |
| @@ -7,6 +7,7 @@ |
| #include <string> |
| #include <vector> |
| +#include "base/bind.h" |
| #include "base/file_util.h" |
| #include "base/files/memory_mapped_file.h" |
| #include "base/json/json_file_value_serializer.h" |
| @@ -15,11 +16,17 @@ |
| #include "base/strings/string_number_conversions.h" |
| #include "chrome/browser/component_updater/component_patcher.h" |
| #include "chrome/browser/component_updater/component_updater_service.h" |
| +#include "chrome/common/chrome_utility_messages.h" |
| #include "chrome/common/extensions/extension_constants.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/utility_process_host.h" |
| +#include "courgette/courgette.h" |
| +#include "courgette/third_party/bsdiff.h" |
| #include "crypto/secure_hash.h" |
| #include "crypto/sha2.h" |
| #include "crypto/signature_verifier.h" |
| #include "extensions/common/crx_file.h" |
| +#include "ipc/ipc_message_macros.h" |
| #include "third_party/zlib/google/zip.h" |
| using crypto::SecureHash; |
| @@ -34,56 +41,160 @@ const char kOutput[] = "output"; |
| const char kPatch[] = "patch"; |
| const char kSha256[] = "sha256"; |
| +// The integer offset disambiguates between overlapping error ranges. |
| +const int kCourgetteErrorOffset = 300; |
| +const int kBsdiffErrorOffset = 600; |
| + |
| +class CourgetteTraits : public DeltaUpdateOpPatchStrategy { |
| + public: |
| + virtual int GetErrorOffset() const OVERRIDE; |
| + virtual int GetSuccessCode() const OVERRIDE; |
| + virtual IPC::Message* GetPatchMessage( |
| + base::FilePath input_abs_path, |
| + base::FilePath patch_abs_path, |
| + base::FilePath output_abs_path) OVERRIDE; |
| + virtual int Patch(base::FilePath input_abs_path, |
| + base::FilePath patch_abs_path, |
| + base::FilePath output_abs_path) OVERRIDE; |
| +}; |
| + |
| +int CourgetteTraits::GetErrorOffset() const { |
| + return kCourgetteErrorOffset; |
| +} |
| + |
| +int CourgetteTraits::GetSuccessCode() const { |
| + return courgette::C_OK; |
| +} |
| + |
| +IPC::Message* CourgetteTraits::GetPatchMessage(base::FilePath input_abs_path, |
| + base::FilePath patch_abs_path, |
| + base::FilePath output_abs_path) { |
| + return new ChromeUtilityMsg_PatchFileCourgette(input_abs_path, |
| + patch_abs_path, |
| + output_abs_path); |
| +} |
| + |
| +int CourgetteTraits::Patch(base::FilePath input_abs_path, |
| + base::FilePath patch_abs_path, |
| + base::FilePath output_abs_path) { |
| + return courgette::ApplyEnsemblePatch(input_abs_path.value().c_str(), |
| + patch_abs_path.value().c_str(), |
| + output_abs_path.value().c_str()); |
| +} |
| + |
| +class BsdiffTraits : public DeltaUpdateOpPatchStrategy { |
| + public: |
| + virtual int GetErrorOffset() const OVERRIDE; |
| + virtual int GetSuccessCode() const OVERRIDE; |
| + virtual IPC::Message* GetPatchMessage( |
| + base::FilePath input_abs_path, |
| + base::FilePath patch_abs_path, |
| + base::FilePath output_abs_path) OVERRIDE; |
| + virtual int Patch(base::FilePath input_abs_path, |
| + base::FilePath patch_abs_path, |
| + base::FilePath output_abs_path) OVERRIDE; |
| +}; |
| + |
| +int BsdiffTraits::GetErrorOffset() const { |
| + return kBsdiffErrorOffset; |
| +} |
| + |
| +int BsdiffTraits::GetSuccessCode() const { |
| + return courgette::OK; |
| +} |
| + |
| +IPC::Message* BsdiffTraits::GetPatchMessage(base::FilePath input_abs_path, |
| + base::FilePath patch_abs_path, |
| + base::FilePath output_abs_path) { |
| + return new ChromeUtilityMsg_PatchFileBsdiff(input_abs_path, |
| + patch_abs_path, |
| + output_abs_path); |
| +} |
| + |
| +int BsdiffTraits::Patch(base::FilePath input_abs_path, |
| + base::FilePath patch_abs_path, |
| + base::FilePath output_abs_path) { |
| + return courgette::ApplyBinaryPatch(input_abs_path, |
| + patch_abs_path, |
| + output_abs_path); |
| +} |
| + |
| } // namespace |
| -DeltaUpdateOp* CreateDeltaUpdateOp(base::DictionaryValue* command) { |
| - std::string operation; |
| - if (!command->GetString(kOp, &operation)) |
| - return NULL; |
| - if (operation == "copy") |
| +DeltaUpdateOpPatchStrategy::~DeltaUpdateOpPatchStrategy() { |
| +} |
| + |
| +DeltaUpdateOp* CreateDeltaUpdateOp(const std::string& operation) { |
| + if (operation == "copy") { |
| return new DeltaUpdateOpCopy(); |
| - else if (operation == "create") |
| + } else if (operation == "create") { |
| return new DeltaUpdateOpCreate(); |
| - else if (operation == "bsdiff") |
| - return new DeltaUpdateOpPatchBsdiff(); |
| - else if (operation == "courgette") |
| - return new DeltaUpdateOpPatchCourgette(); |
| + } else if (operation == "bsdiff") { |
| + scoped_ptr<DeltaUpdateOpPatchStrategy> traits(new BsdiffTraits()); |
| + return new DeltaUpdateOpPatch(traits.Pass()); |
| + } else if (operation == "courgette") { |
| + scoped_ptr<DeltaUpdateOpPatchStrategy> traits(new CourgetteTraits()); |
| + return new DeltaUpdateOpPatch(traits.Pass()); |
| + } |
| return NULL; |
| } |
| -DeltaUpdateOp::DeltaUpdateOp() {} |
| +DeltaUpdateOp* CreateDeltaUpdateOp(const base::DictionaryValue& command) { |
| + std::string operation; |
| + if (!command.GetString(kOp, &operation)) |
| + return NULL; |
| + return CreateDeltaUpdateOp(operation); |
| +} |
| + |
| +DeltaUpdateOp::DeltaUpdateOp() : in_process_(false) {} |
| DeltaUpdateOp::~DeltaUpdateOp() {} |
| -ComponentUnpacker::Error DeltaUpdateOp::Run(base::DictionaryValue* command_args, |
| - const base::FilePath& input_dir, |
| - const base::FilePath& unpack_dir, |
| - ComponentPatcher* patcher, |
| - ComponentInstaller* installer, |
| - int* error) { |
| +void DeltaUpdateOp::Run( |
| + const base::DictionaryValue* command_args, |
| + const base::FilePath& input_dir, |
| + const base::FilePath& unpack_dir, |
| + ComponentInstaller* installer, |
| + bool in_process, |
| + const ComponentUnpacker::Callback& callback, |
| + scoped_refptr<base::SequencedTaskRunner> task_runner) { |
| + callback_ = callback; |
| + in_process_ = in_process; |
| + task_runner_ = task_runner; |
| std::string output_rel_path; |
| if (!command_args->GetString(kOutput, &output_rel_path) || |
| - !command_args->GetString(kSha256, &output_sha256_)) |
| - return ComponentUnpacker::kDeltaBadCommands; |
| + !command_args->GetString(kSha256, &output_sha256_)) { |
| + DoneRunning(ComponentUnpacker::kDeltaBadCommands, 0); |
| + return; |
| + } |
| output_abs_path_ = unpack_dir.Append( |
| base::FilePath::FromUTF8Unsafe(output_rel_path)); |
| ComponentUnpacker::Error parse_result = DoParseArguments( |
| command_args, input_dir, installer); |
| - if (parse_result != ComponentUnpacker::kNone) |
| - return parse_result; |
| + if (parse_result != ComponentUnpacker::kNone) { |
| + DoneRunning(parse_result, 0); |
| + return; |
| + } |
| const base::FilePath parent = output_abs_path_.DirName(); |
| if (!base::DirectoryExists(parent)) { |
| - if (!base::CreateDirectory(parent)) |
| - return ComponentUnpacker::kIoError; |
| + if (!base::CreateDirectory(parent)) { |
| + DoneRunning(ComponentUnpacker::kIoError, 0); |
| + return; |
| + } |
| } |
| - ComponentUnpacker::Error run_result = DoRun(patcher, error); |
| - if (run_result != ComponentUnpacker::kNone) |
| - return run_result; |
| + DoRun(base::Bind(&DeltaUpdateOp::DoneRunning, |
| + scoped_refptr<DeltaUpdateOp>(this))); |
| +} |
| - return CheckHash(); |
| +void DeltaUpdateOp::DoneRunning(ComponentUnpacker::Error error, |
| + int extended_error) { |
| + if (error == ComponentUnpacker::kNone) |
| + error = CheckHash(); |
| + task_runner_->PostTask(FROM_HERE, |
| + base::Bind(callback_, error, extended_error)); |
| } |
| // Uses the hash as a checksum to confirm that the file now residing in the |
| @@ -108,10 +219,16 @@ ComponentUnpacker::Error DeltaUpdateOp::CheckHash() { |
| return ComponentUnpacker::kNone; |
| } |
| +bool DeltaUpdateOp::InProcess() { |
| + return in_process_; |
| +} |
| + |
| DeltaUpdateOpCopy::DeltaUpdateOpCopy() {} |
| +DeltaUpdateOpCopy::~DeltaUpdateOpCopy() {} |
| + |
| ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments( |
| - base::DictionaryValue* command_args, |
| + const base::DictionaryValue* command_args, |
| const base::FilePath& input_dir, |
| ComponentInstaller* installer) { |
| std::string input_rel_path; |
| @@ -124,19 +241,19 @@ ComponentUnpacker::Error DeltaUpdateOpCopy::DoParseArguments( |
| return ComponentUnpacker::kNone; |
| } |
| -ComponentUnpacker::Error DeltaUpdateOpCopy::DoRun(ComponentPatcher*, |
| - int* error) { |
| - *error = 0; |
| +void DeltaUpdateOpCopy::DoRun(const ComponentUnpacker::Callback& callback) { |
| if (!base::CopyFile(input_abs_path_, output_abs_path_)) |
| - return ComponentUnpacker::kDeltaOperationFailure; |
| - |
| - return ComponentUnpacker::kNone; |
| + callback.Run(ComponentUnpacker::kDeltaOperationFailure, 0); |
| + else |
| + callback.Run(ComponentUnpacker::kNone, 0); |
| } |
| DeltaUpdateOpCreate::DeltaUpdateOpCreate() {} |
| +DeltaUpdateOpCreate::~DeltaUpdateOpCreate() {} |
| + |
| ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments( |
| - base::DictionaryValue* command_args, |
| + const base::DictionaryValue* command_args, |
| const base::FilePath& input_dir, |
| ComponentInstaller* installer) { |
| std::string patch_rel_path; |
| @@ -149,19 +266,24 @@ ComponentUnpacker::Error DeltaUpdateOpCreate::DoParseArguments( |
| return ComponentUnpacker::kNone; |
| } |
| -ComponentUnpacker::Error DeltaUpdateOpCreate::DoRun(ComponentPatcher*, |
| - int* error) { |
| - *error = 0; |
| +void DeltaUpdateOpCreate::DoRun(const ComponentUnpacker::Callback& callback) { |
| if (!base::Move(patch_abs_path_, output_abs_path_)) |
| - return ComponentUnpacker::kDeltaOperationFailure; |
| + callback.Run(ComponentUnpacker::kDeltaOperationFailure, 0); |
| + else |
| + callback.Run(ComponentUnpacker::kNone, 0); |
| +} |
| - return ComponentUnpacker::kNone; |
| + |
| +DeltaUpdateOpPatch::DeltaUpdateOpPatch( |
| + scoped_ptr<DeltaUpdateOpPatchStrategy> traits) { |
|
Sorin Jianu
2014/02/28 01:53:53
need to rename the traits variables throughout.
waffles
2014/02/28 17:14:09
Done.
|
| + traits_ = traits.Pass(); |
| } |
| -DeltaUpdateOpPatchBsdiff::DeltaUpdateOpPatchBsdiff() {} |
| +DeltaUpdateOpPatch::~DeltaUpdateOpPatch() { |
| +} |
| -ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoParseArguments( |
| - base::DictionaryValue* command_args, |
| +ComponentUnpacker::Error DeltaUpdateOpPatch::DoParseArguments( |
| + const base::DictionaryValue* command_args, |
| const base::FilePath& input_dir, |
| ComponentInstaller* installer) { |
| std::string patch_rel_path; |
| @@ -179,47 +301,63 @@ ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoParseArguments( |
| return ComponentUnpacker::kNone; |
| } |
| -ComponentUnpacker::Error DeltaUpdateOpPatchBsdiff::DoRun( |
| - ComponentPatcher* patcher, |
| - int* error) { |
| - *error = 0; |
| - return patcher->Patch(ComponentPatcher::kPatchTypeBsdiff, |
| - input_abs_path_, |
| - patch_abs_path_, |
| - output_abs_path_, |
| - error); |
| +void DeltaUpdateOpPatch::DoRun(const ComponentUnpacker::Callback& callback) { |
| + callback_ = callback; |
| + if (!InProcess()) { |
| + content::BrowserThread::PostTask( |
| + content::BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&DeltaUpdateOpPatch::StartProcess, base::Unretained(this))); |
| + return; |
| + } |
| + const int result = traits_->Patch(input_abs_path_, |
| + patch_abs_path_, |
| + output_abs_path_); |
| + if (result == traits_->GetSuccessCode()) |
| + DonePatching(ComponentUnpacker::kNone, 0); |
| + else |
| + DonePatching(ComponentUnpacker::kDeltaOperationFailure, result); |
| } |
| -DeltaUpdateOpPatchCourgette::DeltaUpdateOpPatchCourgette() {} |
| +void DeltaUpdateOpPatch::StartProcess() { |
| + content::UtilityProcessHost* host = content::UtilityProcessHost::Create( |
| + this, base::MessageLoopProxy::current().get()); |
| + host->DisableSandbox(); |
| + host->Send(traits_->GetPatchMessage(input_abs_path_, |
| + patch_abs_path_, |
| + output_abs_path_)); |
| +} |
| -ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoParseArguments( |
| - base::DictionaryValue* command_args, |
| - const base::FilePath& input_dir, |
| - ComponentInstaller* installer) { |
| - std::string patch_rel_path; |
| - std::string input_rel_path; |
| - if (!command_args->GetString(kPatch, &patch_rel_path) || |
| - !command_args->GetString(kInput, &input_rel_path)) |
| - return ComponentUnpacker::kDeltaBadCommands; |
| +void DeltaUpdateOpPatch::DonePatching(ComponentUnpacker::Error error, |
| + int error_code) { |
| + if (error != ComponentUnpacker::kNone) { |
| + error_code += traits_->GetErrorOffset(); |
| + } |
| + callback_.Run(error, error_code); |
| +} |
| - if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_)) |
| - return ComponentUnpacker::kDeltaMissingExistingFile; |
| +bool DeltaUpdateOpPatch::OnMessageReceived(const IPC::Message& message) { |
| + bool handled = true; |
| + IPC_BEGIN_MESSAGE_MAP(DeltaUpdateOpPatch, message) |
| + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_PatchFile_Succeeded, |
| + OnPatchSucceeded) |
| + IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_PatchFile_Failed, |
| + OnPatchFailed) |
| + IPC_MESSAGE_UNHANDLED(handled = false) |
| + IPC_END_MESSAGE_MAP() |
| + return handled; |
| +} |
| - patch_abs_path_ = input_dir.Append( |
| - base::FilePath::FromUTF8Unsafe(patch_rel_path)); |
| +void DeltaUpdateOpPatch::OnProcessCrashed(int exit_code) { |
| + DonePatching(ComponentUnpacker::kDeltaPatchProcessFailure, exit_code); |
| +} |
| - return ComponentUnpacker::kNone; |
| +void DeltaUpdateOpPatch::OnPatchSucceeded() { |
| + DonePatching(ComponentUnpacker::kNone, 0); |
| } |
| -ComponentUnpacker::Error DeltaUpdateOpPatchCourgette::DoRun( |
| - ComponentPatcher* patcher, |
| - int* error) { |
| - *error = 0; |
| - return patcher->Patch(ComponentPatcher::kPatchTypeCourgette, |
| - input_abs_path_, |
| - patch_abs_path_, |
| - output_abs_path_, |
| - error); |
| +void DeltaUpdateOpPatch::OnPatchFailed(int error_code) { |
| + DonePatching(ComponentUnpacker::kDeltaOperationFailure, error_code); |
| } |
| } // namespace component_updater |