root/chrome/installer/util/copy_reg_key_work_item.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cleared_destination_
  2. Do
  3. Rollback

// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Implementation of a work item that replaces the contents of one registry key
// with that of another (i.e., the destination is erased prior to the copy).

#include "chrome/installer/util/copy_reg_key_work_item.h"

#include <shlwapi.h>

#include "base/logging.h"
#include "base/win/registry.h"

using base::win::RegKey;

CopyRegKeyWorkItem::~CopyRegKeyWorkItem() {
}

CopyRegKeyWorkItem::CopyRegKeyWorkItem(HKEY predefined_root,
                                       const std::wstring& source_key_path,
                                       const std::wstring& dest_key_path,
                                       CopyOverWriteOption overwrite_option)
    : predefined_root_(predefined_root),
      source_key_path_(source_key_path),
      dest_key_path_(dest_key_path),
      overwrite_option_(overwrite_option),
      cleared_destination_(false) {
  DCHECK(predefined_root);
  // It's a safe bet that we don't want to copy or overwrite one of the root
  // trees.
  DCHECK(!source_key_path.empty());
  DCHECK(!dest_key_path.empty());
  DCHECK(overwrite_option == ALWAYS || overwrite_option == IF_NOT_PRESENT);
}

bool CopyRegKeyWorkItem::Do() {
  if (source_key_path_.empty() || dest_key_path_.empty())
    return false;

  // Leave immediately if we're not supposed to overwrite an existing key and
  // one is there.
  if (overwrite_option_ == IF_NOT_PRESENT &&
      RegKey(predefined_root_, dest_key_path_.c_str(),
             KEY_QUERY_VALUE).Valid()) {
    return true;
  }

  RegistryKeyBackup backup;
  RegKey dest_key;

  // Only try to make a backup if we're not configured to ignore failures.
  if (!ignore_failure_) {
    if (!backup.Initialize(predefined_root_, dest_key_path_.c_str())) {
      LOG(ERROR) << "Failed to backup destination for registry key copy.";
      return false;
    }
  }

  // Delete the destination before attempting to copy.
  LONG result = SHDeleteKey(predefined_root_, dest_key_path_.c_str());
  if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
    LOG(ERROR) << "Failed to delete key at " << dest_key_path_ << ", result: "
               << result;
  } else {
    cleared_destination_ = true;
    // We've just modified the registry, so remember any backup we may have
    // made so that Rollback can take us back where we started.
    backup_.swap(backup);
    // Make the copy.
    result = dest_key.Create(predefined_root_, dest_key_path_.c_str(),
                             KEY_WRITE);
    if (result != ERROR_SUCCESS) {
      LOG(ERROR) << "Failed to open destination key at " << dest_key_path_
                 << ", result: " << result;
    } else {
      result = SHCopyKey(predefined_root_, source_key_path_.c_str(),
                         dest_key.Handle(), 0);
      switch (result) {
        case ERROR_FILE_NOT_FOUND:
          // The source didn't exist, so neither should the destination.
          dest_key.Close();
          SHDeleteKey(predefined_root_, dest_key_path_.c_str());
          // Handle like a success.
          result = ERROR_SUCCESS;
          // -- Fall through to success case. --
        case ERROR_SUCCESS:
          break;
        default:
          LOG(ERROR) << "Failed to copy key from " << source_key_path_ << " to "
                     << dest_key_path_ << ", result: " << result;
          break;
      }
    }
  }

  return ignore_failure_ ? true : (result == ERROR_SUCCESS);
}

void CopyRegKeyWorkItem::Rollback() {
  if (ignore_failure_)
    return;

  if (cleared_destination_) {
    // Delete anything in the key before restoring the backup in case new data
    // was written after Do().
    LONG result = SHDeleteKey(predefined_root_, dest_key_path_.c_str());
    if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
      LOG(ERROR) << "Failed to delete key at " << dest_key_path_
                 << " in rollback, result: " << result;
    }

    // Restore the old contents.  The restoration takes on its default security
    // attributes; any custom attributes are lost.
    if (!backup_.WriteTo(predefined_root_, dest_key_path_.c_str()))
      LOG(ERROR) << "Failed to restore key in rollback.";
  }
}

/* [<][>][^][v][top][bottom][index][help] */