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()); |
| 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_SHARE_DELETE flag. Once we know we have all of them, |
35 !file_util::CopyDirectory(key_path_, key_backup_path_, true) || | 44 // 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 |