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/update_client/component_patcher.h"
6 
7 #include <string>
8 #include <utility>
9 #include <vector>
10 
11 #include "base/bind.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/threading/sequenced_task_runner_handle.h"
18 #include "base/values.h"
19 #include "components/update_client/component_patcher_operation.h"
20 #include "components/update_client/patcher.h"
21 #include "components/update_client/update_client.h"
22 #include "components/update_client/update_client_errors.h"
23 
24 namespace update_client {
25 
26 namespace {
27 
28 // Deserialize the commands file (present in delta update packages). The top
29 // level must be a list.
ReadCommands(const base::FilePath & unpack_path)30 base::ListValue* ReadCommands(const base::FilePath& unpack_path) {
31   const base::FilePath commands =
32       unpack_path.Append(FILE_PATH_LITERAL("commands.json"));
33   if (!base::PathExists(commands))
34     return nullptr;
35 
36   JSONFileValueDeserializer deserializer(commands);
37   std::unique_ptr<base::Value> root =
38       deserializer.Deserialize(nullptr, nullptr);
39 
40   return (root.get() && root->is_list())
41              ? static_cast<base::ListValue*>(root.release())
42              : nullptr;
43 }
44 
45 }  // namespace
46 
ComponentPatcher(const base::FilePath & input_dir,const base::FilePath & unpack_dir,scoped_refptr<CrxInstaller> installer,scoped_refptr<Patcher> patcher)47 ComponentPatcher::ComponentPatcher(const base::FilePath& input_dir,
48                                    const base::FilePath& unpack_dir,
49                                    scoped_refptr<CrxInstaller> installer,
50                                    scoped_refptr<Patcher> patcher)
51     : input_dir_(input_dir),
52       unpack_dir_(unpack_dir),
53       installer_(installer),
54       patcher_(patcher) {}
55 
56 ComponentPatcher::~ComponentPatcher() = default;
57 
Start(Callback callback)58 void ComponentPatcher::Start(Callback callback) {
59   callback_ = std::move(callback);
60   base::SequencedTaskRunnerHandle::Get()->PostTask(
61       FROM_HERE, base::BindOnce(&ComponentPatcher::StartPatching,
62                                 scoped_refptr<ComponentPatcher>(this)));
63 }
64 
StartPatching()65 void ComponentPatcher::StartPatching() {
66   commands_.reset(ReadCommands(input_dir_));
67   if (!commands_) {
68     DonePatching(UnpackerError::kDeltaBadCommands, 0);
69   } else {
70     next_command_ = commands_->begin();
71     PatchNextFile();
72   }
73 }
74 
PatchNextFile()75 void ComponentPatcher::PatchNextFile() {
76   if (next_command_ == commands_->end()) {
77     DonePatching(UnpackerError::kNone, 0);
78     return;
79   }
80   const base::DictionaryValue* command_args;
81   if (!next_command_->GetAsDictionary(&command_args)) {
82     DonePatching(UnpackerError::kDeltaBadCommands, 0);
83     return;
84   }
85 
86   std::string operation;
87   if (command_args->GetString(kOp, &operation)) {
88     current_operation_ = CreateDeltaUpdateOp(operation, patcher_);
89   }
90 
91   if (!current_operation_) {
92     DonePatching(UnpackerError::kDeltaUnsupportedCommand, 0);
93     return;
94   }
95   current_operation_->Run(
96       command_args, input_dir_, unpack_dir_, installer_,
97       base::BindOnce(&ComponentPatcher::DonePatchingFile,
98                      scoped_refptr<ComponentPatcher>(this)));
99 }
100 
DonePatchingFile(UnpackerError error,int extended_error)101 void ComponentPatcher::DonePatchingFile(UnpackerError error,
102                                         int extended_error) {
103   if (error != UnpackerError::kNone) {
104     DonePatching(error, extended_error);
105   } else {
106     ++next_command_;
107     PatchNextFile();
108   }
109 }
110 
DonePatching(UnpackerError error,int extended_error)111 void ComponentPatcher::DonePatching(UnpackerError error, int extended_error) {
112   current_operation_ = nullptr;
113   base::SequencedTaskRunnerHandle::Get()->PostTask(
114       FROM_HERE, base::BindOnce(std::move(callback_), error, extended_error));
115 }
116 
117 }  // namespace update_client
118