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