| Index: chrome/browser/component_updater/component_unpacker.cc
|
| diff --git a/chrome/browser/component_updater/component_unpacker.cc b/chrome/browser/component_updater/component_unpacker.cc
|
| index 74b17853bacf6890421a15b6ae0302ac5ea9d0b0..6ddff606097eb5dcfe1ed01069b7d184fbe015da 100644
|
| --- a/chrome/browser/component_updater/component_unpacker.cc
|
| +++ b/chrome/browser/component_updater/component_unpacker.cc
|
| @@ -31,6 +31,19 @@ namespace component_updater {
|
|
|
| namespace {
|
|
|
| +namespace serialize {
|
| +
|
| +const char kKeyFingerprint[] = "fingerprint";
|
| +const char kKeyPKHash[] = "public_key_hash";
|
| +const char kKeyInProcess[] = "in_process";
|
| +
|
| +const base::FilePath::CharType kCrxFileName[] =
|
| + FILE_PATH_LITERAL("saved_installer.crx");
|
| +const base::FilePath::CharType kInstallDataFileName[] =
|
| + FILE_PATH_LITERAL("metadata.json");
|
| +
|
| +} // namespace serialize
|
| +
|
| // This class makes sure that the CRX digital signature is valid
|
| // and well formed.
|
| class CRXValidator {
|
| @@ -124,8 +137,7 @@ scoped_ptr<base::DictionaryValue> ReadManifest(
|
| if (!base::PathExists(manifest))
|
| return scoped_ptr<base::DictionaryValue>();
|
| JSONFileValueSerializer serializer(manifest);
|
| - std::string error;
|
| - scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error));
|
| + scoped_ptr<base::Value> root(serializer.Deserialize(NULL, NULL));
|
| if (!root.get())
|
| return scoped_ptr<base::DictionaryValue>();
|
| if (!root->IsType(base::Value::TYPE_DICTIONARY))
|
| @@ -182,11 +194,19 @@ bool ComponentUnpacker::Verify() {
|
| return true;
|
| }
|
|
|
| +bool ComponentUnpacker::CreateUnpackDirectory(base::FilePath* new_dir) {
|
| + if (unpack_base_dir_.empty()) {
|
| + return base::CreateNewTempDirectory(base::FilePath::StringType(), new_dir);
|
| + }
|
| +
|
| + return base::CreateTemporaryDirInDir(
|
| + unpack_base_dir_, base::FilePath::StringType(), new_dir);
|
| +}
|
| +
|
| bool ComponentUnpacker::Unzip() {
|
| base::FilePath& destination = is_delta_ ? unpack_diff_path_ : unpack_path_;
|
| VLOG(1) << "Unpacking in: " << destination.value();
|
| - if (!base::CreateNewTempDirectory(base::FilePath::StringType(),
|
| - &destination)) {
|
| + if (!CreateUnpackDirectory(&destination)) {
|
| VLOG(1) << "Unable to create temporary directory for unpacking.";
|
| error_ = kUnzipPathError;
|
| return false;
|
| @@ -203,8 +223,7 @@ bool ComponentUnpacker::Unzip() {
|
| bool ComponentUnpacker::BeginPatching() {
|
| if (is_delta_) { // Package is a diff package.
|
| // Use a different temp directory for the patch output files.
|
| - if (!base::CreateNewTempDirectory(base::FilePath::StringType(),
|
| - &unpack_path_)) {
|
| + if (!CreateUnpackDirectory(&unpack_path_)) {
|
| error_ = kUnzipPathError;
|
| return false;
|
| }
|
| @@ -264,6 +283,14 @@ void ComponentUnpacker::Install() {
|
| }
|
| DCHECK(error_ == kNone);
|
| if (!installer_->Install(*manifest, unpack_path_)) {
|
| + // Saves the installer files and tries to re-install which is not managed
|
| + // by the component updater service.
|
| + if (SaveInstallSource(installer_->GetBackupPath())) {
|
| + installer_->InstallExternally();
|
| + }
|
| +
|
| + // But keep current install error code since we cannot get the external
|
| + // install result.
|
| error_ = kInstallerError;
|
| return;
|
| }
|
| @@ -280,4 +307,92 @@ void ComponentUnpacker::Finish() {
|
| ComponentUnpacker::~ComponentUnpacker() {
|
| }
|
|
|
| +bool ComponentUnpacker::SaveInstallSource(
|
| + const base::FilePath& backup_path) const {
|
| + if (backup_path.empty()) {
|
| + return false;
|
| + }
|
| +
|
| + if (!base::CreateDirectory(backup_path)) {
|
| + return false;
|
| + }
|
| +
|
| + const base::FilePath crx_path = backup_path.Append(serialize::kCrxFileName);
|
| + if (!base::CopyFile(path_, crx_path)) {
|
| + return false;
|
| + }
|
| +
|
| + const base::FilePath install_data_file_path =
|
| + backup_path.Append(serialize::kInstallDataFileName);
|
| + JSONFileValueSerializer serializer(install_data_file_path);
|
| +
|
| + scoped_ptr<base::DictionaryValue> root(new base::DictionaryValue);
|
| + root->SetString(serialize::kKeyFingerprint, fingerprint_);
|
| + root->SetBoolean(serialize::kKeyInProcess, in_process_);
|
| + scoped_ptr<base::ListValue> pk_hash_list(new base::ListValue);
|
| + for (size_t i = 0; i < pk_hash_.size(); ++i) {
|
| + pk_hash_list->Append(base::Value::CreateIntegerValue(
|
| + static_cast<int>(pk_hash_[i])));
|
| + }
|
| + root->Set(serialize::kKeyPKHash, pk_hash_list.release());
|
| + if (!serializer.Serialize(*root)) {
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void ComponentUnpacker::set_unpack_base_dir(const base::FilePath& path) {
|
| + unpack_base_dir_ = path;
|
| +}
|
| +
|
| +scoped_refptr<ComponentUnpacker> ComponentUnpacker::CreateFromBackup(
|
| + const base::FilePath& backup_path,
|
| + const std::vector<uint8>& pk_hash,
|
| + ComponentInstaller* installer,
|
| + scoped_refptr<base::SequencedTaskRunner> task_runner) {
|
| + const base::FilePath crx_path = backup_path.Append(serialize::kCrxFileName);
|
| + if (!base::PathExists(crx_path) || base::DirectoryExists(crx_path)) {
|
| + return scoped_refptr<ComponentUnpacker>();
|
| + }
|
| +
|
| + std::string fingerprint;
|
| + bool in_process = false;
|
| +
|
| + const base::FilePath install_data_file_path =
|
| + backup_path.Append(serialize::kInstallDataFileName);
|
| + if (!base::PathExists(install_data_file_path)) {
|
| + return scoped_refptr<ComponentUnpacker>();
|
| + }
|
| +
|
| + JSONFileValueSerializer serialize(install_data_file_path);
|
| + scoped_ptr<base::Value> root(serialize.Deserialize(NULL, NULL));
|
| + if (!root.get() || !root->IsType(base::Value::TYPE_DICTIONARY)) {
|
| + return scoped_refptr<ComponentUnpacker>();
|
| + }
|
| +
|
| + scoped_ptr<base::DictionaryValue> metadata(
|
| + static_cast<base::DictionaryValue*>(root.release()));
|
| +
|
| + base::ListValue* pk_hash_list = NULL;
|
| + if (!metadata->GetStringASCII(serialize::kKeyFingerprint, &fingerprint) ||
|
| + !metadata->GetBoolean(serialize::kKeyInProcess, &in_process) ||
|
| + !metadata->GetList(serialize::kKeyPKHash, &pk_hash_list) ||
|
| + pk_hash_list == NULL ||
|
| + pk_hash_list->GetSize() != pk_hash.size()) {
|
| + return scoped_refptr<ComponentUnpacker>();
|
| + }
|
| +
|
| + for (size_t i = 0; i < pk_hash.size(); ++i) {
|
| + int value = 0;
|
| + if (!pk_hash_list->GetInteger(i, &value) ||
|
| + pk_hash[i] != static_cast<uint8>(value)) {
|
| + return scoped_refptr<ComponentUnpacker>();
|
| + }
|
| + }
|
| +
|
| + return make_scoped_refptr(new ComponentUnpacker(
|
| + pk_hash, crx_path, fingerprint, installer, in_process, task_runner));
|
| +}
|
| +
|
| } // namespace component_updater
|
|
|