summaryrefslogtreecommitdiffstats
path: root/chrome/browser/download/download_file.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/download/download_file.cc')
-rw-r--r--chrome/browser/download/download_file.cc201
1 files changed, 201 insertions, 0 deletions
diff --git a/chrome/browser/download/download_file.cc b/chrome/browser/download/download_file.cc
new file mode 100644
index 0000000..ebdaa1c
--- /dev/null
+++ b/chrome/browser/download/download_file.cc
@@ -0,0 +1,201 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/download/download_file.h"
+
+#include "base/file_util.h"
+#include "build/build_config.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/browser/download/download_manager.h"
+#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/history/download_types.h"
+#include "net/base/net_errors.h"
+
+#if defined(OS_WIN)
+#include "app/win_util.h"
+#include "chrome/common/win_safe_util.h"
+#elif defined(OS_MACOSX)
+#include "chrome/browser/cocoa/file_metadata.h"
+#endif
+
+DownloadFile::DownloadFile(const DownloadCreateInfo* info)
+ : file_stream_(info->save_info.file_stream),
+ source_url_(info->url),
+ referrer_url_(info->referrer_url),
+ id_(info->download_id),
+ child_id_(info->child_id),
+ request_id_(info->request_id),
+ full_path_(info->save_info.file_path),
+ path_renamed_(false),
+ dont_sleep_(true) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+}
+
+DownloadFile::~DownloadFile() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ Close();
+}
+
+bool DownloadFile::Initialize() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ if (!full_path_.empty() ||
+ download_util::CreateTemporaryFileForDownload(&full_path_))
+ return Open();
+ return false;
+}
+
+bool DownloadFile::AppendDataToFile(const char* data, size_t data_len) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+
+ if (!file_stream_.get())
+ return false;
+
+ // FIXME bug 595247: handle errors on file writes.
+ size_t written = file_stream_->Write(data, data_len, NULL);
+ return (written == data_len);
+}
+
+void DownloadFile::Cancel() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ Close();
+ if (!full_path_.empty())
+ file_util::Delete(full_path_, false);
+}
+
+// The UI has provided us with our finalized name.
+bool DownloadFile::Rename(const FilePath& new_path, bool is_final_rename) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+
+ // Save the information whether the download is in progress because
+ // it will be overwritten by closing the file.
+ bool saved_in_progress = in_progress();
+
+ // If the new path is same as the old one, there is no need to perform the
+ // following renaming logic.
+ if (new_path == full_path_) {
+ path_renamed_ = is_final_rename;
+
+ // Don't close the file if we're not done (finished or canceled).
+ if (!saved_in_progress)
+ Close();
+
+ return true;
+ }
+
+ Close();
+
+ file_util::CreateDirectory(new_path.DirName());
+
+#if defined(OS_WIN)
+ // We cannot rename because rename will keep the same security descriptor
+ // on the destination file. We want to recreate the security descriptor
+ // with the security that makes sense in the new path.
+ if (!file_util::RenameFileAndResetSecurityDescriptor(full_path_, new_path))
+ return false;
+#elif defined(OS_POSIX)
+ {
+ // Similarly, on Unix, we're moving a temp file created with permissions
+ // 600 to |new_path|. Here, we try to fix up the destination file with
+ // appropriate permissions.
+ struct stat st;
+ // First check the file existence and create an empty file if it doesn't
+ // exist.
+ if (!file_util::PathExists(new_path))
+ file_util::WriteFile(new_path, "", 0);
+ bool stat_succeeded = (stat(new_path.value().c_str(), &st) == 0);
+
+ // TODO(estade): Move() falls back to copying and deleting when a simple
+ // rename fails. Copying sucks for large downloads. crbug.com/8737
+ if (!file_util::Move(full_path_, new_path))
+ return false;
+
+ if (stat_succeeded)
+ chmod(new_path.value().c_str(), st.st_mode);
+ }
+#endif
+
+ full_path_ = new_path;
+ path_renamed_ = is_final_rename;
+
+ // We don't need to re-open the file if we're done (finished or canceled).
+ if (!saved_in_progress)
+ return true;
+
+ if (!Open())
+ return false;
+
+ // Move to the end of the new file.
+ if (file_stream_->Seek(net::FROM_END, 0) < 0)
+ return false;
+
+ return true;
+}
+
+void DownloadFile::DeleteCrDownload() {
+ FilePath crdownload = download_util::GetCrDownloadPath(full_path_);
+ file_util::Delete(crdownload, false);
+}
+
+void DownloadFile::Finish() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ Close();
+}
+
+void DownloadFile::Close() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ if (file_stream_.get()) {
+#if defined(OS_CHROMEOS)
+ // Currently we don't really care about the return value, since if it fails
+ // theres not much we can do. But we might in the future.
+ file_stream_->Flush();
+#endif
+ file_stream_->Close();
+ file_stream_.reset();
+ }
+}
+
+bool DownloadFile::Open() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ DCHECK(!full_path_.empty());
+
+ // Create a new file steram if it is not provided.
+ if (!file_stream_.get()) {
+ file_stream_.reset(new net::FileStream);
+ if (file_stream_->Open(full_path_,
+ base::PLATFORM_FILE_OPEN_ALWAYS |
+ base::PLATFORM_FILE_WRITE) != net::OK) {
+ file_stream_.reset();
+ return false;
+ }
+ }
+
+#if defined(OS_WIN)
+ AnnotateWithSourceInformation();
+#endif
+ return true;
+}
+
+void DownloadFile::AnnotateWithSourceInformation() {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+#if defined(OS_WIN)
+ // Sets the Zone to tell Windows that this file comes from the internet.
+ // We ignore the return value because a failure is not fatal.
+ win_util::SetInternetZoneIdentifier(full_path_);
+#elif defined(OS_MACOSX)
+ file_metadata::AddQuarantineMetadataToFile(full_path_, source_url_,
+ referrer_url_);
+ file_metadata::AddOriginMetadataToFile(full_path_, source_url_,
+ referrer_url_);
+#endif
+}
+
+void DownloadFile::CancelDownloadRequest(ResourceDispatcherHost* rdh) {
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
+ ChromeThread::PostTask(
+ ChromeThread::IO, FROM_HERE,
+ NewRunnableFunction(&download_util::CancelDownloadRequest,
+ rdh,
+ child_id_,
+ request_id_));
+}