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