Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1224)

Side by Side Diff: chrome/installer/setup/uninstall.cc

Issue 10832210: Delete the installation folder after deleting its contents. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review comments. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 300 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 FilePath grandparent_dir(parent_dir.DirName()); 311 FilePath grandparent_dir(parent_dir.DirName());
312 ret = ScheduleFileSystemEntityForDeletion(grandparent_dir.value().c_str()); 312 ret = ScheduleFileSystemEntityForDeletion(grandparent_dir.value().c_str());
313 if (!ret) { 313 if (!ret) {
314 LOG(ERROR) << "Failed to schedule grandparent dir for deletion: " 314 LOG(ERROR) << "Failed to schedule grandparent dir for deletion: "
315 << grandparent_dir.value(); 315 << grandparent_dir.value();
316 } 316 }
317 } 317 }
318 return ret; 318 return ret;
319 } 319 }
320 320
321 // Deletes empty parent & empty grandparent dir of given path. 321 enum DeleteResult {
322 bool DeleteEmptyParentDir(const FilePath& path) { 322 DELETE_SUCCEEDED,
323 bool ret = true; 323 DELETE_NOT_EMPTY,
324 FilePath parent_dir = path.DirName(); 324 DELETE_FAILED,
325 if (!parent_dir.empty() && file_util::IsDirectoryEmpty(parent_dir)) { 325 DELETE_REQUIRES_REBOOT,
326 if (!file_util::Delete(parent_dir, true)) { 326 };
327 ret = false;
328 LOG(ERROR) << "Failed to delete folder: " << parent_dir.value();
329 }
330 327
331 parent_dir = parent_dir.DirName(); 328 // Deletes the given directory if it is empty. Returns DELETE_SUCCEEDED if the
332 if (!parent_dir.empty() && file_util::IsDirectoryEmpty(parent_dir)) { 329 // directory is deleted, DELETE_NOT_EMPTY if it is not empty, and DELETE_FAILED
333 if (!file_util::Delete(parent_dir, true)) { 330 // otherwise.
334 ret = false; 331 DeleteResult DeleteEmptyDir(const FilePath& path) {
335 LOG(ERROR) << "Failed to delete folder: " << parent_dir.value(); 332 if (!file_util::IsDirectoryEmpty(path))
336 } 333 return DELETE_NOT_EMPTY;
337 } 334
338 } 335 if (file_util::Delete(path, true))
339 return ret; 336 return DELETE_SUCCEEDED;
337
338 LOG(ERROR) << "Failed to delete folder: " << path.value();
339 return DELETE_FAILED;
340 } 340 }
341 341
342 void GetLocalStateFolders(const Product& product, 342 void GetLocalStateFolders(const Product& product,
343 std::vector<FilePath>* paths) { 343 std::vector<FilePath>* paths) {
344 // Obtain the location of the user profile data. 344 // Obtain the location of the user profile data.
345 product.GetUserDataPaths(paths); 345 product.GetUserDataPaths(paths);
346 LOG_IF(ERROR, paths->empty()) 346 LOG_IF(ERROR, paths->empty())
347 << "Could not retrieve user's profile directory."; 347 << "Could not retrieve user's profile directory.";
348 } 348 }
349 349
(...skipping 10 matching lines...) Expand all
360 continue; 360 continue;
361 if (!file_util::CreateTemporaryFile(&backup)) 361 if (!file_util::CreateTemporaryFile(&backup))
362 LOG(ERROR) << "Failed to create temporary file for Local State."; 362 LOG(ERROR) << "Failed to create temporary file for Local State.";
363 else 363 else
364 file_util::CopyFile(state_file, backup); 364 file_util::CopyFile(state_file, backup);
365 break; 365 break;
366 } 366 }
367 return backup; 367 return backup;
368 } 368 }
369 369
370 enum DeleteResult {
371 DELETE_SUCCEEDED,
372 DELETE_FAILED,
373 DELETE_REQUIRES_REBOOT,
374 };
375
376 // Deletes all user data directories for a product. 370 // Deletes all user data directories for a product.
377 DeleteResult DeleteLocalState(const std::vector<FilePath>& local_state_folders, 371 DeleteResult DeleteLocalState(const std::vector<FilePath>& local_state_folders,
378 bool schedule_on_failure) { 372 bool schedule_on_failure) {
379 if (local_state_folders.empty()) 373 if (local_state_folders.empty())
380 return DELETE_SUCCEEDED; 374 return DELETE_SUCCEEDED;
381 375
382 DeleteResult result = DELETE_SUCCEEDED; 376 DeleteResult result = DELETE_SUCCEEDED;
383 for (size_t i = 0; i < local_state_folders.size(); ++i) { 377 for (size_t i = 0; i < local_state_folders.size(); ++i) {
384 const FilePath& user_local_state = local_state_folders[i]; 378 const FilePath& user_local_state = local_state_folders[i];
385 VLOG(1) << "Deleting user profile " << user_local_state.value(); 379 VLOG(1) << "Deleting user profile " << user_local_state.value();
386 if (!file_util::Delete(user_local_state, true)) { 380 if (!file_util::Delete(user_local_state, true)) {
387 LOG(ERROR) << "Failed to delete user profile dir: " 381 LOG(ERROR) << "Failed to delete user profile dir: "
388 << user_local_state.value(); 382 << user_local_state.value();
389 if (schedule_on_failure) { 383 if (schedule_on_failure) {
390 ScheduleDirectoryForDeletion(user_local_state.value().c_str()); 384 ScheduleDirectoryForDeletion(user_local_state.value().c_str());
391 result = DELETE_REQUIRES_REBOOT; 385 result = DELETE_REQUIRES_REBOOT;
392 } else { 386 } else {
393 result = DELETE_FAILED; 387 result = DELETE_FAILED;
394 } 388 }
395 } 389 }
396 } 390 }
397 391
398 if (result == DELETE_REQUIRES_REBOOT) { 392 if (result == DELETE_REQUIRES_REBOOT) {
399 ScheduleParentAndGrandparentForDeletion(local_state_folders[0]); 393 ScheduleParentAndGrandparentForDeletion(local_state_folders[0]);
400 } else { 394 } else {
401 DeleteEmptyParentDir(local_state_folders[0]); 395 const FilePath user_data_dir(local_state_folders[0].DirName());
396 if (!user_data_dir.empty() &&
397 DeleteEmptyDir(user_data_dir) == DELETE_SUCCEEDED) {
398 const FilePath product_dir(user_data_dir.DirName());
399 if (!product_dir.empty())
400 DeleteEmptyDir(product_dir);
401 }
402 } 402 }
403 403
404 return result; 404 return result;
405 } 405 }
406 406
407 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, 407 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state,
408 const FilePath& setup_path, 408 const FilePath& setup_path,
409 const Version& installed_version) { 409 const Version& installed_version) {
410 bool ret = false; 410 bool ret = false;
411 FilePath setup_exe(installer_state.GetInstallerDirectory(installed_version) 411 FilePath setup_exe(installer_state.GetInstallerDirectory(installed_version)
412 .Append(setup_path.BaseName())); 412 .Append(setup_path.BaseName()));
413 FilePath temp_file; 413 FilePath temp_file;
414 if (!file_util::CreateTemporaryFile(&temp_file)) { 414 if (!file_util::CreateTemporaryFile(&temp_file)) {
415 LOG(ERROR) << "Failed to create temporary file for setup.exe."; 415 LOG(ERROR) << "Failed to create temporary file for setup.exe.";
416 } else { 416 } else {
417 VLOG(1) << "Attempting to move setup to: " << temp_file.value(); 417 VLOG(1) << "Attempting to move setup to: " << temp_file.value();
418 ret = file_util::Move(setup_exe, temp_file); 418 ret = file_util::Move(setup_exe, temp_file);
419 PLOG_IF(ERROR, !ret) << "Failed to move setup to " << temp_file.value(); 419 PLOG_IF(ERROR, !ret) << "Failed to move setup to " << temp_file.value();
420 420
421 // We cannot delete the file right away, but try to delete it some other 421 // We cannot delete the file right away, but try to delete it some other
422 // way. Either with the help of a different process or the system. 422 // way. Either with the help of a different process or the system.
423 if (ret && !file_util::DeleteAfterReboot(temp_file)) { 423 if (ret && !file_util::DeleteAfterReboot(temp_file)) {
424 static const uint32 kDeleteAfterMs = 10 * 1000; 424 static const uint32 kDeleteAfterMs = 10 * 1000;
425 installer::DeleteFileFromTempProcess(temp_file, kDeleteAfterMs); 425 installer::DeleteFileFromTempProcess(temp_file, kDeleteAfterMs);
426 } 426 }
427 } 427 }
428 return ret; 428 return ret;
429 } 429 }
430 430
431 DeleteResult DeleteApplicationProductAndVendorDirectories(
432 const FilePath& application_directory) {
433 DeleteResult result(DeleteEmptyDir(application_directory));
gab 2012/08/13 19:33:54 nit: DeleteResult is a POD (i.e. enum), I think th
erikwright (departed) 2012/08/13 19:37:37 Found no mention of this for PODS or non-PODS. The
gab 2012/08/13 19:46:16 Ah interesting, maybe we should define "grt-style"
434 if (result == DELETE_SUCCEEDED) {
435 // Now check and delete if the parent directories are empty
436 // For example Google\Chrome or Chromium
437 const FilePath product_directory(application_directory.DirName());
438 if (!product_directory.empty()) {
439 result = DeleteEmptyDir(product_directory);
440 if (result == DELETE_SUCCEEDED) {
441 const FilePath vendor_directory(product_directory.DirName());
442 if (!vendor_directory.empty())
443 result = DeleteEmptyDir(vendor_directory);
444 }
445 }
446 }
447 if (result == DELETE_NOT_EMPTY)
448 result = DELETE_SUCCEEDED;
449 return result;
450 }
451
431 DeleteResult DeleteAppHostFilesAndFolders(const InstallerState& installer_state, 452 DeleteResult DeleteAppHostFilesAndFolders(const InstallerState& installer_state,
432 const Version& installed_version) { 453 const Version& installed_version) {
433 const FilePath& target_path = installer_state.target_path(); 454 const FilePath& target_path = installer_state.target_path();
434 if (target_path.empty()) { 455 if (target_path.empty()) {
435 LOG(ERROR) << "DeleteAppHostFilesAndFolders: no installation destination " 456 LOG(ERROR) << "DeleteAppHostFilesAndFolders: no installation destination "
436 << "path."; 457 << "path.";
437 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. 458 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return.
438 } 459 }
439 460
440 DeleteInstallTempDir(target_path); 461 DeleteInstallTempDir(target_path);
441 462
442 DeleteResult result = DELETE_SUCCEEDED; 463 DeleteResult result = DELETE_SUCCEEDED;
443 464
444 FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe)); 465 FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe));
445 if (!file_util::Delete(app_host_exe, false)) { 466 if (!file_util::Delete(app_host_exe, false)) {
446 result = DELETE_FAILED; 467 result = DELETE_FAILED;
447 LOG(ERROR) << "Failed to delete path: " << app_host_exe.value(); 468 LOG(ERROR) << "Failed to delete path: " << app_host_exe.value();
448 } else { 469 } else {
449 DeleteEmptyParentDir(target_path); 470 result = DeleteApplicationProductAndVendorDirectories(target_path);
450 } 471 }
451 472
452 return result; 473 return result;
453 } 474 }
454 475
455 DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state, 476 DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state,
456 const Version& installed_version) { 477 const Version& installed_version) {
457 const FilePath& target_path = installer_state.target_path(); 478 const FilePath& target_path = installer_state.target_path();
458 if (target_path.empty()) { 479 if (target_path.empty()) {
459 LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination " 480 LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination "
(...skipping 11 matching lines...) Expand all
471 false, 492 false,
472 static_cast<FileEnumerator::FileType>(FileEnumerator::FILES | 493 static_cast<FileEnumerator::FileType>(FileEnumerator::FILES |
473 FileEnumerator::DIRECTORIES)); 494 FileEnumerator::DIRECTORIES));
474 while (true) { 495 while (true) {
475 FilePath to_delete(file_enumerator.Next()); 496 FilePath to_delete(file_enumerator.Next());
476 if (to_delete.empty()) 497 if (to_delete.empty())
477 break; 498 break;
478 if (to_delete.BaseName().value() == installer::kChromeAppHostExe) 499 if (to_delete.BaseName().value() == installer::kChromeAppHostExe)
479 continue; 500 continue;
480 501
481 VLOG(1) << "Deleting install path " << target_path.value(); 502 VLOG(1) << "Deleting install path " << to_delete.value();
482 if (!file_util::Delete(to_delete, true)) { 503 if (!file_util::Delete(to_delete, true)) {
483 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); 504 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value();
484 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { 505 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) {
485 // We don't try killing Chrome processes for Chrome Frame builds since 506 // We don't try killing Chrome processes for Chrome Frame builds since
486 // that is unlikely to help. Instead, schedule files for deletion and 507 // that is unlikely to help. Instead, schedule files for deletion and
487 // return a value that will trigger a reboot prompt. 508 // return a value that will trigger a reboot prompt.
488 FileEnumerator::FindInfo find_info; 509 FileEnumerator::FindInfo find_info;
489 file_enumerator.GetFindInfo(&find_info); 510 file_enumerator.GetFindInfo(&find_info);
490 if (FileEnumerator::IsDirectory(find_info)) 511 if (FileEnumerator::IsDirectory(find_info))
491 ScheduleDirectoryForDeletion(to_delete.value().c_str()); 512 ScheduleDirectoryForDeletion(to_delete.value().c_str());
492 else 513 else
493 ScheduleFileSystemEntityForDeletion(to_delete.value().c_str()); 514 ScheduleFileSystemEntityForDeletion(to_delete.value().c_str());
494 result = DELETE_REQUIRES_REBOOT; 515 result = DELETE_REQUIRES_REBOOT;
495 } else { 516 } else {
496 // Try closing any running Chrome processes and deleting files once 517 // Try closing any running Chrome processes and deleting files once
497 // again. 518 // again.
498 CloseAllChromeProcesses(); 519 CloseAllChromeProcesses();
499 if (!file_util::Delete(to_delete, true)) { 520 if (!file_util::Delete(to_delete, true)) {
500 LOG(ERROR) << "Failed to delete path (2nd try): " 521 LOG(ERROR) << "Failed to delete path (2nd try): "
501 << to_delete.value(); 522 << to_delete.value();
502 result = DELETE_FAILED; 523 result = DELETE_FAILED;
503 break; 524 break;
504 } 525 }
505 } 526 }
506 } 527 }
507 } 528 }
508 529
509 if (result == DELETE_REQUIRES_REBOOT) { 530 if (result == DELETE_REQUIRES_REBOOT) {
531 // Delete the Application directory at reboot if empty.
532 ScheduleFileSystemEntityForDeletion(target_path.value().c_str());
533
510 // If we need a reboot to continue, schedule the parent directories for 534 // If we need a reboot to continue, schedule the parent directories for
511 // deletion unconditionally. If they are not empty, the session manager 535 // deletion unconditionally. If they are not empty, the session manager
512 // will not delete them on reboot. 536 // will not delete them on reboot.
513 ScheduleParentAndGrandparentForDeletion(target_path); 537 ScheduleParentAndGrandparentForDeletion(target_path);
514 } else { 538 } else {
515 // Now check and delete if the parent directories are empty 539 result = DeleteApplicationProductAndVendorDirectories(target_path);
516 // For example Google\Chrome or Chromium
517 DeleteEmptyParentDir(target_path);
518 } 540 }
519 return result; 541 return result;
520 } 542 }
521 543
522 // This method checks if Chrome is currently running or if the user has 544 // This method checks if Chrome is currently running or if the user has
523 // cancelled the uninstall operation by clicking Cancel on the confirmation 545 // cancelled the uninstall operation by clicking Cancel on the confirmation
524 // box that Chrome pops up. 546 // box that Chrome pops up.
525 InstallStatus IsChromeActiveOrUserCancelled( 547 InstallStatus IsChromeActiveOrUserCancelled(
526 const InstallerState& installer_state, 548 const InstallerState& installer_state,
527 const Product& product) { 549 const Product& product) {
(...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after
1161 1183
1162 // Try and delete the preserved local state once the post-install 1184 // Try and delete the preserved local state once the post-install
1163 // operations are complete. 1185 // operations are complete.
1164 if (!backup_state_file.empty()) 1186 if (!backup_state_file.empty())
1165 file_util::Delete(backup_state_file, false); 1187 file_util::Delete(backup_state_file, false);
1166 1188
1167 return ret; 1189 return ret;
1168 } 1190 }
1169 1191
1170 } // namespace installer 1192 } // namespace installer
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698