Chromium Code Reviews| 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 |