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.
5 // Implementation of a work item that replaces the contents of one registry key
6 // with that of another (i.e., the destination is erased prior to the copy).
8 #include "chrome/installer/util/copy_reg_key_work_item.h"
12 #include "base/logging.h"
13 #include "base/win/registry.h"
15 using base::win::RegKey
;
17 CopyRegKeyWorkItem::~CopyRegKeyWorkItem() {
20 CopyRegKeyWorkItem::CopyRegKeyWorkItem(HKEY predefined_root
,
21 const std::wstring
& source_key_path
,
22 const std::wstring
& dest_key_path
,
23 CopyOverWriteOption overwrite_option
)
24 : predefined_root_(predefined_root
),
25 source_key_path_(source_key_path
),
26 dest_key_path_(dest_key_path
),
27 overwrite_option_(overwrite_option
),
28 cleared_destination_(false) {
29 DCHECK(predefined_root
);
30 // It's a safe bet that we don't want to copy or overwrite one of the root
32 DCHECK(!source_key_path
.empty());
33 DCHECK(!dest_key_path
.empty());
34 DCHECK(overwrite_option
== ALWAYS
|| overwrite_option
== IF_NOT_PRESENT
);
37 bool CopyRegKeyWorkItem::Do() {
38 if (source_key_path_
.empty() || dest_key_path_
.empty())
41 // Leave immediately if we're not supposed to overwrite an existing key and
43 if (overwrite_option_
== IF_NOT_PRESENT
&&
44 RegKey(predefined_root_
, dest_key_path_
.c_str(),
45 KEY_QUERY_VALUE
).Valid()) {
49 RegistryKeyBackup backup
;
52 // Only try to make a backup if we're not configured to ignore failures.
53 if (!ignore_failure_
) {
54 if (!backup
.Initialize(predefined_root_
, dest_key_path_
.c_str())) {
55 LOG(ERROR
) << "Failed to backup destination for registry key copy.";
60 // Delete the destination before attempting to copy.
61 LONG result
= SHDeleteKey(predefined_root_
, dest_key_path_
.c_str());
62 if (result
!= ERROR_SUCCESS
&& result
!= ERROR_FILE_NOT_FOUND
) {
63 LOG(ERROR
) << "Failed to delete key at " << dest_key_path_
<< ", result: "
66 cleared_destination_
= true;
67 // We've just modified the registry, so remember any backup we may have
68 // made so that Rollback can take us back where we started.
71 result
= dest_key
.Create(predefined_root_
, dest_key_path_
.c_str(),
73 if (result
!= ERROR_SUCCESS
) {
74 LOG(ERROR
) << "Failed to open destination key at " << dest_key_path_
75 << ", result: " << result
;
77 result
= SHCopyKey(predefined_root_
, source_key_path_
.c_str(),
78 dest_key
.Handle(), 0);
80 case ERROR_FILE_NOT_FOUND
:
81 // The source didn't exist, so neither should the destination.
83 SHDeleteKey(predefined_root_
, dest_key_path_
.c_str());
84 // Handle like a success.
85 result
= ERROR_SUCCESS
;
86 // -- Fall through to success case. --
90 LOG(ERROR
) << "Failed to copy key from " << source_key_path_
<< " to "
91 << dest_key_path_
<< ", result: " << result
;
97 return ignore_failure_
? true : (result
== ERROR_SUCCESS
);
100 void CopyRegKeyWorkItem::Rollback() {
104 if (cleared_destination_
) {
105 // Delete anything in the key before restoring the backup in case new data
106 // was written after Do().
107 LONG result
= SHDeleteKey(predefined_root_
, dest_key_path_
.c_str());
108 if (result
!= ERROR_SUCCESS
&& result
!= ERROR_FILE_NOT_FOUND
) {
109 LOG(ERROR
) << "Failed to delete key at " << dest_key_path_
110 << " in rollback, result: " << result
;
113 // Restore the old contents. The restoration takes on its default security
114 // attributes; any custom attributes are lost.
115 if (!backup_
.WriteTo(predefined_root_
, dest_key_path_
.c_str()))
116 LOG(ERROR
) << "Failed to restore key in rollback.";