Home | History | Annotate | Download | only in util
      1 // Copyright (c) 2011 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 "chrome/installer/util/set_reg_value_work_item.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/string_util.h"
      9 #include "base/win/registry.h"
     10 #include "chrome/installer/util/logging_installer.h"
     11 
     12 SetRegValueWorkItem::~SetRegValueWorkItem() {
     13 }
     14 
     15 SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root,
     16                                          const std::wstring& key_path,
     17                                          REGSAM wow64_access,
     18                                          const std::wstring& value_name,
     19                                          const std::wstring& value_data,
     20                                          bool overwrite)
     21     : predefined_root_(predefined_root),
     22       key_path_(key_path),
     23       value_name_(value_name),
     24       overwrite_(overwrite),
     25       wow64_access_(wow64_access),
     26       status_(SET_VALUE),
     27       type_(REG_SZ),
     28       previous_type_(0) {
     29   DCHECK(wow64_access == 0 ||
     30          wow64_access == KEY_WOW64_32KEY ||
     31          wow64_access == KEY_WOW64_64KEY);
     32   const uint8* data = reinterpret_cast<const uint8*>(value_data.c_str());
     33   value_.assign(data, data + (value_data.length() + 1) * sizeof(wchar_t));
     34 }
     35 
     36 SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root,
     37                                          const std::wstring& key_path,
     38                                          REGSAM wow64_access,
     39                                          const std::wstring& value_name,
     40                                          DWORD value_data,
     41                                          bool overwrite)
     42     : predefined_root_(predefined_root),
     43       key_path_(key_path),
     44       value_name_(value_name),
     45       overwrite_(overwrite),
     46       wow64_access_(wow64_access),
     47       status_(SET_VALUE),
     48       type_(REG_DWORD),
     49       previous_type_(0) {
     50   DCHECK(wow64_access == 0 ||
     51          wow64_access == KEY_WOW64_32KEY ||
     52          wow64_access == KEY_WOW64_64KEY);
     53   const uint8* data = reinterpret_cast<const uint8*>(&value_data);
     54   value_.assign(data, data + sizeof(value_data));
     55 }
     56 
     57 SetRegValueWorkItem::SetRegValueWorkItem(HKEY predefined_root,
     58                                          const std::wstring& key_path,
     59                                          REGSAM wow64_access,
     60                                          const std::wstring& value_name,
     61                                          int64 value_data,
     62                                          bool overwrite)
     63     : predefined_root_(predefined_root),
     64       key_path_(key_path),
     65       value_name_(value_name),
     66       overwrite_(overwrite),
     67       wow64_access_(wow64_access),
     68       status_(SET_VALUE),
     69       type_(REG_QWORD),
     70       previous_type_(0) {
     71   DCHECK(wow64_access == 0 ||
     72          wow64_access == KEY_WOW64_32KEY ||
     73          wow64_access == KEY_WOW64_64KEY);
     74   const uint8* data = reinterpret_cast<const uint8*>(&value_data);
     75   value_.assign(data, data + sizeof(value_data));
     76 }
     77 
     78 bool SetRegValueWorkItem::Do() {
     79   LONG result = ERROR_SUCCESS;
     80   base::win::RegKey key;
     81   if (status_ != SET_VALUE) {
     82     // we already did something.
     83     VLOG(1) << "multiple calls to Do()";
     84     result = ERROR_CANTWRITE;
     85     return ignore_failure_;
     86   }
     87 
     88   status_ = VALUE_UNCHANGED;
     89   result = key.Open(predefined_root_,
     90                     key_path_.c_str(),
     91                     KEY_READ | KEY_SET_VALUE | wow64_access_);
     92   if (result != ERROR_SUCCESS) {
     93     VLOG(1) << "can not open " << key_path_ << " error: " << result;
     94     return ignore_failure_;
     95   }
     96 
     97   DWORD type = 0;
     98   DWORD size = 0;
     99   result = key.ReadValue(value_name_.c_str(), NULL, &size, &type);
    100   // If the value exists but we don't want to overwrite then there's
    101   // nothing more to do.
    102   if ((result != ERROR_FILE_NOT_FOUND) && !overwrite_) {
    103     return true;
    104   }
    105 
    106   // If there's something to be saved, save it.
    107   if (result == ERROR_SUCCESS) {
    108     if (!size) {
    109       previous_type_ = type;
    110     } else {
    111       previous_value_.resize(size);
    112       result = key.ReadValue(value_name_.c_str(), &previous_value_[0], &size,
    113                              &previous_type_);
    114       if (result != ERROR_SUCCESS) {
    115         previous_value_.clear();
    116         VLOG(1) << "Failed to save original value. Error: " << result;
    117       }
    118     }
    119   }
    120 
    121   result = key.WriteValue(value_name_.c_str(), &value_[0],
    122                           static_cast<DWORD>(value_.size()), type_);
    123   if (result != ERROR_SUCCESS) {
    124     VLOG(1) << "Failed to write value " << key_path_ << " error: " << result;
    125     return ignore_failure_;
    126   }
    127 
    128   status_ = previous_type_ ? VALUE_OVERWRITTEN : NEW_VALUE_CREATED;
    129   return true;
    130 }
    131 
    132 void SetRegValueWorkItem::Rollback() {
    133   if (ignore_failure_)
    134     return;
    135 
    136   if (status_ == SET_VALUE || status_ == VALUE_ROLL_BACK)
    137     return;
    138 
    139   if (status_ == VALUE_UNCHANGED) {
    140     status_ = VALUE_ROLL_BACK;
    141     VLOG(1) << "rollback: setting unchanged, nothing to do";
    142     return;
    143   }
    144 
    145   base::win::RegKey key;
    146   LONG result = key.Open(
    147       predefined_root_, key_path_.c_str(), KEY_SET_VALUE | wow64_access_);
    148   if (result != ERROR_SUCCESS) {
    149     VLOG(1) << "rollback: can not open " << key_path_ << " error: " << result;
    150     return;
    151   }
    152 
    153   if (status_ == NEW_VALUE_CREATED) {
    154     result = key.DeleteValue(value_name_.c_str());
    155     VLOG(1) << "rollback: deleting " << value_name_ << " error: " << result;
    156   } else if (status_ == VALUE_OVERWRITTEN) {
    157     const unsigned char* previous_value =
    158         previous_value_.empty() ? NULL : &previous_value_[0];
    159     result = key.WriteValue(value_name_.c_str(), previous_value,
    160                             static_cast<DWORD>(previous_value_.size()),
    161                             previous_type_);
    162     VLOG(1) << "rollback: restoring " << value_name_ << " error: " << result;
    163   } else {
    164     NOTREACHED();
    165   }
    166 
    167   status_ = VALUE_ROLL_BACK;
    168 }
    169