15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/set_reg_value_work_item.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/logging_installer.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SetRegValueWorkItem::~SetRegValueWorkItem() { 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root, 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& key_path, 17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) REGSAM wow64_access, 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& value_name, 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& value_data, 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool overwrite) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : predefined_root_(predefined_root), 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key_path_(key_path), 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_name_(value_name), 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) overwrite_(overwrite), 25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) wow64_access_(wow64_access), 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_(SET_VALUE), 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_(REG_SZ), 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) previous_type_(0) { 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(wow64_access == 0 || 30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) wow64_access == KEY_WOW64_32KEY || 31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) wow64_access == KEY_WOW64_64KEY); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint8* data = reinterpret_cast<const uint8*>(value_data.c_str()); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_.assign(data, data + (value_data.length() + 1) * sizeof(wchar_t)); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root, 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& key_path, 38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) REGSAM wow64_access, 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& value_name, 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD value_data, 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool overwrite) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : predefined_root_(predefined_root), 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key_path_(key_path), 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_name_(value_name), 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) overwrite_(overwrite), 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) wow64_access_(wow64_access), 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_(SET_VALUE), 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_(REG_DWORD), 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) previous_type_(0) { 50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(wow64_access == 0 || 51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) wow64_access == KEY_WOW64_32KEY || 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) wow64_access == KEY_WOW64_64KEY); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint8* data = reinterpret_cast<const uint8*>(&value_data); 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_.assign(data, data + sizeof(value_data)); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& key_path, 59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) REGSAM wow64_access, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& value_name, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 value_data, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool overwrite) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : predefined_root_(predefined_root), 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key_path_(key_path), 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_name_(value_name), 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) overwrite_(overwrite), 67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) wow64_access_(wow64_access), 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_(SET_VALUE), 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_(REG_QWORD), 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) previous_type_(0) { 71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(wow64_access == 0 || 72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) wow64_access == KEY_WOW64_32KEY || 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) wow64_access == KEY_WOW64_64KEY); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint8* data = reinterpret_cast<const uint8*>(&value_data); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value_.assign(data, data + sizeof(value_data)); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SetRegValueWorkItem::Do() { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LONG result = ERROR_SUCCESS; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::RegKey key; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status_ != SET_VALUE) { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we already did something. 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "multiple calls to Do()"; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = ERROR_CANTWRITE; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ignore_failure_; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_ = VALUE_UNCHANGED; 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) result = key.Open(predefined_root_, 90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) key_path_.c_str(), 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) KEY_READ | KEY_SET_VALUE | wow64_access_); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != ERROR_SUCCESS) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "can not open " << key_path_ << " error: " << result; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ignore_failure_; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD type = 0; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD size = 0; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = key.ReadValue(value_name_.c_str(), NULL, &size, &type); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the value exists but we don't want to overwrite then there's 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // nothing more to do. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((result != ERROR_FILE_NOT_FOUND) && !overwrite_) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there's something to be saved, save it. 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == ERROR_SUCCESS) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!size) { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) previous_type_ = type; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) previous_value_.resize(size); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = key.ReadValue(value_name_.c_str(), &previous_value_[0], &size, 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &previous_type_); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != ERROR_SUCCESS) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) previous_value_.clear(); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Failed to save original value. Error: " << result; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = key.WriteValue(value_name_.c_str(), &value_[0], 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<DWORD>(value_.size()), type_); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != ERROR_SUCCESS) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Failed to write value " << key_path_ << " error: " << result; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ignore_failure_; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_ = previous_type_ ? VALUE_OVERWRITTEN : NEW_VALUE_CREATED; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetRegValueWorkItem::Rollback() { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ignore_failure_) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status_ == SET_VALUE || status_ == VALUE_ROLL_BACK) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status_ == VALUE_UNCHANGED) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_ = VALUE_ROLL_BACK; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "rollback: setting unchanged, nothing to do"; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::RegKey key; 146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) LONG result = key.Open( 147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) predefined_root_, key_path_.c_str(), KEY_SET_VALUE | wow64_access_); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != ERROR_SUCCESS) { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "rollback: can not open " << key_path_ << " error: " << result; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status_ == NEW_VALUE_CREATED) { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = key.DeleteValue(value_name_.c_str()); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "rollback: deleting " << value_name_ << " error: " << result; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (status_ == VALUE_OVERWRITTEN) { 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const unsigned char* previous_value = 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) previous_value_.empty() ? NULL : &previous_value_[0]; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = key.WriteValue(value_name_.c_str(), previous_value, 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<DWORD>(previous_value_.size()), 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) previous_type_); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "rollback: restoring " << value_name_ << " error: " << result; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_ = VALUE_ROLL_BACK; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 169