1 // Copyright (c) 2010 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 #include "chrome/installer/util/copy_tree_work_item.h"
9 #include "base/files/file_util.h"
10 #include "base/logging.h"
11 #include "chrome/installer/util/logging_installer.h"
13 CopyTreeWorkItem::~CopyTreeWorkItem() {
16 CopyTreeWorkItem::CopyTreeWorkItem(const base::FilePath
& source_path
,
17 const base::FilePath
& dest_path
,
18 const base::FilePath
& temp_dir
,
19 CopyOverWriteOption overwrite_option
,
20 const base::FilePath
& alternative_path
)
21 : source_path_(source_path
),
22 dest_path_(dest_path
),
24 overwrite_option_(overwrite_option
),
25 alternative_path_(alternative_path
),
26 copied_to_dest_path_(false),
27 moved_to_backup_(false),
28 copied_to_alternate_path_(false) {
31 bool CopyTreeWorkItem::Do() {
32 if (!base::PathExists(source_path_
)) {
33 LOG(ERROR
) << source_path_
.value() << " does not exist";
37 bool dest_exist
= base::PathExists(dest_path_
);
38 // handle overwrite_option_ = IF_DIFFERENT case.
40 (overwrite_option_
== WorkItem::IF_DIFFERENT
) && // only for single file
41 (!base::DirectoryExists(source_path_
)) &&
42 (!base::DirectoryExists(dest_path_
)) &&
43 (base::ContentsEqual(source_path_
, dest_path_
))) {
44 VLOG(1) << "Source file " << source_path_
.value()
45 << " and destination file " << dest_path_
.value()
46 << " are exactly same. Returning true.";
48 } else if ((dest_exist
) &&
49 (overwrite_option_
== WorkItem::NEW_NAME_IF_IN_USE
) &&
50 (!base::DirectoryExists(source_path_
)) &&
51 (!base::DirectoryExists(dest_path_
)) &&
52 (IsFileInUse(dest_path_
))) {
53 // handle overwrite_option_ = NEW_NAME_IF_IN_USE case.
54 if (alternative_path_
.empty() ||
55 base::PathExists(alternative_path_
) ||
56 !base::CopyFile(source_path_
, alternative_path_
)) {
57 LOG(ERROR
) << "failed to copy " << source_path_
.value()
58 << " to " << alternative_path_
.value();
61 copied_to_alternate_path_
= true;
62 VLOG(1) << "Copied source file " << source_path_
.value()
63 << " to alternative path " << alternative_path_
.value();
66 } else if ((dest_exist
) &&
67 (overwrite_option_
== WorkItem::IF_NOT_PRESENT
)) {
68 // handle overwrite_option_ = IF_NOT_PRESENT case.
72 // In all cases that reach here, move dest to a backup path.
74 if (!backup_path_
.CreateUniqueTempDirUnderPath(temp_dir_
)) {
75 PLOG(ERROR
) << "Failed to get backup path in folder "
80 base::FilePath backup
= backup_path_
.path().Append(dest_path_
.BaseName());
81 if (base::Move(dest_path_
, backup
)) {
82 moved_to_backup_
= true;
83 VLOG(1) << "Moved destination " << dest_path_
.value() <<
84 " to backup path " << backup
.value();
86 LOG(ERROR
) << "failed moving " << dest_path_
.value()
87 << " to " << backup
.value();
92 // In all cases that reach here, copy source to destination.
93 if (base::CopyDirectory(source_path_
, dest_path_
, true)) {
94 copied_to_dest_path_
= true;
95 VLOG(1) << "Copied source " << source_path_
.value()
96 << " to destination " << dest_path_
.value();
98 LOG(ERROR
) << "failed copy " << source_path_
.value()
99 << " to " << dest_path_
.value();
106 void CopyTreeWorkItem::Rollback() {
107 // Normally the delete operations below should not fail unless some
108 // programs like anti-virus are inspecting the files we just copied.
109 // If this does happen sometimes, we may consider using Move instead of
110 // Delete here. For now we just log the error and continue with the
111 // rest of rollback operation.
112 if (copied_to_dest_path_
&& !base::DeleteFile(dest_path_
, true)) {
113 LOG(ERROR
) << "Can not delete " << dest_path_
.value();
115 if (moved_to_backup_
) {
116 base::FilePath
backup(backup_path_
.path().Append(dest_path_
.BaseName()));
117 if (!base::Move(backup
, dest_path_
)) {
118 LOG(ERROR
) << "failed move " << backup
.value()
119 << " to " << dest_path_
.value();
122 if (copied_to_alternate_path_
&&
123 !base::DeleteFile(alternative_path_
, true)) {
124 LOG(ERROR
) << "Can not delete " << alternative_path_
.value();
128 bool CopyTreeWorkItem::IsFileInUse(const base::FilePath
& path
) {
129 if (!base::PathExists(path
))
132 HANDLE handle
= ::CreateFile(path
.value().c_str(), FILE_ALL_ACCESS
,
133 NULL
, NULL
, OPEN_EXISTING
, NULL
, NULL
);
134 if (handle
== INVALID_HANDLE_VALUE
)