OLD | NEW |
---|---|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "base/file_util.h" | 5 #include "base/file_util.h" |
6 #include "base/logging.h" | 6 #include "base/logging.h" |
7 #include "chrome/installer/util/delete_tree_work_item.h" | 7 #include "chrome/installer/util/delete_tree_work_item.h" |
8 | 8 |
9 DeleteTreeWorkItem::DeleteTreeWorkItem( | |
10 const FilePath& root_path, | |
11 const std::vector<FilePath>& key_paths) | |
12 : root_path_(root_path) { | |
13 // Populate our key_paths_ list with empty backup path values. | |
14 std::vector<FilePath>::const_iterator it = key_paths.begin(); | |
robertshield
2010/12/01 21:40:54
nitty nit: KeyFileList::const_iterator it(key_path
tommi (sloooow) - chröme
2010/12/01 22:07:15
Done.
| |
15 for (; it != key_paths.end(); ++it) { | |
16 key_paths_.push_back(KeyFileList::value_type(*it, FilePath())); | |
17 } | |
18 } | |
19 | |
9 DeleteTreeWorkItem::~DeleteTreeWorkItem() { | 20 DeleteTreeWorkItem::~DeleteTreeWorkItem() { |
10 if (!backup_path_.empty()) { | 21 if (!backup_path_.empty()) { |
11 FilePath tmp_dir = backup_path_.DirName(); | 22 FilePath tmp_dir = backup_path_.DirName(); |
12 if (file_util::PathExists(tmp_dir)) { | 23 if (file_util::PathExists(tmp_dir)) { |
13 file_util::Delete(tmp_dir, true); | 24 file_util::Delete(tmp_dir, true); |
14 } | 25 } |
15 } | 26 } |
16 if (!key_backup_path_.empty()) { | 27 |
17 FilePath tmp_dir = key_backup_path_.DirName(); | 28 KeyFileList::const_iterator it = key_paths_.begin(); |
18 if (file_util::PathExists(tmp_dir)) { | 29 for (; it != key_paths_.end(); ++it) { |
19 file_util::Delete(tmp_dir, true); | 30 if (!it->second.empty()) { |
31 FilePath tmp_dir = it->second.DirName(); | |
32 if (file_util::PathExists(tmp_dir)) { | |
33 file_util::Delete(tmp_dir, true); | |
34 } | |
20 } | 35 } |
21 } | 36 } |
22 } | 37 } |
23 | 38 |
24 DeleteTreeWorkItem::DeleteTreeWorkItem(const std::wstring& root_path, | |
25 const std::wstring& key_path) | |
26 : root_path_(root_path), | |
27 key_path_(key_path) { | |
28 } | |
29 | |
30 // We first try to move key_path_ to backup_path. If it succeeds, we go ahead | 39 // We first try to move key_path_ to backup_path. If it succeeds, we go ahead |
31 // and move the rest. | 40 // and move the rest. |
32 bool DeleteTreeWorkItem::Do() { | 41 bool DeleteTreeWorkItem::Do() { |
33 if (!key_path_.empty() && file_util::PathExists(key_path_)) { | 42 // Go through all the key files and see if we can open them exclusively |
34 if (!GetBackupPath(key_path_, &key_backup_path_) || | 43 // with only the FILE_FLAG_SHARE_DELETE flag. Once we know we have all |
robertshield
2010/12/01 21:40:54
*FILE_SHARE_DELETE
tommi (sloooow) - chröme
2010/12/01 22:07:15
Done.
| |
35 !file_util::CopyDirectory(key_path_, key_backup_path_, true) || | 44 // of them, we can delete them. |
36 !file_util::Delete(key_path_, true)) { | 45 KeyFileList::iterator it = key_paths_.begin(); |
37 LOG(ERROR) << "can not delete " << key_path_.value() | 46 std::vector<HANDLE> opened_key_files; |
38 << " OR copy it to backup path " << key_backup_path_.value(); | 47 bool abort = false; |
39 return false; | 48 for (; !abort && it != key_paths_.end(); ++it) { |
49 if (!GetBackupPath(it->first, &it->second) || | |
50 !file_util::CopyFile(it->first, it->second)) { | |
51 PLOG(ERROR) << "Could not back up: " << it->first.value(); | |
52 abort = true; | |
53 } else { | |
54 HANDLE file = ::CreateFile(it->first.value().c_str(), FILE_ALL_ACCESS, | |
55 FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, | |
56 NULL); | |
57 if (file != INVALID_HANDLE_VALUE) { | |
58 VLOG(1) << "Acquired exclusive lock for key file: " | |
59 << it->first.value(); | |
60 opened_key_files.push_back(file); | |
61 } else { | |
62 if (::GetLastError() != ERROR_FILE_NOT_FOUND) | |
63 abort = true; | |
64 PLOG(INFO) << "Failed to open " << it->first.value(); | |
65 } | |
40 } | 66 } |
41 } | 67 } |
42 | 68 |
69 if (!abort) { | |
70 // We now hold exclusive locks with "share delete" permissions for each | |
71 // of the key files and also have created backups of those files. | |
72 // We can safely delete the key files now. | |
73 it = key_paths_.begin(); | |
74 for (; !abort && it != key_paths_.end(); ++it) { | |
75 if (!file_util::Delete(it->first, true)) { | |
76 // This should not really be possible because of the above. | |
77 NOTREACHED(); | |
78 PLOG(ERROR) << "Unexpectedly could not delete " << it->first.value(); | |
79 abort = true; | |
80 } | |
81 } | |
82 } | |
83 | |
84 std::vector<HANDLE>::const_iterator file_it = opened_key_files.begin(); | |
85 for (; file_it != opened_key_files.end(); ++file_it) | |
86 ::CloseHandle(*file_it); | |
87 | |
88 opened_key_files.clear(); | |
89 | |
90 if (abort) { | |
91 LOG(ERROR) << "Could not exclusively hold all key files."; | |
92 return false; | |
93 } | |
94 | |
95 // Now that we've taken care of the key files, take care of the rest. | |
43 if (!root_path_.empty() && file_util::PathExists(root_path_)) { | 96 if (!root_path_.empty() && file_util::PathExists(root_path_)) { |
44 if (!GetBackupPath(root_path_, &backup_path_) || | 97 if (!GetBackupPath(root_path_, &backup_path_) || |
45 !file_util::CopyDirectory(root_path_, backup_path_, true) || | 98 !file_util::CopyDirectory(root_path_, backup_path_, true) || |
46 !file_util::Delete(root_path_, true)) { | 99 !file_util::Delete(root_path_, true)) { |
47 LOG(ERROR) << "can not delete " << root_path_.value() | 100 LOG(ERROR) << "can not delete " << root_path_.value() |
48 << " OR copy it to backup path " << backup_path_.value(); | 101 << " OR copy it to backup path " << backup_path_.value(); |
49 return false; | 102 return false; |
50 } | 103 } |
51 } | 104 } |
105 | |
52 return true; | 106 return true; |
53 } | 107 } |
54 | 108 |
55 // If there are files in backup paths move them back. | 109 // If there are files in backup paths move them back. |
56 void DeleteTreeWorkItem::Rollback() { | 110 void DeleteTreeWorkItem::Rollback() { |
57 if (!backup_path_.empty() && file_util::PathExists(backup_path_)) { | 111 if (!backup_path_.empty() && file_util::PathExists(backup_path_)) { |
58 file_util::Move(backup_path_, root_path_); | 112 file_util::Move(backup_path_, root_path_); |
59 } | 113 } |
60 if (!key_backup_path_.empty() && file_util::PathExists(key_backup_path_)) { | 114 |
61 file_util::Move(key_backup_path_, key_path_); | 115 KeyFileList::const_iterator it = key_paths_.begin(); |
116 for (; it != key_paths_.end(); ++it) { | |
117 if (!it->second.empty() && file_util::PathExists(it->second)) { | |
118 if (!file_util::Move(it->second, it->first)) { | |
119 // This could happen if we could not delete the key file to begin with. | |
120 PLOG(WARNING) << "Rollback: Failed to move backup file back in place: " | |
121 << it->second.value() << " to " << it->first.value(); | |
122 } | |
123 } | |
62 } | 124 } |
63 } | 125 } |
64 | 126 |
65 bool DeleteTreeWorkItem::GetBackupPath(const FilePath& for_path, | 127 bool DeleteTreeWorkItem::GetBackupPath(const FilePath& for_path, |
66 FilePath* backup_path) { | 128 FilePath* backup_path) { |
67 if (!file_util::CreateNewTempDirectory(L"", backup_path)) { | 129 if (!file_util::CreateNewTempDirectory(L"", backup_path)) { |
68 // We assume that CreateNewTempDirectory() is doing its job well. | 130 // We assume that CreateNewTempDirectory() is doing its job well. |
69 LOG(ERROR) << "Couldn't get backup path for delete."; | 131 LOG(ERROR) << "Couldn't get backup path for delete."; |
70 return false; | 132 return false; |
71 } | 133 } |
72 | 134 |
73 *backup_path = backup_path->Append(for_path.BaseName()); | 135 *backup_path = backup_path->Append(for_path.BaseName()); |
74 return true; | 136 return true; |
75 } | 137 } |
OLD | NEW |