OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // This file defines the methods useful for uninstalling Chrome. | 5 // This file defines the methods useful for uninstalling Chrome. |
6 | 6 |
7 #include "chrome/installer/setup/uninstall.h" | 7 #include "chrome/installer/setup/uninstall.h" |
8 | 8 |
9 #include <windows.h> | 9 #include <windows.h> |
10 | 10 |
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
332 if (!parent_dir.empty() && file_util::IsDirectoryEmpty(parent_dir)) { | 332 if (!parent_dir.empty() && file_util::IsDirectoryEmpty(parent_dir)) { |
333 if (!file_util::Delete(parent_dir, true)) { | 333 if (!file_util::Delete(parent_dir, true)) { |
334 ret = false; | 334 ret = false; |
335 LOG(ERROR) << "Failed to delete folder: " << parent_dir.value(); | 335 LOG(ERROR) << "Failed to delete folder: " << parent_dir.value(); |
336 } | 336 } |
337 } | 337 } |
338 } | 338 } |
339 return ret; | 339 return ret; |
340 } | 340 } |
341 | 341 |
342 FilePath GetLocalStateFolder(const Product& product) { | 342 void GetLocalStateFolders(const Product& product, |
343 std::vector<FilePath>* paths) { | |
343 // Obtain the location of the user profile data. | 344 // Obtain the location of the user profile data. |
344 FilePath local_state_folder = product.GetUserDataPath(); | 345 product.GetUserDataPaths(paths); |
345 LOG_IF(ERROR, local_state_folder.empty()) | 346 LOG_IF(ERROR, paths->empty()) |
346 << "Could not retrieve user's profile directory."; | 347 << "Could not retrieve user's profile directory."; |
347 | |
348 return local_state_folder; | |
349 } | 348 } |
350 | 349 |
351 // Creates a copy of the local state file and returns a path to the copy. | 350 // Creates a copy of the local state file and returns a path to the copy. |
352 FilePath BackupLocalStateFile(const FilePath& local_state_folder) { | 351 FilePath BackupLocalStateFile( |
352 const std::vector<FilePath>& local_state_folders) { | |
353 FilePath backup; | 353 FilePath backup; |
354 FilePath state_file(local_state_folder.Append(chrome::kLocalStateFilename)); | 354 |
355 if (!file_util::CreateTemporaryFile(&backup)) { | 355 // Copy the first local state file that is found. |
356 LOG(ERROR) << "Failed to create temporary file for Local State."; | 356 for (size_t i = 0; i < local_state_folders.size(); ++i) { |
gab
2012/08/03 17:54:20
Is it ok if the Metro directory comes out of this?
grt (UTC plus 2)
2012/08/03 20:18:37
Yes. Ideally, we'd aggregate the metrics from bot
| |
357 } else { | 357 const FilePath& local_state_folder = local_state_folders[i]; |
358 file_util::CopyFile(state_file, backup); | 358 FilePath state_file(local_state_folder.Append(chrome::kLocalStateFilename)); |
359 if (!file_util::PathExists(state_file)) | |
360 continue; | |
361 if (!file_util::CreateTemporaryFile(&backup)) | |
362 LOG(ERROR) << "Failed to create temporary file for Local State."; | |
363 else | |
364 file_util::CopyFile(state_file, backup); | |
365 break; | |
359 } | 366 } |
360 return backup; | 367 return backup; |
361 } | 368 } |
362 | 369 |
363 enum DeleteResult { | 370 enum DeleteResult { |
364 DELETE_SUCCEEDED, | 371 DELETE_SUCCEEDED, |
365 DELETE_FAILED, | 372 DELETE_FAILED, |
366 DELETE_REQUIRES_REBOOT, | 373 DELETE_REQUIRES_REBOOT, |
367 }; | 374 }; |
368 | 375 |
369 // Copies the local state to the temp folder and then deletes it. | 376 // Deletes all user data directories for a product. |
370 // The path to the copy is returned via the local_state_copy parameter. | 377 DeleteResult DeleteLocalState(const std::vector<FilePath>& local_state_folders, |
371 DeleteResult DeleteLocalState(const Product& product) { | 378 bool schedule_on_failure) { |
372 FilePath user_local_state(GetLocalStateFolder(product)); | 379 if (local_state_folders.empty()) |
373 if (user_local_state.empty()) | |
374 return DELETE_SUCCEEDED; | 380 return DELETE_SUCCEEDED; |
gab
2012/08/03 17:54:20
I think this should be: {
NOTREACHED();
return
grt (UTC plus 2)
2012/08/03 20:18:37
I added a DCHECK to GetChromeUserDataPaths() rathe
gab
2012/08/03 20:42:41
Yes, but I still think the return statement here s
grt (UTC plus 2)
2012/08/03 20:56:34
hmm. i disagree (although it's purely academic si
gab
2012/08/03 21:58:57
Ah ok I see your point, given the returned value i
grt (UTC plus 2)
2012/08/04 19:25:20
After more thought, I like this as-is. The fact t
gab
2012/08/05 06:27:39
sgtm
| |
375 | 381 |
376 DeleteResult result = DELETE_SUCCEEDED; | 382 DeleteResult result = DELETE_SUCCEEDED; |
377 VLOG(1) << "Deleting user profile " << user_local_state.value(); | 383 const FilePath *user_local_state = NULL; |
gab
2012/08/03 17:54:20
Move this in the for loop (see comment below as to
grt (UTC plus 2)
2012/08/03 20:18:37
Done.
| |
378 if (!file_util::Delete(user_local_state, true)) { | 384 for (size_t i = 0; i < local_state_folders.size(); ++i) { |
379 LOG(ERROR) << "Failed to delete user profile dir: " | 385 user_local_state = &local_state_folders[i]; |
380 << user_local_state.value(); | 386 VLOG(1) << "Deleting user profile " << user_local_state->value(); |
381 if (product.is_chrome_frame()) { | 387 if (!file_util::Delete(*user_local_state, true)) { |
382 ScheduleDirectoryForDeletion(user_local_state.value().c_str()); | 388 LOG(ERROR) << "Failed to delete user profile dir: " |
383 result = DELETE_REQUIRES_REBOOT; | 389 << user_local_state->value(); |
384 } else { | 390 if (schedule_on_failure) { |
385 result = DELETE_FAILED; | 391 ScheduleDirectoryForDeletion(user_local_state->value().c_str()); |
392 result = DELETE_REQUIRES_REBOOT; | |
393 } else { | |
394 result = DELETE_FAILED; | |
395 } | |
386 } | 396 } |
387 } | 397 } |
388 | 398 |
389 if (result == DELETE_REQUIRES_REBOOT) { | 399 if (user_local_state) { |
gab
2012/08/03 17:54:20
This check is unnecessary given you only proceed i
grt (UTC plus 2)
2012/08/03 20:18:37
Done.
| |
390 ScheduleParentAndGrandparentForDeletion(user_local_state); | 400 if (result == DELETE_REQUIRES_REBOOT) { |
391 } else { | 401 ScheduleParentAndGrandparentForDeletion(*user_local_state); |
gab
2012/08/03 17:54:20
You can use local_state_folders[0] here instead (g
grt (UTC plus 2)
2012/08/03 20:18:37
Done.
| |
392 DeleteEmptyParentDir(user_local_state); | 402 } else { |
403 DeleteEmptyParentDir(*user_local_state); | |
404 } | |
393 } | 405 } |
394 | 406 |
395 return result; | 407 return result; |
396 } | 408 } |
397 | 409 |
398 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, | 410 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, |
399 const FilePath& setup_path, | 411 const FilePath& setup_path, |
400 const Version& installed_version) { | 412 const Version& installed_version) { |
401 bool ret = false; | 413 bool ret = false; |
402 FilePath setup_exe(installer_state.GetInstallerDirectory(installed_version) | 414 FilePath setup_exe(installer_state.GetInstallerDirectory(installed_version) |
(...skipping 691 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1094 | 1106 |
1095 // Finally delete all the files from Chrome folder after moving setup.exe | 1107 // Finally delete all the files from Chrome folder after moving setup.exe |
1096 // and the user's Local State to a temp location. | 1108 // and the user's Local State to a temp location. |
1097 bool delete_profile = ShouldDeleteProfile(installer_state, cmd_line, status, | 1109 bool delete_profile = ShouldDeleteProfile(installer_state, cmd_line, status, |
1098 product); | 1110 product); |
1099 ret = installer::UNINSTALL_SUCCESSFUL; | 1111 ret = installer::UNINSTALL_SUCCESSFUL; |
1100 | 1112 |
1101 // When deleting files, we must make sure that we're either a "single" | 1113 // When deleting files, we must make sure that we're either a "single" |
1102 // (aka non-multi) installation or we are the Chrome Binaries. | 1114 // (aka non-multi) installation or we are the Chrome Binaries. |
1103 | 1115 |
1104 FilePath backup_state_file( | 1116 std::vector<FilePath> local_state_folders; |
1105 BackupLocalStateFile(GetLocalStateFolder(product))); | 1117 GetLocalStateFolders(product, &local_state_folders); |
1118 FilePath backup_state_file(BackupLocalStateFile(local_state_folders)); | |
1106 | 1119 |
1107 DeleteResult delete_result = DELETE_SUCCEEDED; | 1120 DeleteResult delete_result = DELETE_SUCCEEDED; |
1108 | 1121 |
1109 if (product.is_chrome_app_host()) { | 1122 if (product.is_chrome_app_host()) { |
1110 DeleteAppHostFilesAndFolders(installer_state, product_state->version()); | 1123 DeleteAppHostFilesAndFolders(installer_state, product_state->version()); |
1111 } else if (!installer_state.is_multi_install() || | 1124 } else if (!installer_state.is_multi_install() || |
1112 product.is_chrome_binaries()) { | 1125 product.is_chrome_binaries()) { |
1113 | 1126 |
1114 // In order to be able to remove the folder in which we're running, we | 1127 // In order to be able to remove the folder in which we're running, we |
1115 // need to move setup.exe out of the install folder. | 1128 // need to move setup.exe out of the install folder. |
1116 // TODO(tommi): What if the temp folder is on a different volume? | 1129 // TODO(tommi): What if the temp folder is on a different volume? |
1117 MoveSetupOutOfInstallFolder(installer_state, setup_path, | 1130 MoveSetupOutOfInstallFolder(installer_state, setup_path, |
1118 product_state->version()); | 1131 product_state->version()); |
1119 delete_result = DeleteChromeFilesAndFolders(installer_state, | 1132 delete_result = DeleteChromeFilesAndFolders(installer_state, |
1120 product_state->version()); | 1133 product_state->version()); |
1121 } | 1134 } |
1122 | 1135 |
1123 if (delete_profile) | 1136 if (delete_profile) |
1124 DeleteLocalState(product); | 1137 DeleteLocalState(local_state_folders, product.is_chrome_frame()); |
1125 | 1138 |
1126 if (delete_result == DELETE_FAILED) { | 1139 if (delete_result == DELETE_FAILED) { |
1127 ret = installer::UNINSTALL_FAILED; | 1140 ret = installer::UNINSTALL_FAILED; |
1128 } else if (delete_result == DELETE_REQUIRES_REBOOT) { | 1141 } else if (delete_result == DELETE_REQUIRES_REBOOT) { |
1129 ret = installer::UNINSTALL_REQUIRES_REBOOT; | 1142 ret = installer::UNINSTALL_REQUIRES_REBOOT; |
1130 } | 1143 } |
1131 | 1144 |
1132 if (!force_uninstall) { | 1145 if (!force_uninstall) { |
1133 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; | 1146 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; |
1134 browser_dist->DoPostUninstallOperations(product_state->version(), | 1147 browser_dist->DoPostUninstallOperations(product_state->version(), |
1135 backup_state_file, distribution_data); | 1148 backup_state_file, distribution_data); |
1136 } | 1149 } |
1137 | 1150 |
1138 // Try and delete the preserved local state once the post-install | 1151 // Try and delete the preserved local state once the post-install |
1139 // operations are complete. | 1152 // operations are complete. |
1140 if (!backup_state_file.empty()) | 1153 if (!backup_state_file.empty()) |
1141 file_util::Delete(backup_state_file, false); | 1154 file_util::Delete(backup_state_file, false); |
1142 | 1155 |
1143 return ret; | 1156 return ret; |
1144 } | 1157 } |
1145 | 1158 |
1146 } // namespace installer | 1159 } // namespace installer |
OLD | NEW |