1// Copyright 2014 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/component_updater/component_patcher.h" 6 7#include <string> 8#include <vector> 9 10#include "base/bind.h" 11#include "base/bind_helpers.h" 12#include "base/files/file_path.h" 13#include "base/files/file_util.h" 14#include "base/json/json_file_value_serializer.h" 15#include "base/location.h" 16#include "base/memory/weak_ptr.h" 17#include "base/values.h" 18#include "components/component_updater/component_patcher_operation.h" 19#include "components/component_updater/component_updater_service.h" 20 21namespace component_updater { 22 23namespace { 24 25// Deserialize the commands file (present in delta update packages). The top 26// level must be a list. 27base::ListValue* ReadCommands(const base::FilePath& unpack_path) { 28 const base::FilePath commands = 29 unpack_path.Append(FILE_PATH_LITERAL("commands.json")); 30 if (!base::PathExists(commands)) 31 return NULL; 32 33 JSONFileValueSerializer serializer(commands); 34 scoped_ptr<base::Value> root(serializer.Deserialize(NULL, NULL)); 35 36 return (root.get() && root->IsType(base::Value::TYPE_LIST)) 37 ? static_cast<base::ListValue*>(root.release()) 38 : NULL; 39} 40 41} // namespace 42 43ComponentPatcher::ComponentPatcher( 44 const base::FilePath& input_dir, 45 const base::FilePath& unpack_dir, 46 ComponentInstaller* installer, 47 scoped_refptr<OutOfProcessPatcher> out_of_process_patcher, 48 scoped_refptr<base::SequencedTaskRunner> task_runner) 49 : input_dir_(input_dir), 50 unpack_dir_(unpack_dir), 51 installer_(installer), 52 out_of_process_patcher_(out_of_process_patcher), 53 task_runner_(task_runner) { 54} 55 56ComponentPatcher::~ComponentPatcher() { 57} 58 59void ComponentPatcher::Start(const ComponentUnpacker::Callback& callback) { 60 callback_ = callback; 61 task_runner_->PostTask(FROM_HERE, 62 base::Bind(&ComponentPatcher::StartPatching, 63 scoped_refptr<ComponentPatcher>(this))); 64} 65 66void ComponentPatcher::StartPatching() { 67 commands_.reset(ReadCommands(input_dir_)); 68 if (!commands_.get()) { 69 DonePatching(ComponentUnpacker::kDeltaBadCommands, 0); 70 } else { 71 next_command_ = commands_->begin(); 72 PatchNextFile(); 73 } 74} 75 76void ComponentPatcher::PatchNextFile() { 77 if (next_command_ == commands_->end()) { 78 DonePatching(ComponentUnpacker::kNone, 0); 79 return; 80 } 81 if (!(*next_command_)->IsType(base::Value::TYPE_DICTIONARY)) { 82 DonePatching(ComponentUnpacker::kDeltaBadCommands, 0); 83 return; 84 } 85 const base::DictionaryValue* command_args = 86 static_cast<base::DictionaryValue*>(*next_command_); 87 88 std::string operation; 89 if (command_args->GetString(kOp, &operation)) { 90 current_operation_ = 91 CreateDeltaUpdateOp(operation, out_of_process_patcher_); 92 } 93 94 if (!current_operation_.get()) { 95 DonePatching(ComponentUnpacker::kDeltaUnsupportedCommand, 0); 96 return; 97 } 98 current_operation_->Run(command_args, 99 input_dir_, 100 unpack_dir_, 101 installer_, 102 base::Bind(&ComponentPatcher::DonePatchingFile, 103 scoped_refptr<ComponentPatcher>(this)), 104 task_runner_); 105} 106 107void ComponentPatcher::DonePatchingFile(ComponentUnpacker::Error error, 108 int extended_error) { 109 if (error != ComponentUnpacker::kNone) { 110 DonePatching(error, extended_error); 111 } else { 112 ++next_command_; 113 PatchNextFile(); 114 } 115} 116 117void ComponentPatcher::DonePatching(ComponentUnpacker::Error error, 118 int extended_error) { 119 current_operation_ = NULL; 120 task_runner_->PostTask(FROM_HERE, 121 base::Bind(callback_, error, extended_error)); 122 callback_.Reset(); 123} 124 125} // namespace component_updater 126