OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/installer/util/copy_tree_work_item.h" | 5 #include "chrome/installer/util/copy_tree_work_item.h" |
6 | 6 |
7 #include <shlwapi.h> | 7 #include <shlwapi.h> |
8 | 8 |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "chrome/installer/util/logging_installer.h" | 11 #include "chrome/installer/util/logging_installer.h" |
12 | 12 |
13 CopyTreeWorkItem::~CopyTreeWorkItem() { | 13 CopyTreeWorkItem::~CopyTreeWorkItem() { |
14 if (file_util::PathExists(backup_path_)) { | |
15 file_util::Delete(backup_path_, true); | |
16 } | |
17 } | 14 } |
18 | 15 |
19 CopyTreeWorkItem::CopyTreeWorkItem(const FilePath& source_path, | 16 CopyTreeWorkItem::CopyTreeWorkItem(const FilePath& source_path, |
20 const FilePath& dest_path, | 17 const FilePath& dest_path, |
21 const FilePath& temp_dir, | 18 const FilePath& temp_dir, |
22 CopyOverWriteOption overwrite_option, | 19 CopyOverWriteOption overwrite_option, |
23 const FilePath& alternative_path) | 20 const FilePath& alternative_path) |
24 : source_path_(source_path), | 21 : source_path_(source_path), |
25 dest_path_(dest_path), | 22 dest_path_(dest_path), |
26 temp_dir_(temp_dir), | 23 temp_dir_(temp_dir), |
27 overwrite_option_(overwrite_option), | 24 overwrite_option_(overwrite_option), |
28 alternative_path_(alternative_path), | 25 alternative_path_(alternative_path), |
29 copied_to_dest_path_(false), | 26 copied_to_dest_path_(false), |
30 moved_to_backup_(false), | 27 moved_to_backup_(false), |
31 copied_to_alternate_path_(false) { | 28 copied_to_alternate_path_(false) { |
32 } | 29 } |
33 | 30 |
34 bool CopyTreeWorkItem::Do() { | 31 bool CopyTreeWorkItem::Do() { |
35 if (!file_util::PathExists(source_path_)) { | 32 if (!file_util::PathExists(source_path_)) { |
36 LOG(ERROR) << source_path_.value() << " does not exist"; | 33 LOG(ERROR) << source_path_.value() << " does not exist"; |
37 return false; | 34 return false; |
38 } | 35 } |
39 | 36 |
40 bool dest_exist = file_util::PathExists(dest_path_); | 37 bool dest_exist = file_util::PathExists(dest_path_); |
41 // handle overwrite_option_ = IF_DIFFERENT case. | 38 // handle overwrite_option_ = IF_DIFFERENT case. |
42 if ((dest_exist) && | 39 if ((dest_exist) && |
43 (overwrite_option_ == WorkItem::IF_DIFFERENT) && // only for single file | 40 (overwrite_option_ == WorkItem::IF_DIFFERENT) && // only for single file |
44 (!file_util::DirectoryExists(source_path_)) && | 41 (!file_util::DirectoryExists(source_path_)) && |
45 (!file_util::DirectoryExists(dest_path_)) && | 42 (!file_util::DirectoryExists(dest_path_)) && |
46 (file_util::ContentsEqual(source_path_, dest_path_))) { | 43 (file_util::ContentsEqual(source_path_, dest_path_))) { |
47 VLOG(1) << "Source file " << source_path_.value() | 44 VLOG(1) << "Source file " << source_path_.value() |
48 << " and destination file " << dest_path_.value() | 45 << " and destination file " << dest_path_.value() |
49 << " are exactly same. Returning true."; | 46 << " are exactly same. Returning true."; |
50 return true; | 47 return true; |
51 } else if ((dest_exist) && | 48 } else if ((dest_exist) && |
52 (overwrite_option_ == WorkItem::NEW_NAME_IF_IN_USE) && | 49 (overwrite_option_ == WorkItem::NEW_NAME_IF_IN_USE) && |
53 (!file_util::DirectoryExists(source_path_)) && | 50 (!file_util::DirectoryExists(source_path_)) && |
(...skipping 13 matching lines...) Expand all Loading... | |
67 return true; | 64 return true; |
68 } | 65 } |
69 } else if ((dest_exist) && | 66 } else if ((dest_exist) && |
70 (overwrite_option_ == WorkItem::IF_NOT_PRESENT)) { | 67 (overwrite_option_ == WorkItem::IF_NOT_PRESENT)) { |
71 // handle overwrite_option_ = IF_NOT_PRESENT case. | 68 // handle overwrite_option_ = IF_NOT_PRESENT case. |
72 return true; | 69 return true; |
73 } | 70 } |
74 | 71 |
75 // In all cases that reach here, move dest to a backup path. | 72 // In all cases that reach here, move dest to a backup path. |
76 if (dest_exist) { | 73 if (dest_exist) { |
77 if (!GetBackupPath()) | 74 if (!backup_path_.CreateUniqueTempDirUnderPath(temp_dir_)) { |
75 LOG(ERROR) << "Failed to get backup path in folder " << temp_dir_.value(); | |
tommi (sloooow) - chröme
2011/02/17 20:00:49
PLOG
grt (UTC plus 2)
2011/02/17 20:26:41
Done.
| |
78 return false; | 76 return false; |
77 } | |
79 | 78 |
80 if (file_util::Move(dest_path_, backup_path_)) { | 79 FilePath backup = backup_path_.path().Append(dest_path_.BaseName()); |
80 if (file_util::Move(dest_path_, backup)) { | |
81 moved_to_backup_ = true; | 81 moved_to_backup_ = true; |
82 VLOG(1) << "Moved destination " << dest_path_.value() << | 82 VLOG(1) << "Moved destination " << dest_path_.value() << |
83 " to backup path " << backup_path_.value(); | 83 " to backup path " << backup.value(); |
84 } else { | 84 } else { |
85 LOG(ERROR) << "failed moving " << dest_path_.value() | 85 LOG(ERROR) << "failed moving " << dest_path_.value() |
tommi (sloooow) - chröme
2011/02/17 20:00:49
I think PLOG would also be useful here (MoveFileEx
grt (UTC plus 2)
2011/02/17 20:26:41
Agreed, but I've found through experimentation tha
| |
86 << " to " << backup_path_.value(); | 86 << " to " << backup.value(); |
87 return false; | 87 return false; |
88 } | 88 } |
89 } | 89 } |
90 | 90 |
91 // In all cases that reach here, copy source to destination. | 91 // In all cases that reach here, copy source to destination. |
92 if (file_util::CopyDirectory(source_path_, dest_path_, true)) { | 92 if (file_util::CopyDirectory(source_path_, dest_path_, true)) { |
93 copied_to_dest_path_ = true; | 93 copied_to_dest_path_ = true; |
94 VLOG(1) << "Copied source " << source_path_.value() | 94 VLOG(1) << "Copied source " << source_path_.value() |
95 << " to destination " << dest_path_.value(); | 95 << " to destination " << dest_path_.value(); |
96 } else { | 96 } else { |
97 LOG(ERROR) << "failed copy " << source_path_.value() | 97 LOG(ERROR) << "failed copy " << source_path_.value() |
98 << " to " << dest_path_.value(); | 98 << " to " << dest_path_.value(); |
99 return false; | 99 return false; |
100 } | 100 } |
101 | 101 |
102 return true; | 102 return true; |
103 } | 103 } |
104 | 104 |
105 void CopyTreeWorkItem::Rollback() { | 105 void CopyTreeWorkItem::Rollback() { |
106 // Normally the delete operations below should not fail unless some | 106 // Normally the delete operations below should not fail unless some |
107 // programs like anti-virus are inpecting the files we just copied. | 107 // programs like anti-virus are inspecting the files we just copied. |
108 // If this does happen sometimes, we may consider using Move instead of | 108 // If this does happen sometimes, we may consider using Move instead of |
109 // Delete here. For now we just log the error and continue with the | 109 // Delete here. For now we just log the error and continue with the |
110 // rest of rollback operation. | 110 // rest of rollback operation. |
111 if (copied_to_dest_path_ && !file_util::Delete(dest_path_, true)) { | 111 if (copied_to_dest_path_ && !file_util::Delete(dest_path_, true)) { |
112 LOG(ERROR) << "Can not delete " << dest_path_.value(); | 112 LOG(ERROR) << "Can not delete " << dest_path_.value(); |
113 } | 113 } |
114 if (moved_to_backup_ && !file_util::Move(backup_path_, dest_path_)) { | 114 if (moved_to_backup_) { |
115 LOG(ERROR) << "failed move " << backup_path_.value() | 115 FilePath backup = backup_path_.path().Append(dest_path_.BaseName()); |
tommi (sloooow) - chröme
2011/02/17 20:00:49
FilePath backup(...);
grt (UTC plus 2)
2011/02/17 20:26:41
Done.
| |
116 << " to " << dest_path_.value(); | 116 if (!file_util::Move(backup, dest_path_)) { |
117 LOG(ERROR) << "failed move " << backup.value() | |
118 << " to " << dest_path_.value(); | |
119 } | |
117 } | 120 } |
118 if (copied_to_alternate_path_ && | 121 if (copied_to_alternate_path_ && |
119 !file_util::Delete(alternative_path_, true)) { | 122 !file_util::Delete(alternative_path_, true)) { |
120 LOG(ERROR) << "Can not delete " << alternative_path_.value(); | 123 LOG(ERROR) << "Can not delete " << alternative_path_.value(); |
121 } | 124 } |
122 } | 125 } |
123 | 126 |
124 bool CopyTreeWorkItem::IsFileInUse(const FilePath& path) { | 127 bool CopyTreeWorkItem::IsFileInUse(const FilePath& path) { |
125 if (!file_util::PathExists(path)) | 128 if (!file_util::PathExists(path)) |
126 return false; | 129 return false; |
127 | 130 |
128 HANDLE handle = ::CreateFile(path.value().c_str(), FILE_ALL_ACCESS, | 131 HANDLE handle = ::CreateFile(path.value().c_str(), FILE_ALL_ACCESS, |
129 NULL, NULL, OPEN_EXISTING, NULL, NULL); | 132 NULL, NULL, OPEN_EXISTING, NULL, NULL); |
130 if (handle == INVALID_HANDLE_VALUE) | 133 if (handle == INVALID_HANDLE_VALUE) |
131 return true; | 134 return true; |
132 | 135 |
133 CloseHandle(handle); | 136 CloseHandle(handle); |
134 return false; | 137 return false; |
135 } | 138 } |
136 | |
137 bool CopyTreeWorkItem::GetBackupPath() { | |
138 backup_path_ = temp_dir_.Append(dest_path_.BaseName()); | |
139 | |
140 if (file_util::PathExists(backup_path_)) { | |
141 // Ideally we should not fail immediately. Instead we could try some | |
142 // random paths under temp_dir_ until we reach certain limit. | |
143 // For now our caller always provides a good temporary directory so | |
144 // we don't bother. | |
145 LOG(ERROR) << "backup path " << backup_path_.value() << " already exists"; | |
146 return false; | |
147 } | |
148 | |
149 return true; | |
150 } | |
OLD | NEW |