Chromium Code Reviews| 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 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 174 | 174 |
| 175 // If chrome has been reactivated, clear all events for this brand as well. | 175 // If chrome has been reactivated, clear all events for this brand as well. |
| 176 string16 reactivation_brand_wide; | 176 string16 reactivation_brand_wide; |
| 177 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) { | 177 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) { |
| 178 std::string reactivation_brand(WideToASCII(reactivation_brand_wide)); | 178 std::string reactivation_brand(WideToASCII(reactivation_brand_wide)); |
| 179 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); | 179 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); |
| 180 rlz_lib::ClearProductState(rlz_lib::CHROME, points); | 180 rlz_lib::ClearProductState(rlz_lib::CHROME, points); |
| 181 } | 181 } |
| 182 } | 182 } |
| 183 | 183 |
| 184 // Decides whether setup.exe and the installer archive should be removed based | |
| 185 // on the original and installer states: | |
| 186 // * non-multi product being uninstalled: remove both | |
| 187 // * any multi product left besides App Host: keep both | |
| 188 // * only App Host left: keep setup.exe | |
| 189 void CheckShouldRemoveSetupAndArchive( | |
| 190 const installer::InstallationState& original_state, | |
| 191 const installer::InstallerState& installer_state, | |
| 192 bool* remove_setup, | |
| 193 bool* remove_archive) { | |
| 194 *remove_setup = true; | |
| 195 *remove_archive = true; | |
| 196 | |
| 197 // If any multi-install product is left (other than App Host) we must leave | |
| 198 // the installer and archive. For the App Host, we only leave the installer. | |
| 199 if (!installer_state.is_multi_install()) { | |
| 200 VLOG(1) << "Removing all installer files for a non-multi installation."; | |
| 201 } else { | |
| 202 for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) { | |
| 203 BrowserDistribution::Type dist_type = | |
| 204 static_cast<BrowserDistribution::Type>(i); | |
| 205 const installer::ProductState* product_state = | |
| 206 original_state.GetProductState( | |
| 207 installer_state.system_install(), dist_type); | |
| 208 if (product_state && product_state->is_multi_install() && | |
| 209 !installer_state.FindProduct(dist_type)) { | |
|
gab
2012/11/30 15:19:45
Does !installer_state.FindProduct(dist_type) here
gab
2012/12/21 21:55:53
Ping.
erikwright (departed)
2013/01/04 20:07:50
Done.
| |
| 210 *remove_setup = false; | |
| 211 if (dist_type != BrowserDistribution::CHROME_APP_HOST) { | |
| 212 VLOG(1) << "Keeping all installer files due to a remaining " | |
| 213 << "multi-install product."; | |
| 214 *remove_archive = false; | |
| 215 return; | |
| 216 } | |
| 217 VLOG(1) << "Keeping setup.exe due to a remaining " | |
| 218 << "app-host installation."; | |
| 219 } | |
| 220 } | |
| 221 VLOG(1) << "Removing the installer archive."; | |
| 222 if (remove_setup) | |
| 223 VLOG(1) << "Removing setup.exe."; | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 // Removes all files from the installer directory, leaving setup.exe iff | |
| 228 // |remove_setup| is false. | |
| 229 // Returns false in case of an error. | |
| 230 bool RemoveInstallerFiles(const FilePath& install_directory, | |
|
gab
2012/11/30 15:19:45
s/install_directory/installer_directory
imo, the
gab
2012/12/21 21:55:53
Ping.
erikwright (departed)
2013/01/04 20:07:50
Done.
| |
| 231 bool remove_setup) { | |
| 232 using file_util::FileEnumerator; | |
| 233 FileEnumerator file_enumerator( | |
| 234 install_directory, | |
| 235 false, | |
| 236 FileEnumerator::FILES | FileEnumerator::DIRECTORIES); | |
| 237 bool success = true; | |
| 238 | |
| 239 FilePath setup_exe_base_name(installer::kSetupExe); | |
| 240 | |
| 241 while (true) { | |
| 242 FilePath to_delete(file_enumerator.Next()); | |
| 243 if (to_delete.empty()) | |
| 244 break; | |
| 245 if (!remove_setup && to_delete.BaseName() == setup_exe_base_name) | |
| 246 continue; | |
| 247 | |
| 248 VLOG(1) << "Deleting install path " << to_delete.value(); | |
|
gab
2012/11/30 15:19:45
s/install/installer (same comment as above).
gab
2012/12/21 21:55:53
Ping.
erikwright (departed)
2013/01/04 20:07:50
Done.
| |
| 249 if (!file_util::Delete(to_delete, true)) { | |
| 250 LOG(ERROR) << "Failed to delete path: " << to_delete.value(); | |
| 251 success = false; | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 return success; | |
| 256 } | |
| 257 | |
| 184 } // namespace | 258 } // namespace |
| 185 | 259 |
| 186 namespace installer { | 260 namespace installer { |
| 187 | 261 |
| 188 // This functions checks for any Chrome instances that are | 262 // This functions checks for any Chrome instances that are |
| 189 // running and first asks them to close politely by sending a Windows message. | 263 // running and first asks them to close politely by sending a Windows message. |
| 190 // If there is an error while sending message or if there are still Chrome | 264 // If there is an error while sending message or if there are still Chrome |
| 191 // procesess active after the message has been sent, this function will try | 265 // procesess active after the message has been sent, this function will try |
| 192 // to kill them. | 266 // to kill them. |
| 193 void CloseAllChromeProcesses() { | 267 void CloseAllChromeProcesses() { |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 403 const FilePath product_dir(user_data_dir.DirName()); | 477 const FilePath product_dir(user_data_dir.DirName()); |
| 404 if (!product_dir.empty()) | 478 if (!product_dir.empty()) |
| 405 DeleteEmptyDir(product_dir); | 479 DeleteEmptyDir(product_dir); |
| 406 } | 480 } |
| 407 } | 481 } |
| 408 | 482 |
| 409 return result; | 483 return result; |
| 410 } | 484 } |
| 411 | 485 |
| 412 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, | 486 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, |
| 413 const FilePath& setup_path, | 487 const FilePath& setup_exe) { |
| 414 const Version& installed_version) { | |
| 415 bool ret = false; | 488 bool ret = false; |
| 416 FilePath setup_exe(installer_state.GetInstallerDirectory(installed_version) | |
| 417 .Append(setup_path.BaseName())); | |
| 418 FilePath temp_file; | 489 FilePath temp_file; |
| 419 if (!file_util::CreateTemporaryFile(&temp_file)) { | 490 if (!file_util::CreateTemporaryFile(&temp_file)) { |
| 420 LOG(ERROR) << "Failed to create temporary file for setup.exe."; | 491 LOG(ERROR) << "Failed to create temporary file for setup.exe."; |
| 421 } else { | 492 } else { |
| 422 VLOG(1) << "Attempting to move setup to: " << temp_file.value(); | 493 VLOG(1) << "Attempting to move setup to: " << temp_file.value(); |
| 423 ret = file_util::Move(setup_exe, temp_file); | 494 ret = file_util::Move(setup_exe, temp_file); |
| 424 PLOG_IF(ERROR, !ret) << "Failed to move setup to " << temp_file.value(); | 495 PLOG_IF(ERROR, !ret) << "Failed to move setup to " << temp_file.value(); |
| 425 | 496 |
| 426 // We cannot delete the file right away, but try to delete it some other | 497 // We cannot delete the file right away, but try to delete it some other |
| 427 // way. Either with the help of a different process or the system. | 498 // way. Either with the help of a different process or the system. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 464 } | 535 } |
| 465 | 536 |
| 466 DeleteInstallTempDir(target_path); | 537 DeleteInstallTempDir(target_path); |
| 467 | 538 |
| 468 DeleteResult result = DELETE_SUCCEEDED; | 539 DeleteResult result = DELETE_SUCCEEDED; |
| 469 | 540 |
| 470 FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe)); | 541 FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe)); |
| 471 if (!file_util::Delete(app_host_exe, false)) { | 542 if (!file_util::Delete(app_host_exe, false)) { |
| 472 result = DELETE_FAILED; | 543 result = DELETE_FAILED; |
| 473 LOG(ERROR) << "Failed to delete path: " << app_host_exe.value(); | 544 LOG(ERROR) << "Failed to delete path: " << app_host_exe.value(); |
| 474 } else { | |
| 475 result = DeleteApplicationProductAndVendorDirectories(target_path); | |
| 476 } | 545 } |
| 477 | 546 |
| 478 return result; | 547 return result; |
| 479 } | 548 } |
| 480 | 549 |
| 481 DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state, | 550 DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state, |
| 482 const Version& installed_version) { | 551 const FilePath& installer_path) { |
|
gab
2012/11/30 15:19:45
s/installer_path/setup_exe to respect naming conve
gab
2012/12/21 21:55:53
Ping.
erikwright (departed)
2013/01/04 20:07:50
I chose not to change what is passed in, as that w
| |
| 483 const FilePath& target_path = installer_state.target_path(); | 552 const FilePath& target_path = installer_state.target_path(); |
| 484 if (target_path.empty()) { | 553 if (target_path.empty()) { |
| 485 LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination " | 554 LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination " |
| 486 << "path."; | 555 << "path."; |
| 487 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. | 556 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. |
| 488 } | 557 } |
| 489 | 558 |
| 490 DeleteInstallTempDir(target_path); | 559 DeleteInstallTempDir(target_path); |
| 491 | 560 |
| 492 DeleteResult result = DELETE_SUCCEEDED; | 561 DeleteResult result = DELETE_SUCCEEDED; |
| 493 | 562 |
| 563 FilePath installer_directory; | |
| 564 if (target_path.IsParent(installer_path)) | |
| 565 installer_directory = installer_path.DirName(); | |
|
gab
2012/11/30 15:19:45
This feels weird, isn't this always expected to be
gab
2012/12/21 21:55:53
Ping.
erikwright (departed)
2013/01/04 20:07:50
Not necessarily. For example, if you execute the i
| |
| 566 | |
| 567 // Enumerate all the files in target_path recursively (breadth-first). | |
| 568 // We delete a file or folder unless it is a parent/child of the installer | |
| 569 // directory. For parents of the installer directory, we will later recurse | |
| 570 // and delete all the children (that are not also parents/children of the | |
| 571 // installer directory). | |
| 494 using file_util::FileEnumerator; | 572 using file_util::FileEnumerator; |
| 495 FileEnumerator file_enumerator(target_path, false, | 573 FileEnumerator file_enumerator( |
| 496 FileEnumerator::FILES | FileEnumerator::DIRECTORIES); | 574 target_path, true, FileEnumerator::FILES | FileEnumerator::DIRECTORIES); |
| 497 while (true) { | 575 while (true) { |
| 498 FilePath to_delete(file_enumerator.Next()); | 576 FilePath to_delete(file_enumerator.Next()); |
| 499 if (to_delete.empty()) | 577 if (to_delete.empty()) |
| 500 break; | 578 break; |
| 501 if (to_delete.BaseName().value() == installer::kChromeAppHostExe) | 579 if (to_delete.BaseName().value() == installer::kChromeAppHostExe) |
| 502 continue; | 580 continue; |
| 581 if (!installer_directory.empty() && | |
| 582 (to_delete == installer_directory || | |
| 583 installer_directory.IsParent(to_delete) || | |
| 584 to_delete.IsParent(installer_directory))) { | |
| 585 continue; | |
| 586 } | |
| 503 | 587 |
| 504 VLOG(1) << "Deleting install path " << to_delete.value(); | 588 VLOG(1) << "Deleting install path " << to_delete.value(); |
| 505 if (!file_util::Delete(to_delete, true)) { | 589 if (!file_util::Delete(to_delete, true)) { |
| 506 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); | 590 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); |
| 507 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { | 591 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { |
| 508 // We don't try killing Chrome processes for Chrome Frame builds since | 592 // We don't try killing Chrome processes for Chrome Frame builds since |
| 509 // that is unlikely to help. Instead, schedule files for deletion and | 593 // that is unlikely to help. Instead, schedule files for deletion and |
| 510 // return a value that will trigger a reboot prompt. | 594 // return a value that will trigger a reboot prompt. |
| 511 FileEnumerator::FindInfo find_info; | 595 FileEnumerator::FindInfo find_info; |
| 512 file_enumerator.GetFindInfo(&find_info); | 596 file_enumerator.GetFindInfo(&find_info); |
| 513 if (FileEnumerator::IsDirectory(find_info)) | 597 if (FileEnumerator::IsDirectory(find_info)) |
| 514 ScheduleDirectoryForDeletion(to_delete.value().c_str()); | 598 ScheduleDirectoryForDeletion(to_delete.value().c_str()); |
| 515 else | 599 else |
| 516 ScheduleFileSystemEntityForDeletion(to_delete.value().c_str()); | 600 ScheduleFileSystemEntityForDeletion(to_delete.value().c_str()); |
| 517 result = DELETE_REQUIRES_REBOOT; | 601 result = DELETE_REQUIRES_REBOOT; |
| 518 } else { | 602 } else { |
| 519 // Try closing any running Chrome processes and deleting files once | 603 // Try closing any running Chrome processes and deleting files once |
| 520 // again. | 604 // again. |
| 521 CloseAllChromeProcesses(); | 605 CloseAllChromeProcesses(); |
| 522 if (!file_util::Delete(to_delete, true)) { | 606 if (!file_util::Delete(to_delete, true)) { |
| 523 LOG(ERROR) << "Failed to delete path (2nd try): " | 607 LOG(ERROR) << "Failed to delete path (2nd try): " |
| 524 << to_delete.value(); | 608 << to_delete.value(); |
| 525 result = DELETE_FAILED; | 609 result = DELETE_FAILED; |
| 526 break; | 610 break; |
| 527 } | 611 } |
| 528 } | 612 } |
| 529 } | 613 } |
| 530 } | 614 } |
| 531 | 615 |
| 532 if (result == DELETE_REQUIRES_REBOOT) { | |
| 533 // Delete the Application directory at reboot if empty. | |
| 534 ScheduleFileSystemEntityForDeletion(target_path.value().c_str()); | |
| 535 | |
| 536 // If we need a reboot to continue, schedule the parent directories for | |
| 537 // deletion unconditionally. If they are not empty, the session manager | |
| 538 // will not delete them on reboot. | |
| 539 ScheduleParentAndGrandparentForDeletion(target_path); | |
| 540 } else { | |
| 541 result = DeleteApplicationProductAndVendorDirectories(target_path); | |
| 542 } | |
| 543 return result; | 616 return result; |
| 544 } | 617 } |
| 545 | 618 |
| 546 // This method checks if Chrome is currently running or if the user has | 619 // This method checks if Chrome is currently running or if the user has |
| 547 // cancelled the uninstall operation by clicking Cancel on the confirmation | 620 // cancelled the uninstall operation by clicking Cancel on the confirmation |
| 548 // box that Chrome pops up. | 621 // box that Chrome pops up. |
| 549 InstallStatus IsChromeActiveOrUserCancelled( | 622 InstallStatus IsChromeActiveOrUserCancelled( |
| 550 const InstallerState& installer_state, | 623 const InstallerState& installer_state, |
| 551 const Product& product) { | 624 const Product& product) { |
| 552 int32 exit_code = content::RESULT_CODE_NORMAL_EXIT; | 625 int32 exit_code = content::RESULT_CODE_NORMAL_EXIT; |
| (...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1227 product); | 1300 product); |
| 1228 ret = installer::UNINSTALL_SUCCESSFUL; | 1301 ret = installer::UNINSTALL_SUCCESSFUL; |
| 1229 | 1302 |
| 1230 // When deleting files, we must make sure that we're either a "single" | 1303 // When deleting files, we must make sure that we're either a "single" |
| 1231 // (aka non-multi) installation or we are the Chrome Binaries. | 1304 // (aka non-multi) installation or we are the Chrome Binaries. |
| 1232 | 1305 |
| 1233 std::vector<FilePath> local_state_folders; | 1306 std::vector<FilePath> local_state_folders; |
| 1234 GetLocalStateFolders(product, &local_state_folders); | 1307 GetLocalStateFolders(product, &local_state_folders); |
| 1235 FilePath backup_state_file(BackupLocalStateFile(local_state_folders)); | 1308 FilePath backup_state_file(BackupLocalStateFile(local_state_folders)); |
| 1236 | 1309 |
| 1237 DeleteResult delete_result = DELETE_SUCCEEDED; | |
| 1238 | |
| 1239 if (product.is_chrome_app_host()) { | 1310 if (product.is_chrome_app_host()) { |
| 1240 DeleteAppHostFilesAndFolders(installer_state, product_state->version()); | 1311 DeleteAppHostFilesAndFolders(installer_state, product_state->version()); |
| 1241 } else if (!installer_state.is_multi_install() || | 1312 } else if (!installer_state.is_multi_install() || |
| 1242 product.is_chrome_binaries()) { | 1313 product.is_chrome_binaries()) { |
| 1243 | 1314 DeleteResult delete_result = DeleteChromeFilesAndFolders( |
| 1244 // In order to be able to remove the folder in which we're running, we | 1315 installer_state, cmd_line.GetProgram()); |
|
gab
2012/11/30 15:19:45
cmd_line.GetProgram() could be relative path here.
gab
2012/12/21 21:55:53
Ping++
erikwright (departed)
2013/01/04 20:07:50
Done.
| |
| 1245 // need to move setup.exe out of the install folder. | 1316 if (delete_result == DELETE_FAILED) { |
| 1246 // TODO(tommi): What if the temp folder is on a different volume? | 1317 ret = installer::UNINSTALL_FAILED; |
| 1247 MoveSetupOutOfInstallFolder(installer_state, setup_path, | 1318 } else if (delete_result == DELETE_REQUIRES_REBOOT) { |
| 1248 product_state->version()); | 1319 ret = installer::UNINSTALL_REQUIRES_REBOOT; |
| 1249 delete_result = DeleteChromeFilesAndFolders(installer_state, | 1320 } |
| 1250 product_state->version()); | |
| 1251 } | 1321 } |
| 1252 | 1322 |
| 1253 if (delete_profile) | 1323 if (delete_profile) |
| 1254 DeleteLocalState(local_state_folders, product.is_chrome_frame()); | 1324 DeleteLocalState(local_state_folders, product.is_chrome_frame()); |
| 1255 | 1325 |
| 1256 if (delete_result == DELETE_FAILED) { | |
| 1257 ret = installer::UNINSTALL_FAILED; | |
| 1258 } else if (delete_result == DELETE_REQUIRES_REBOOT) { | |
| 1259 ret = installer::UNINSTALL_REQUIRES_REBOOT; | |
| 1260 } | |
| 1261 | |
| 1262 if (!force_uninstall) { | 1326 if (!force_uninstall) { |
| 1263 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; | 1327 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; |
| 1264 browser_dist->DoPostUninstallOperations(product_state->version(), | 1328 browser_dist->DoPostUninstallOperations(product_state->version(), |
| 1265 backup_state_file, distribution_data); | 1329 backup_state_file, distribution_data); |
| 1266 } | 1330 } |
| 1267 | 1331 |
| 1268 // Try and delete the preserved local state once the post-install | 1332 // Try and delete the preserved local state once the post-install |
| 1269 // operations are complete. | 1333 // operations are complete. |
| 1270 if (!backup_state_file.empty()) | 1334 if (!backup_state_file.empty()) |
| 1271 file_util::Delete(backup_state_file, false); | 1335 file_util::Delete(backup_state_file, false); |
| 1272 | 1336 |
| 1273 return ret; | 1337 return ret; |
| 1274 } | 1338 } |
| 1275 | 1339 |
| 1340 void CleanUpInstallationDirectoryAfterUninstall( | |
| 1341 const InstallationState& original_state, | |
| 1342 const InstallerState& installer_state, | |
| 1343 const CommandLine& cmd_line, | |
| 1344 installer::InstallStatus* uninstall_status) { | |
| 1345 if (*uninstall_status != installer::UNINSTALL_SUCCESSFUL && | |
| 1346 *uninstall_status != installer::UNINSTALL_REQUIRES_REBOOT) { | |
| 1347 return; | |
| 1348 } | |
| 1349 const FilePath target_path(installer_state.target_path()); | |
| 1350 if (target_path.empty()) { | |
| 1351 LOG(ERROR) << "No installation destination path."; | |
| 1352 *uninstall_status = installer::UNINSTALL_FAILED; | |
| 1353 return; | |
| 1354 } | |
| 1355 FilePath setup_exe(cmd_line.GetProgram()); | |
| 1356 file_util::AbsolutePath(&setup_exe); | |
| 1357 if (!target_path.IsParent(setup_exe)) { | |
| 1358 LOG(INFO) << "setup.exe is not in target path. Skipping installer cleanup."; | |
| 1359 return; | |
| 1360 } | |
| 1361 FilePath install_directory(setup_exe.DirName()); | |
| 1362 | |
| 1363 bool remove_setup = true; | |
| 1364 bool remove_archive = true; | |
| 1365 CheckShouldRemoveSetupAndArchive(original_state, installer_state, | |
| 1366 &remove_setup, &remove_archive); | |
| 1367 if (!remove_archive) | |
| 1368 return; | |
| 1369 | |
| 1370 if (remove_setup) { | |
| 1371 // In order to be able to remove the folder in which we're running, we | |
| 1372 // need to move setup.exe out of the install folder. | |
| 1373 // TODO(tommi): What if the temp folder is on a different volume? | |
| 1374 MoveSetupOutOfInstallFolder(installer_state, setup_exe); | |
| 1375 } | |
| 1376 | |
| 1377 // Remove files from "...\<product>\Application\<version>\Installer" | |
| 1378 if (!RemoveInstallerFiles(install_directory, remove_setup)) { | |
| 1379 *uninstall_status = installer::UNINSTALL_FAILED; | |
| 1380 return; | |
| 1381 } | |
| 1382 | |
| 1383 if (!remove_setup) | |
| 1384 return; | |
| 1385 | |
| 1386 // Try to remove the empty directory hierarchy. | |
| 1387 | |
| 1388 // Delete "...\<product>\Application\<version>\Installer" | |
| 1389 if (DeleteEmptyDir(install_directory) != DELETE_SUCCEEDED) { | |
| 1390 *uninstall_status = installer::UNINSTALL_FAILED; | |
| 1391 return; | |
| 1392 } | |
| 1393 | |
| 1394 // Delete "...\<product>\Application\<version>" | |
| 1395 DeleteResult delete_result = DeleteEmptyDir(install_directory.DirName()); | |
| 1396 if (delete_result == DELETE_FAILED || | |
| 1397 (delete_result == DELETE_NOT_EMPTY && | |
| 1398 *uninstall_status != installer::UNINSTALL_REQUIRES_REBOOT)) { | |
| 1399 *uninstall_status = installer::UNINSTALL_FAILED; | |
| 1400 return; | |
| 1401 } | |
| 1402 | |
| 1403 if (*uninstall_status == installer::UNINSTALL_REQUIRES_REBOOT) { | |
| 1404 // Delete the Application directory at reboot if empty. | |
| 1405 ScheduleFileSystemEntityForDeletion(target_path.value().c_str()); | |
| 1406 | |
| 1407 // If we need a reboot to continue, schedule the parent directories for | |
| 1408 // deletion unconditionally. If they are not empty, the session manager | |
| 1409 // will not delete them on reboot. | |
| 1410 ScheduleParentAndGrandparentForDeletion(target_path); | |
| 1411 } else if (DeleteApplicationProductAndVendorDirectories(target_path) == | |
| 1412 installer::DELETE_FAILED) { | |
| 1413 *uninstall_status = installer::UNINSTALL_FAILED; | |
| 1414 } | |
| 1415 } | |
| 1416 | |
| 1276 } // namespace installer | 1417 } // namespace installer |
| OLD | NEW |