| 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 94546373f39b4cbac174bf84841c6bcc5f099b6c..341df220ffe8d5122920cca5bf4db483b2b8eb49 100644
|
| --- a/chrome/browser/component_updater/component_unpacker.cc
|
| +++ b/chrome/browser/component_updater/component_unpacker.cc
|
| @@ -12,6 +12,7 @@
|
| #include "base/memory/scoped_handle.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/stringprintf.h"
|
| +#include "chrome/browser/component_updater/component_patcher.h"
|
| #include "chrome/browser/component_updater/component_updater_service.h"
|
| #include "chrome/common/extensions/extension_constants.h"
|
| #include "crypto/secure_hash.h"
|
| @@ -22,11 +23,12 @@
|
| using crypto::SecureHash;
|
|
|
| namespace {
|
| +
|
| // This class makes sure that the CRX digital signature is valid
|
| // and well formed.
|
| class CRXValidator {
|
| public:
|
| - explicit CRXValidator(FILE* crx_file) : valid_(false) {
|
| + explicit CRXValidator(FILE* crx_file) : valid_(false), delta_(false) {
|
| extensions::CrxFile::Header header;
|
| size_t len = fread(&header, 1, sizeof(header), crx_file);
|
| if (len < sizeof(header))
|
| @@ -37,6 +39,7 @@ class CRXValidator {
|
| extensions::CrxFile::Parse(header, &error));
|
| if (!crx.get())
|
| return;
|
| + delta_ = extensions::CrxFile::HeaderIsDelta(header);
|
|
|
| std::vector<uint8> key(header.key_size);
|
| len = fread(&key[0], sizeof(uint8), header.key_size, crx_file);
|
| @@ -72,10 +75,13 @@ class CRXValidator {
|
|
|
| bool valid() const { return valid_; }
|
|
|
| + bool delta() const { return delta_; }
|
| +
|
| const std::vector<uint8>& public_key() const { return public_key_; }
|
|
|
| private:
|
| bool valid_;
|
| + bool delta_;
|
| std::vector<uint8> public_key_;
|
| };
|
|
|
| @@ -98,12 +104,29 @@ base::DictionaryValue* ReadManifest(const base::FilePath& unpack_path) {
|
| return static_cast<base::DictionaryValue*>(root.release());
|
| }
|
|
|
| +// Deletes a path if it exists, and then creates a directory there.
|
| +// Returns true if and only if these operations were successful.
|
| +// This method doesn't take any special steps to prevent files from
|
| +// being inserted into the target directory by another process or thread.
|
| +bool MakeEmptyDirectory(const base::FilePath& path) {
|
| + if (file_util::PathExists(path)) {
|
| + if (!file_util::Delete(path, true))
|
| + return false;
|
| + }
|
| + if (!file_util::CreateDirectory(path))
|
| + return false;
|
| + return true;
|
| +}
|
| +
|
| } // namespace.
|
|
|
| ComponentUnpacker::ComponentUnpacker(const std::vector<uint8>& pk_hash,
|
| const base::FilePath& path,
|
| + const std::string& fingerprint,
|
| + ComponentPatcher* patcher,
|
| ComponentInstaller* installer)
|
| - : error_(kNone) {
|
| + : error_(kNone),
|
| + extended_error_(0) {
|
| if (pk_hash.empty() || path.empty()) {
|
| error_ = kInvalidParams;
|
| return;
|
| @@ -135,31 +158,61 @@ ComponentUnpacker::ComponentUnpacker(const std::vector<uint8>& pk_hash,
|
| return;
|
| }
|
| // We want the temporary directory to be unique and yet predictable, so
|
| - // we can easily find the package in a end user machine.
|
| - std::string dir(
|
| + // we can easily find the package in an end user machine.
|
| + const std::string dir(
|
| base::StringPrintf("CRX_%s", base::HexEncode(hash, 6).c_str()));
|
| unpack_path_ = path.DirName().AppendASCII(dir.c_str());
|
| - if (file_util::DirectoryExists(unpack_path_)) {
|
| - if (!file_util::Delete(unpack_path_, true)) {
|
| - unpack_path_.clear();
|
| - error_ = kUzipPathError;
|
| - return;
|
| - }
|
| - }
|
| - if (!file_util::CreateDirectory(unpack_path_)) {
|
| + if (!MakeEmptyDirectory(unpack_path_)) {
|
| unpack_path_.clear();
|
| - error_ = kUzipPathError;
|
| + error_ = kUnzipPathError;
|
| return;
|
| }
|
| - if (!zip::Unzip(path, unpack_path_)) {
|
| - error_ = kUnzipFailed;
|
| - return;
|
| + if (validator.delta()) { // Package is a diff package.
|
| + // We want a different temp directory for the delta files; we'll put the
|
| + // patch output into unpack_path_.
|
| + std::string dir(
|
| + base::StringPrintf("CRX_%s_diff", base::HexEncode(hash, 6).c_str()));
|
| + base::FilePath unpack_diff_path = path.DirName().AppendASCII(dir.c_str());
|
| + if (!MakeEmptyDirectory(unpack_diff_path)) {
|
| + error_ = kUnzipPathError;
|
| + return;
|
| + }
|
| + if (!zip::Unzip(path, unpack_diff_path)) {
|
| + error_ = kUnzipFailed;
|
| + return;
|
| + }
|
| + ComponentUnpacker::Error result = DifferentialUpdatePatch(unpack_diff_path,
|
| + unpack_path_,
|
| + patcher,
|
| + installer,
|
| + &extended_error_);
|
| + file_util::Delete(unpack_diff_path, true);
|
| + unpack_diff_path.clear();
|
| + error_ = result;
|
| + if (error_ != kNone) {
|
| + return;
|
| + }
|
| + } else {
|
| + // Package is a normal update/install; unzip it into unpack_path_ directly.
|
| + if (!zip::Unzip(path, unpack_path_)) {
|
| + error_ = kUnzipFailed;
|
| + return;
|
| + }
|
| }
|
| scoped_ptr<base::DictionaryValue> manifest(ReadManifest(unpack_path_));
|
| if (!manifest.get()) {
|
| error_ = kBadManifest;
|
| return;
|
| }
|
| + // Write the fingerprint to disk.
|
| + if (static_cast<int>(fingerprint.size()) !=
|
| + file_util::WriteFile(
|
| + unpack_path_.Append(FILE_PATH_LITERAL("manifest.fingerprint")),
|
| + fingerprint.c_str(),
|
| + fingerprint.size())) {
|
| + error_ = kFingerprintWriteFailed;
|
| + return;
|
| + }
|
| if (!installer->Install(*manifest, unpack_path_)) {
|
| error_ = kInstallerError;
|
| return;
|
| @@ -169,7 +222,6 @@ ComponentUnpacker::ComponentUnpacker(const std::vector<uint8>& pk_hash,
|
| }
|
|
|
| ComponentUnpacker::~ComponentUnpacker() {
|
| - if (!unpack_path_.empty()) {
|
| + if (!unpack_path_.empty())
|
| file_util::Delete(unpack_path_, true);
|
| - }
|
| }
|
|
|