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

Side by Side Diff: chrome/browser/download/download_manager.cc

Issue 2877008: Rename the download to its final name only after the download is finished (Closed)
Patch Set: rebase Created 10 years, 5 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
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "chrome/browser/download/download_manager.h" 5 #include "chrome/browser/download/download_manager.h"
6 6
7 #include "app/l10n_util.h" 7 #include "app/l10n_util.h"
8 #include "app/resource_bundle.h" 8 #include "app/resource_bundle.h"
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
(...skipping 459 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 // Check writability of the suggested path. If we can't write to it, default 470 // Check writability of the suggested path. If we can't write to it, default
471 // to the user's "My Documents" directory. We'll prompt them in this case. 471 // to the user's "My Documents" directory. We'll prompt them in this case.
472 FilePath dir = info->suggested_path.DirName(); 472 FilePath dir = info->suggested_path.DirName();
473 FilePath filename = info->suggested_path.BaseName(); 473 FilePath filename = info->suggested_path.BaseName();
474 if (!file_util::PathIsWritable(dir)) { 474 if (!file_util::PathIsWritable(dir)) {
475 info->prompt_user_for_save_location = true; 475 info->prompt_user_for_save_location = true;
476 PathService::Get(chrome::DIR_USER_DOCUMENTS, &info->suggested_path); 476 PathService::Get(chrome::DIR_USER_DOCUMENTS, &info->suggested_path);
477 info->suggested_path = info->suggested_path.Append(filename); 477 info->suggested_path = info->suggested_path.Append(filename);
478 } 478 }
479 479
480 // Do not add the path uniquifier if we are saving to a specific path as in
481 // the drag-out case.
482 if (info->save_info.file_path.empty()) {
483 info->path_uniquifier = download_util::GetUniquePathNumber(
484 info->suggested_path);
485 }
486
487 // If the download is deemed dangerous, we'll use a temporary name for it. 480 // If the download is deemed dangerous, we'll use a temporary name for it.
488 if (info->is_dangerous) { 481 if (info->is_dangerous) {
489 info->original_name = FilePath(info->suggested_path).BaseName(); 482 info->original_name = FilePath(info->suggested_path).BaseName();
490 // Create a temporary file to hold the file until the user approves its 483 // Create a temporary file to hold the file until the user approves its
491 // download. 484 // download.
492 FilePath::StringType file_name; 485 FilePath::StringType file_name;
493 FilePath path; 486 FilePath path;
494 while (path.empty()) { 487 while (path.empty()) {
495 SStringPrintf(&file_name, FILE_PATH_LITERAL("unconfirmed %d.download"), 488 SStringPrintf(&file_name, FILE_PATH_LITERAL("unconfirmed %d.crdownload"),
496 base::RandInt(0, 100000)); 489 base::RandInt(0, 100000));
497 path = dir.Append(file_name); 490 path = dir.Append(file_name);
498 if (file_util::PathExists(path)) 491 if (file_util::PathExists(path))
499 path = FilePath(); 492 path = FilePath();
500 } 493 }
501 info->suggested_path = path; 494 info->suggested_path = path;
502 } else { 495 } else {
496 // Do not add the path uniquifier if we are saving to a specific path as in
497 // the drag-out case.
498 if (info->save_info.file_path.empty()) {
499 info->path_uniquifier = download_util::GetUniquePathNumberWithCrDownload(
500 info->suggested_path);
501 }
503 // We know the final path, build it if necessary. 502 // We know the final path, build it if necessary.
504 if (info->path_uniquifier > 0) { 503 if (info->path_uniquifier > 0) {
505 download_util::AppendNumberToPath(&(info->suggested_path), 504 download_util::AppendNumberToPath(&(info->suggested_path),
506 info->path_uniquifier); 505 info->path_uniquifier);
507 // Setting path_uniquifier to 0 to make sure we don't try to unique it 506 // Setting path_uniquifier to 0 to make sure we don't try to unique it
508 // later on. 507 // later on.
509 info->path_uniquifier = 0; 508 info->path_uniquifier = 0;
510 } else if (info->path_uniquifier == -1) { 509 } else if (info->path_uniquifier == -1) {
511 // We failed to find a unique path. We have to prompt the user. 510 // We failed to find a unique path. We have to prompt the user.
512 info->prompt_user_for_save_location = true; 511 info->prompt_user_for_save_location = true;
513 } 512 }
514 } 513 }
515 514
515 // Create an empty file at the suggested path so that we don't allocate the
516 // same "non-existant" path to multiple downloads.
517 // See: http://code.google.com/p/chromium/issues/detail?id=3662
516 if (!info->prompt_user_for_save_location && 518 if (!info->prompt_user_for_save_location &&
517 info->save_info.file_path.empty()) { 519 info->save_info.file_path.empty()) {
518 // Create an empty file at the suggested path so that we don't allocate the 520 if (info->is_dangerous)
519 // same "non-existant" path to multiple downloads. 521 file_util::WriteFile(info->suggested_path, "", 0);
520 // See: http://code.google.com/p/chromium/issues/detail?id=3662 522 else
521 file_util::WriteFile(info->suggested_path, "", 0); 523 file_util::WriteFile(download_util::GetCrDownloadPath(
524 info->suggested_path), "", 0);
522 } 525 }
523 526
524 // Now we return to the UI thread. 527 // Now we return to the UI thread.
525 ChromeThread::PostTask( 528 ChromeThread::PostTask(
526 ChromeThread::UI, FROM_HERE, 529 ChromeThread::UI, FROM_HERE,
527 NewRunnableMethod(this, 530 NewRunnableMethod(this,
528 &DownloadManager::OnPathExistenceAvailable, 531 &DownloadManager::OnPathExistenceAvailable,
529 info)); 532 info));
530 } 533 }
531 534
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
584 profile_->IsOffTheRecord(), 587 profile_->IsOffTheRecord(),
585 info->is_extension_install, 588 info->is_extension_install,
586 !info->save_info.file_path.empty()); 589 !info->save_info.file_path.empty());
587 download->set_manager(this); 590 download->set_manager(this);
588 in_progress_[info->download_id] = download; 591 in_progress_[info->download_id] = download;
589 } else { 592 } else {
590 NOTREACHED(); // Should not exist! 593 NOTREACHED(); // Should not exist!
591 return; 594 return;
592 } 595 }
593 596
594 // Called before DownloadFinished in order to avoid a race condition where we
595 // attempt to open a completed download before it has been renamed.
596 ChromeThread::PostTask(
597 ChromeThread::FILE, FROM_HERE,
598 NewRunnableMethod(
599 file_manager_, &DownloadFileManager::OnFinalDownloadName,
600 download->id(), target_path, this));
601
602 // If the download already completed by the time we reached this point, then
603 // notify observers that it did.
604 PendingFinishedMap::iterator pending_it = 597 PendingFinishedMap::iterator pending_it =
605 pending_finished_downloads_.find(info->download_id); 598 pending_finished_downloads_.find(info->download_id);
606 if (pending_it != pending_finished_downloads_.end()) 599 bool download_finished = (pending_it != pending_finished_downloads_.end());
600
601 if (download_finished || info->is_dangerous) {
602 // The download has already finished or the download is not safe.
603 // We can now rename the file to its final name (or its tentative name
604 // in dangerous download cases).
605 ChromeThread::PostTask(
606 ChromeThread::FILE, FROM_HERE,
607 NewRunnableMethod(
608 file_manager_, &DownloadFileManager::OnFinalDownloadName,
609 download->id(), target_path, !info->is_dangerous, this));
610 } else {
611 // The download hasn't finished and it is a safe download. We need to
612 // rename it to its intermediate '.crdownload' path.
613 FilePath download_path = download_util::GetCrDownloadPath(target_path);
614 ChromeThread::PostTask(
615 ChromeThread::FILE, FROM_HERE,
616 NewRunnableMethod(
617 file_manager_, &DownloadFileManager::OnIntermediateDownloadName,
618 download->id(), download_path, this));
619 download->set_need_final_rename(true);
620 }
621
622 if (download_finished) {
623 // If the download already completed by the time we reached this point, then
624 // notify observers that it did.
607 DownloadFinished(pending_it->first, pending_it->second); 625 DownloadFinished(pending_it->first, pending_it->second);
626 }
608 627
609 download->Rename(target_path); 628 download->Rename(target_path);
610 629
611 // Do not store the download in the history database for a few special cases: 630 // Do not store the download in the history database for a few special cases:
612 // - incognito mode (that is the point of this mode) 631 // - incognito mode (that is the point of this mode)
613 // - extensions (users don't think of extension installation as 'downloading') 632 // - extensions (users don't think of extension installation as 'downloading')
614 // - temporary download, like in drag-and-drop 633 // - temporary download, like in drag-and-drop
615 // We have to make sure that these handles don't collide with normal db 634 // We have to make sure that these handles don't collide with normal db
616 // handles, so we use a negative value. Eventually, they could overlap, but 635 // handles, so we use a negative value. Eventually, they could overlap, but
617 // you'd have to do enough downloading that your ISP would likely stab you in 636 // you'd have to do enough downloading that your ISP would likely stab you in
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
722 // We first need to rename the downloaded file from its temporary name to 741 // We first need to rename the downloaded file from its temporary name to
723 // its final name before we can continue. 742 // its final name before we can continue.
724 ChromeThread::PostTask( 743 ChromeThread::PostTask(
725 ChromeThread::FILE, FROM_HERE, 744 ChromeThread::FILE, FROM_HERE,
726 NewRunnableMethod( 745 NewRunnableMethod(
727 this, &DownloadManager::ProceedWithFinishedDangerousDownload, 746 this, &DownloadManager::ProceedWithFinishedDangerousDownload,
728 download->db_handle(), 747 download->db_handle(),
729 download->full_path(), download->original_name())); 748 download->full_path(), download->original_name()));
730 return; 749 return;
731 } 750 }
751
752 if (download->need_final_rename()) {
753 ChromeThread::PostTask(
754 ChromeThread::FILE, FROM_HERE,
755 NewRunnableMethod(
756 file_manager_, &DownloadFileManager::OnFinalDownloadName,
757 download->id(), download->full_path(), false, this));
758 return;
759 }
760
732 ContinueDownloadFinished(download); 761 ContinueDownloadFinished(download);
733 } 762 }
734 763
735 void DownloadManager::DownloadRenamedToFinalName(int download_id, 764 void DownloadManager::DownloadRenamedToFinalName(int download_id,
736 const FilePath& full_path) { 765 const FilePath& full_path) {
737 DownloadMap::iterator it = downloads_.begin(); 766 DownloadMap::iterator it = downloads_.begin();
738 while (it != downloads_.end()) { 767 while (it != downloads_.end()) {
739 DownloadItem* download = it->second; 768 DownloadItem* download = it->second;
740 if (download->id() == download_id) { 769 if (download->id() == download_id) {
741 // The download file is meant to be completed if both the filename is 770 // The download file is meant to be completed if both the filename is
742 // finalized and the file data is downloaded. The ordering of these two 771 // finalized and the file data is downloaded. The ordering of these two
743 // actions is indeterministic. Thus, if we are still in downloading the 772 // actions is indeterministic. Thus, if we are still in downloading the
744 // file, delay the notification. 773 // file, delay the notification.
745 download->set_name_finalized(true); 774 download->set_name_finalized(true);
746 if (download->state() == DownloadItem::COMPLETE) 775 if (download->state() == DownloadItem::COMPLETE)
747 download->NotifyObserversDownloadFileCompleted(); 776 download->NotifyObserversDownloadFileCompleted();
777
778 // This was called from DownloadFinished; continue to call
779 // ContinueDownloadFinished.
780 if (download->need_final_rename()) {
781 download->set_need_final_rename(false);
782 ContinueDownloadFinished(download);
783 }
748 return; 784 return;
749 } 785 }
750 it++; 786 it++;
751 } 787 }
752 } 788 }
753 789
754 void DownloadManager::ContinueDownloadFinished(DownloadItem* download) { 790 void DownloadManager::ContinueDownloadFinished(DownloadItem* download) {
755 // If this was a dangerous download, it has now been approved and must be 791 // If this was a dangerous download, it has now been approved and must be
756 // removed from dangerous_finished_ so it does not get deleted on shutdown. 792 // removed from dangerous_finished_ so it does not get deleted on shutdown.
757 DownloadMap::iterator it = dangerous_finished_.find(download->id()); 793 DownloadMap::iterator it = dangerous_finished_.find(download->id());
(...skipping 840 matching lines...) Expand 10 before | Expand all | Expand 10 after
1598 observing_download_manager_->NotifyModelChanged(); 1634 observing_download_manager_->NotifyModelChanged();
1599 } 1635 }
1600 1636
1601 void DownloadManager::OtherDownloadManagerObserver::SetDownloads( 1637 void DownloadManager::OtherDownloadManagerObserver::SetDownloads(
1602 std::vector<DownloadItem*>& downloads) { 1638 std::vector<DownloadItem*>& downloads) {
1603 } 1639 }
1604 1640
1605 void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() { 1641 void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() {
1606 observed_download_manager_ = NULL; 1642 observed_download_manager_ = NULL;
1607 } 1643 }
OLDNEW
« no previous file with comments | « chrome/browser/download/download_manager.h ('k') | chrome/browser/download/download_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698