This source file includes following definitions.
- name_str
- name
- type
- data
- data_len
- Initialize
- Initialize
- WriteTo
- Initialize
- WriteTo
#include "chrome/installer/util/registry_key_backup.h"
#include <algorithm>
#include <map>
#include <utility>
#include <vector>
#include "base/logging.h"
#include "base/win/registry.h"
using base::win::RegKey;
namespace {
const REGSAM kKeyReadNoNotify = (KEY_READ) & ~(KEY_NOTIFY);
class ValueData {
public:
ValueData();
~ValueData();
void Initialize(const wchar_t* name_buffer, DWORD name_size,
DWORD type, const uint8* data, DWORD data_size);
const std::wstring& name_str() const { return name_; }
const wchar_t* name() const { return name_.empty() ? NULL : name_.c_str(); }
DWORD type() const { return type_; }
const uint8* data() const { return data_.empty() ? NULL : &data_[0]; }
DWORD data_len() const { return static_cast<DWORD>(data_.size()); }
private:
std::wstring name_;
std::vector<uint8> data_;
DWORD type_;
};
}
class RegistryKeyBackup::KeyData {
public:
KeyData();
~KeyData();
bool Initialize(const RegKey& key);
bool WriteTo(RegKey* key) const;
private:
std::vector<ValueData> values_;
std::map<std::wstring, KeyData> subkeys_;
};
ValueData::ValueData() : type_(REG_NONE) {
}
ValueData::~ValueData() {
}
void ValueData::Initialize(
const wchar_t* name_buffer,
DWORD name_size,
DWORD type,
const uint8* data,
DWORD data_size) {
name_.assign(name_buffer, name_size);
type_ = type;
data_.assign(data, data + data_size);
}
RegistryKeyBackup::KeyData::KeyData() {
}
RegistryKeyBackup::KeyData::~KeyData() {
}
bool RegistryKeyBackup::KeyData::Initialize(const RegKey& key) {
std::vector<ValueData> values;
std::map<std::wstring, KeyData> subkeys;
DWORD num_subkeys = 0;
DWORD max_subkey_name_len = 0;
DWORD num_values = 0;
DWORD max_value_name_len = 0;
DWORD max_value_len = 0;
LONG result = RegQueryInfoKey(key.Handle(), NULL, NULL, NULL,
&num_subkeys, &max_subkey_name_len, NULL,
&num_values, &max_value_name_len,
&max_value_len, NULL, NULL);
if (result != ERROR_SUCCESS) {
LOG(ERROR) << "Failed getting info of key to backup, result: " << result;
return false;
}
DWORD max_name_len = std::max(max_subkey_name_len, max_value_name_len) + 1;
std::vector<wchar_t> name_buffer(max_name_len);
if (num_values != 0) {
values.reserve(num_values);
std::vector<uint8> value_buffer(max_value_len != 0 ? max_value_len : 1);
DWORD name_size = 0;
DWORD value_type = REG_NONE;
DWORD value_size = 0;
for (DWORD i = 0; i < num_values; ) {
name_size = static_cast<DWORD>(name_buffer.size());
value_size = static_cast<DWORD>(value_buffer.size());
result = RegEnumValue(key.Handle(), i, &name_buffer[0], &name_size,
NULL, &value_type, &value_buffer[0], &value_size);
switch (result) {
case ERROR_NO_MORE_ITEMS:
num_values = i;
break;
case ERROR_SUCCESS:
values.push_back(ValueData());
values.back().Initialize(&name_buffer[0], name_size, value_type,
&value_buffer[0], value_size);
++i;
break;
case ERROR_MORE_DATA:
if (value_size > value_buffer.size())
value_buffer.resize(value_size);
if (name_size + 1 > name_buffer.size())
name_buffer.resize(name_size + 1);
break;
default:
LOG(ERROR) << "Failed backing up value " << i << ", result: "
<< result;
return false;
}
}
DLOG_IF(WARNING, RegEnumValue(key.Handle(), num_values, &name_buffer[0],
&name_size, NULL, &value_type, NULL,
NULL) != ERROR_NO_MORE_ITEMS)
<< "Concurrent modifications to registry key during backup operation.";
}
if (num_subkeys != 0) {
DWORD name_size = 0;
for (DWORD i = 0; i < num_subkeys; ) {
name_size = static_cast<DWORD>(name_buffer.size());
result = RegEnumKeyEx(key.Handle(), i, &name_buffer[0], &name_size,
NULL, NULL, NULL, NULL);
switch (result) {
case ERROR_NO_MORE_ITEMS:
num_subkeys = i;
break;
case ERROR_SUCCESS:
subkeys.insert(std::make_pair(&name_buffer[0], KeyData()));
++i;
break;
case ERROR_MORE_DATA:
name_buffer.resize(name_size + 1);
break;
default:
LOG(ERROR) << "Failed getting name of subkey " << i
<< " for backup, result: " << result;
return false;
}
}
DLOG_IF(WARNING,
RegEnumKeyEx(key.Handle(), num_subkeys, NULL, &name_size, NULL,
NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)
<< "Concurrent modifications to registry key during backup operation.";
RegKey subkey;
for (std::map<std::wstring, KeyData>::iterator it = subkeys.begin();
it != subkeys.end(); ++it) {
result = subkey.Open(key.Handle(), it->first.c_str(), kKeyReadNoNotify);
if (result != ERROR_SUCCESS) {
LOG(ERROR) << "Failed opening subkey \"" << it->first
<< "\" for backup, result: " << result;
return false;
}
if (!it->second.Initialize(subkey)) {
LOG(ERROR) << "Failed backing up subkey \"" << it->first << "\"";
return false;
}
}
}
values_.swap(values);
subkeys_.swap(subkeys);
return true;
}
bool RegistryKeyBackup::KeyData::WriteTo(RegKey* key) const {
DCHECK(key);
LONG result = ERROR_SUCCESS;
for (std::vector<ValueData>::const_iterator it = values_.begin();
it != values_.end(); ++it) {
const ValueData& value = *it;
result = RegSetValueEx(key->Handle(), value.name(), 0, value.type(),
value.data(), value.data_len());
if (result != ERROR_SUCCESS) {
LOG(ERROR) << "Failed writing value \"" << value.name_str()
<< "\", result: " << result;
return false;
}
}
RegKey subkey;
for (std::map<std::wstring, KeyData>::const_iterator it = subkeys_.begin();
it != subkeys_.end(); ++it) {
const std::wstring& name = it->first;
result = subkey.Create(key->Handle(), name.c_str(), KEY_WRITE);
if (result != ERROR_SUCCESS) {
LOG(ERROR) << "Failed creating subkey \"" << name << "\", result: "
<< result;
return false;
}
if (!it->second.WriteTo(&subkey)) {
LOG(ERROR) << "Failed writing subkey \"" << name << "\", result: "
<< result;
return false;
}
}
return true;
}
RegistryKeyBackup::RegistryKeyBackup() {
}
RegistryKeyBackup::~RegistryKeyBackup() {
}
bool RegistryKeyBackup::Initialize(HKEY root, const wchar_t* key_path) {
DCHECK(key_path);
RegKey key;
scoped_ptr<KeyData> key_data;
LONG result = key.Open(root, key_path, kKeyReadNoNotify);
if (result == ERROR_SUCCESS) {
key_data.reset(new KeyData());
if (!key_data->Initialize(key)) {
LOG(ERROR) << "Failed to backup key at " << key_path;
return false;
}
} else if (result != ERROR_FILE_NOT_FOUND) {
LOG(ERROR) << "Failed to open key at " << key_path
<< " to create backup, result: " << result;
return false;
}
key_data_.swap(key_data);
return true;
}
bool RegistryKeyBackup::WriteTo(HKEY root, const wchar_t* key_path) const {
DCHECK(key_path);
bool success = false;
if (key_data_.get() != NULL) {
RegKey dest_key;
LONG result = dest_key.Create(root, key_path, KEY_WRITE);
if (result != ERROR_SUCCESS) {
LOG(ERROR) << "Failed to create destination key at " << key_path
<< " to write backup, result: " << result;
} else {
success = key_data_->WriteTo(&dest_key);
LOG_IF(ERROR, !success) << "Failed to write key data.";
}
} else {
success = true;
}
return success;
}