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

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

Issue 7373004: Move the save file code from chrome to content. This is just a file move so the DEPS in content\b... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/download/base_file.h"
6
7 #include "base/file_util.h"
8 #include "base/format_macros.h"
9 #include "base/logging.h"
10 #include "base/stringprintf.h"
11 #include "base/utf_string_conversions.h"
12 #include "crypto/secure_hash.h"
13 #include "net/base/file_stream.h"
14 #include "net/base/net_errors.h"
15 #include "chrome/browser/download/download_util.h"
16 #include "content/browser/browser_thread.h"
17
18 #if defined(OS_WIN)
19 #include "chrome/common/win_safe_util.h"
20 #elif defined(OS_MACOSX)
21 #include "chrome/browser/mac/file_metadata.h"
22 #endif
23
24 BaseFile::BaseFile(const FilePath& full_path,
25 const GURL& source_url,
26 const GURL& referrer_url,
27 int64 received_bytes,
28 const linked_ptr<net::FileStream>& file_stream)
29 : full_path_(full_path),
30 source_url_(source_url),
31 referrer_url_(referrer_url),
32 file_stream_(file_stream),
33 bytes_so_far_(received_bytes),
34 power_save_blocker_(true),
35 calculate_hash_(false),
36 detached_(false) {
37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
38 memset(sha256_hash_, 0, sizeof(sha256_hash_));
39 }
40
41 BaseFile::~BaseFile() {
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
43 if (detached_)
44 Close();
45 else
46 Cancel(); // Will delete the file.
47 }
48
49 bool BaseFile::Initialize(bool calculate_hash) {
50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
51 DCHECK(!detached_);
52
53 calculate_hash_ = calculate_hash;
54
55 if (calculate_hash_)
56 secure_hash_.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256));
57
58 if (!full_path_.empty() ||
59 download_util::CreateTemporaryFileForDownload(&full_path_))
60 return Open();
61 return false;
62 }
63
64 bool BaseFile::AppendDataToFile(const char* data, size_t data_len) {
65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
66 DCHECK(!detached_);
67
68 if (!file_stream_.get())
69 return false;
70
71 // TODO(phajdan.jr): get rid of this check.
72 if (data_len == 0)
73 return true;
74
75 bytes_so_far_ += data_len;
76
77 // TODO(phajdan.jr): handle errors on file writes. http://crbug.com/58355
78 size_t written = file_stream_->Write(data, data_len, NULL);
79 if (written != data_len)
80 return false;
81
82 if (calculate_hash_)
83 secure_hash_->Update(data, data_len);
84
85 return true;
86 }
87
88 bool BaseFile::Rename(const FilePath& new_path) {
89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
90
91 // Save the information whether the download is in progress because
92 // it will be overwritten by closing the file.
93 bool saved_in_progress = in_progress();
94
95 // If the new path is same as the old one, there is no need to perform the
96 // following renaming logic.
97 if (new_path == full_path_) {
98 // Don't close the file if we're not done (finished or canceled).
99 if (!saved_in_progress)
100 Close();
101
102 return true;
103 }
104
105 Close();
106
107 file_util::CreateDirectory(new_path.DirName());
108
109 #if defined(OS_WIN)
110 // We cannot rename because rename will keep the same security descriptor
111 // on the destination file. We want to recreate the security descriptor
112 // with the security that makes sense in the new path.
113 if (!file_util::RenameFileAndResetSecurityDescriptor(full_path_, new_path))
114 return false;
115 #elif defined(OS_POSIX)
116 {
117 // Similarly, on Unix, we're moving a temp file created with permissions
118 // 600 to |new_path|. Here, we try to fix up the destination file with
119 // appropriate permissions.
120 struct stat st;
121 // First check the file existence and create an empty file if it doesn't
122 // exist.
123 if (!file_util::PathExists(new_path))
124 file_util::WriteFile(new_path, "", 0);
125 bool stat_succeeded = (stat(new_path.value().c_str(), &st) == 0);
126
127 // TODO(estade): Move() falls back to copying and deleting when a simple
128 // rename fails. Copying sucks for large downloads. crbug.com/8737
129 if (!file_util::Move(full_path_, new_path))
130 return false;
131
132 if (stat_succeeded)
133 chmod(new_path.value().c_str(), st.st_mode);
134 }
135 #endif
136
137 full_path_ = new_path;
138
139 // We don't need to re-open the file if we're done (finished or canceled).
140 if (!saved_in_progress)
141 return true;
142
143 if (!Open())
144 return false;
145
146 return true;
147 }
148
149 void BaseFile::Detach() {
150 detached_ = true;
151 }
152
153 void BaseFile::Cancel() {
154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
155 DCHECK(!detached_);
156
157 Close();
158
159 if (!full_path_.empty())
160 file_util::Delete(full_path_, false);
161 }
162
163 void BaseFile::Finish() {
164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
165
166 if (calculate_hash_)
167 secure_hash_->Finish(sha256_hash_, kSha256HashLen);
168
169 Close();
170 }
171
172 bool BaseFile::GetSha256Hash(std::string* hash) {
173 DCHECK(!detached_);
174 if (!calculate_hash_ || in_progress())
175 return false;
176 hash->assign(reinterpret_cast<const char*>(sha256_hash_),
177 sizeof(sha256_hash_));
178 return true;
179 }
180
181 void BaseFile::AnnotateWithSourceInformation() {
182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
183 DCHECK(!detached_);
184
185 #if defined(OS_WIN)
186 // Sets the Zone to tell Windows that this file comes from the internet.
187 // We ignore the return value because a failure is not fatal.
188 win_util::SetInternetZoneIdentifier(full_path_,
189 UTF8ToWide(source_url_.spec()));
190 #elif defined(OS_MACOSX)
191 file_metadata::AddQuarantineMetadataToFile(full_path_, source_url_,
192 referrer_url_);
193 file_metadata::AddOriginMetadataToFile(full_path_, source_url_,
194 referrer_url_);
195 #endif
196 }
197
198 bool BaseFile::Open() {
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
200 DCHECK(!detached_);
201 DCHECK(!full_path_.empty());
202
203 // Create a new file stream if it is not provided.
204 if (!file_stream_.get()) {
205 file_stream_.reset(new net::FileStream);
206 if (file_stream_->Open(full_path_,
207 base::PLATFORM_FILE_OPEN_ALWAYS |
208 base::PLATFORM_FILE_WRITE) != net::OK) {
209 file_stream_.reset();
210 return false;
211 }
212
213 // We may be re-opening the file after rename. Always make sure we're
214 // writing at the end of the file.
215 if (file_stream_->Seek(net::FROM_END, 0) < 0) {
216 file_stream_.reset();
217 return false;
218 }
219 }
220
221 #if defined(OS_WIN)
222 AnnotateWithSourceInformation();
223 #endif
224 return true;
225 }
226
227 void BaseFile::Close() {
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
229 if (file_stream_.get()) {
230 #if defined(OS_CHROMEOS)
231 // Currently we don't really care about the return value, since if it fails
232 // theres not much we can do. But we might in the future.
233 file_stream_->Flush();
234 #endif
235 file_stream_->Close();
236 file_stream_.reset();
237 }
238 }
239
240 std::string BaseFile::DebugString() const {
241 return base::StringPrintf("{ source_url_ = \"%s\""
242 " full_path_ = \"%" PRFilePath "\""
243 " bytes_so_far_ = %" PRId64 " detached_ = %c }",
244 source_url_.spec().c_str(),
245 full_path_.value().c_str(),
246 bytes_so_far_,
247 detached_ ? 'T' : 'F');
248 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698