OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/chromeos/file_system_provider/fileapi/file_stream_write
r.h" | 5 #include "chrome/browser/chromeos/file_system_provider/fileapi/file_stream_write
r.h" |
6 | 6 |
7 #include "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" |
8 #include "base/memory/ref_counted.h" | 8 #include "base/memory/ref_counted.h" |
9 #include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_fi
le_util.h" | 9 #include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_fi
le_util.h" |
10 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h" | 10 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h" |
11 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_inte
rface.h" | 11 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_inte
rface.h" |
12 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
13 #include "net/base/io_buffer.h" | 13 #include "net/base/io_buffer.h" |
14 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
15 | 15 |
16 using content::BrowserThread; | 16 using content::BrowserThread; |
17 | 17 |
18 namespace chromeos { | 18 namespace chromeos { |
19 namespace file_system_provider { | 19 namespace file_system_provider { |
20 namespace { | 20 namespace { |
21 | 21 |
22 // Dicards the callback from CloseFile(). | 22 // Dicards the callback from CloseFile(). |
23 void EmptyStatusCallback(base::File::Error /* result */) { | 23 void EmptyStatusCallback(base::File::Error /* result */) { |
24 } | 24 } |
25 | 25 |
26 // Opens a file for writing and calls the completion callback. Must be called | 26 } // namespace |
27 // on UI thread. | |
28 void OpenFileOnUIThread( | |
29 const fileapi::FileSystemURL& url, | |
30 const FileStreamWriter::OpenFileCompletedCallback& callback) { | |
31 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
32 | 27 |
33 util::FileSystemURLParser parser(url); | 28 class FileStreamWriter::OperationRunner |
34 if (!parser.Parse()) { | 29 : public base::RefCountedThreadSafe<FileStreamWriter::OperationRunner> { |
35 callback.Run(base::WeakPtr<ProvidedFileSystemInterface>(), | 30 public: |
36 base::FilePath(), | 31 OperationRunner() : file_handle_(-1) {} |
37 0 /* file_handle */, | 32 |
38 base::File::FILE_ERROR_SECURITY); | 33 // Opens a file for writing and calls the completion callback. Must be called |
39 return; | 34 // on UI thread. |
| 35 void OpenFileOnUIThread( |
| 36 const fileapi::FileSystemURL& url, |
| 37 const fileapi::AsyncFileUtil::StatusCallback& callback) { |
| 38 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 39 |
| 40 util::FileSystemURLParser parser(url); |
| 41 if (!parser.Parse()) { |
| 42 BrowserThread::PostTask( |
| 43 BrowserThread::IO, |
| 44 FROM_HERE, |
| 45 base::Bind(callback, base::File::FILE_ERROR_SECURITY)); |
| 46 return; |
| 47 } |
| 48 |
| 49 file_system_ = parser.file_system()->GetWeakPtr(); |
| 50 abort_callback_ = parser.file_system()->OpenFile( |
| 51 parser.file_path(), |
| 52 ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE, |
| 53 base::Bind( |
| 54 &OperationRunner::OnOpenFileCompletedOnUIThread, this, callback)); |
40 } | 55 } |
41 | 56 |
42 parser.file_system()->OpenFile( | 57 // Closes a file. Ignores result, since outlives the caller. Must be called on |
43 parser.file_path(), | 58 // UI thread. |
44 ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE, | 59 void CloseFileOnUIThread() { |
45 base::Bind( | 60 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
46 callback, parser.file_system()->GetWeakPtr(), parser.file_path())); | 61 if (file_system_.get() && file_handle_ != -1) { |
47 } | 62 abort_callback_ = file_system_->CloseFile( |
48 | 63 file_handle_, base::Bind(&EmptyStatusCallback)); |
49 // Forwards results of calling OpenFileOnUIThread back to the IO thread. | 64 } |
50 void OnOpenFileCompletedOnUIThread( | |
51 const FileStreamWriter::OpenFileCompletedCallback& callback, | |
52 base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
53 const base::FilePath& file_path, | |
54 int file_handle, | |
55 base::File::Error result) { | |
56 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
57 BrowserThread::PostTask( | |
58 BrowserThread::IO, | |
59 FROM_HERE, | |
60 base::Bind(callback, file_system, file_path, file_handle, result)); | |
61 } | |
62 | |
63 // Closes a file. Ignores result, since it is called from a constructor. | |
64 // Must be called on UI thread. | |
65 void CloseFileOnUIThread(base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
66 int file_handle) { | |
67 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
68 if (file_system.get()) | |
69 file_system->CloseFile(file_handle, base::Bind(&EmptyStatusCallback)); | |
70 } | |
71 | |
72 // Requests writing bytes to the file. In case of either success or a failure | |
73 // |callback| is executed. Must be called on UI thread. | |
74 void WriteFileOnUIThread( | |
75 base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
76 int file_handle, | |
77 scoped_refptr<net::IOBuffer> buffer, | |
78 int64 offset, | |
79 int length, | |
80 const fileapi::AsyncFileUtil::StatusCallback& callback) { | |
81 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
82 | |
83 // If the file system got unmounted, then abort the writing operation. | |
84 if (!file_system.get()) { | |
85 callback.Run(base::File::FILE_ERROR_ABORT); | |
86 return; | |
87 } | 65 } |
88 | 66 |
89 file_system->WriteFile(file_handle, buffer, offset, length, callback); | 67 // Requests writing bytes to the file. In case of either success or a failure |
90 } | 68 // |callback| is executed. Must be called on UI thread. |
| 69 void WriteFileOnUIThread( |
| 70 scoped_refptr<net::IOBuffer> buffer, |
| 71 int64 offset, |
| 72 int length, |
| 73 const fileapi::AsyncFileUtil::StatusCallback& callback) { |
| 74 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
91 | 75 |
92 // Forward the completion callback to IO thread. | 76 // If the file system got unmounted, then abort the writing operation. |
93 void OnWriteFileCompletedOnUIThread( | 77 if (!file_system_.get()) { |
94 const fileapi::AsyncFileUtil::StatusCallback& callback, | 78 BrowserThread::PostTask( |
95 base::File::Error result) { | 79 BrowserThread::IO, |
96 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 80 FROM_HERE, |
97 BrowserThread::PostTask( | 81 base::Bind(callback, base::File::FILE_ERROR_ABORT)); |
98 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); | 82 return; |
99 } | 83 } |
100 | 84 |
101 } // namespace | 85 abort_callback_ = file_system_->WriteFile( |
| 86 file_handle_, |
| 87 buffer, |
| 88 offset, |
| 89 length, |
| 90 base::Bind( |
| 91 &OperationRunner::OnWriteFileCompletedOnUIThread, this, callback)); |
| 92 } |
| 93 |
| 94 // Aborts the most recent operation (if exists), and calls the callback. |
| 95 void AbortOnUIThread(const fileapi::AsyncFileUtil::StatusCallback& callback) { |
| 96 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 97 |
| 98 if (abort_callback_.is_null()) { |
| 99 // No operation on the file system being performed. At most a callback |
| 100 // call, which will be discarded. |
| 101 BrowserThread::PostTask( |
| 102 BrowserThread::IO, |
| 103 FROM_HERE, |
| 104 base::Bind(callback, base::File::FILE_ERROR_ABORT)); |
| 105 return; |
| 106 } |
| 107 |
| 108 const ProvidedFileSystemInterface::AbortCallback abort_callback = |
| 109 abort_callback_; |
| 110 abort_callback_ = ProvidedFileSystemInterface::AbortCallback(); |
| 111 abort_callback.Run(base::Bind( |
| 112 &OperationRunner::OnAbortCompletedOnUIThread, this, callback)); |
| 113 } |
| 114 |
| 115 private: |
| 116 friend class base::RefCountedThreadSafe<OperationRunner>; |
| 117 |
| 118 virtual ~OperationRunner() {} |
| 119 |
| 120 // Remembers a file handle for further operations and forwards the result to |
| 121 // the IO thread. |
| 122 void OnOpenFileCompletedOnUIThread( |
| 123 const fileapi::AsyncFileUtil::StatusCallback& callback, |
| 124 int file_handle, |
| 125 base::File::Error result) { |
| 126 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 127 |
| 128 file_handle_ = file_handle; |
| 129 BrowserThread::PostTask( |
| 130 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); |
| 131 } |
| 132 |
| 133 // Forwards a response of writing to a file to the IO thread. |
| 134 void OnWriteFileCompletedOnUIThread( |
| 135 const fileapi::AsyncFileUtil::StatusCallback& callback, |
| 136 base::File::Error result) { |
| 137 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 138 BrowserThread::PostTask( |
| 139 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); |
| 140 } |
| 141 |
| 142 // Forwards a response of aborting an operation to the IO thread. |
| 143 void OnAbortCompletedOnUIThread( |
| 144 const fileapi::AsyncFileUtil::StatusCallback& callback, |
| 145 base::File::Error result) { |
| 146 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 147 BrowserThread::PostTask( |
| 148 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); |
| 149 } |
| 150 |
| 151 ProvidedFileSystemInterface::AbortCallback abort_callback_; |
| 152 base::WeakPtr<ProvidedFileSystemInterface> file_system_; |
| 153 int file_handle_; |
| 154 |
| 155 DISALLOW_COPY_AND_ASSIGN(OperationRunner); |
| 156 }; |
102 | 157 |
103 FileStreamWriter::FileStreamWriter(const fileapi::FileSystemURL& url, | 158 FileStreamWriter::FileStreamWriter(const fileapi::FileSystemURL& url, |
104 int64 initial_offset) | 159 int64 initial_offset) |
105 : url_(url), | 160 : url_(url), |
106 current_offset_(initial_offset), | 161 current_offset_(initial_offset), |
| 162 runner_(new OperationRunner), |
107 state_(NOT_INITIALIZED), | 163 state_(NOT_INITIALIZED), |
108 file_handle_(0), | |
109 weak_ptr_factory_(this) { | 164 weak_ptr_factory_(this) { |
110 } | 165 } |
111 | 166 |
112 FileStreamWriter::~FileStreamWriter() { | 167 FileStreamWriter::~FileStreamWriter() { |
113 BrowserThread::PostTask( | 168 BrowserThread::PostTask( |
114 BrowserThread::UI, | 169 BrowserThread::UI, |
115 FROM_HERE, | 170 FROM_HERE, |
116 base::Bind(&CloseFileOnUIThread, file_system_, file_handle_)); | 171 base::Bind(&OperationRunner::CloseFileOnUIThread, runner_)); |
117 } | 172 } |
118 | 173 |
119 void FileStreamWriter::Initialize( | 174 void FileStreamWriter::Initialize( |
120 const base::Closure& pending_closure, | 175 const base::Closure& pending_closure, |
121 const net::CompletionCallback& error_callback) { | 176 const net::CompletionCallback& error_callback) { |
| 177 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
122 DCHECK_EQ(NOT_INITIALIZED, state_); | 178 DCHECK_EQ(NOT_INITIALIZED, state_); |
123 state_ = INITIALIZING; | 179 state_ = INITIALIZING; |
124 | 180 |
125 BrowserThread::PostTask( | 181 BrowserThread::PostTask( |
126 BrowserThread::UI, | 182 BrowserThread::UI, |
127 FROM_HERE, | 183 FROM_HERE, |
128 base::Bind(&OpenFileOnUIThread, | 184 base::Bind(&OperationRunner::OpenFileOnUIThread, |
| 185 runner_, |
129 url_, | 186 url_, |
130 base::Bind(&OnOpenFileCompletedOnUIThread, | 187 base::Bind(&FileStreamWriter::OnOpenFileCompleted, |
131 base::Bind(&FileStreamWriter::OnOpenFileCompleted, | 188 weak_ptr_factory_.GetWeakPtr(), |
132 weak_ptr_factory_.GetWeakPtr(), | 189 pending_closure, |
133 pending_closure, | 190 error_callback))); |
134 error_callback)))); | |
135 } | 191 } |
136 | 192 |
137 void FileStreamWriter::OnOpenFileCompleted( | 193 void FileStreamWriter::OnOpenFileCompleted( |
138 const base::Closure& pending_closure, | 194 const base::Closure& pending_closure, |
139 const net::CompletionCallback& error_callback, | 195 const net::CompletionCallback& error_callback, |
140 base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
141 const base::FilePath& file_path, | |
142 int file_handle, | |
143 base::File::Error result) { | 196 base::File::Error result) { |
144 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 197 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
145 DCHECK_EQ(INITIALIZING, state_); | 198 DCHECK_EQ(INITIALIZING, state_); |
146 | 199 |
147 // In case of an error, return immediately using the |error_callback| of the | 200 // In case of an error, return immediately using the |error_callback| of the |
148 // Write() pending request. | 201 // Write() pending request. |
149 if (result != base::File::FILE_OK) { | 202 if (result != base::File::FILE_OK) { |
150 state_ = FAILED; | 203 state_ = FAILED; |
151 error_callback.Run(net::FileErrorToNetError(result)); | 204 error_callback.Run(net::FileErrorToNetError(result)); |
152 return; | 205 return; |
153 } | 206 } |
154 | 207 |
155 file_system_ = file_system; | |
156 file_path_ = file_path; | |
157 file_handle_ = file_handle; | |
158 DCHECK_LT(0, file_handle); | |
159 DCHECK_EQ(base::File::FILE_OK, result); | 208 DCHECK_EQ(base::File::FILE_OK, result); |
160 state_ = INITIALIZED; | 209 state_ = INITIALIZED; |
161 | 210 |
162 // Run the task waiting for the initialization to be completed. | 211 // Run the task waiting for the initialization to be completed. |
163 pending_closure.Run(); | 212 pending_closure.Run(); |
164 } | 213 } |
165 | 214 |
166 int FileStreamWriter::Write(net::IOBuffer* buffer, | 215 int FileStreamWriter::Write(net::IOBuffer* buffer, |
167 int buffer_length, | 216 int buffer_length, |
168 const net::CompletionCallback& callback) { | 217 const net::CompletionCallback& callback) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 | 251 |
203 case FAILED: | 252 case FAILED: |
204 NOTREACHED(); | 253 NOTREACHED(); |
205 break; | 254 break; |
206 } | 255 } |
207 | 256 |
208 return net::ERR_IO_PENDING; | 257 return net::ERR_IO_PENDING; |
209 } | 258 } |
210 | 259 |
211 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) { | 260 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) { |
212 NOTIMPLEMENTED(); | 261 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
213 return net::ERR_FAILED; | 262 |
| 263 BrowserThread::PostTask( |
| 264 BrowserThread::UI, |
| 265 FROM_HERE, |
| 266 base::Bind(&OperationRunner::AbortOnUIThread, |
| 267 runner_, |
| 268 base::Bind(&FileStreamWriter::OnAbortCompleted, |
| 269 weak_ptr_factory_.GetWeakPtr(), |
| 270 callback))); |
| 271 return net::ERR_IO_PENDING; |
214 } | 272 } |
215 | 273 |
216 int FileStreamWriter::Flush(const net::CompletionCallback& callback) { | 274 int FileStreamWriter::Flush(const net::CompletionCallback& callback) { |
217 if (state_ != INITIALIZED) | 275 if (state_ != INITIALIZED) |
218 return net::ERR_FAILED; | 276 return net::ERR_FAILED; |
219 | 277 |
220 return net::OK; | 278 return net::OK; |
221 } | 279 } |
222 | 280 |
223 void FileStreamWriter::OnWriteFileCompleted( | 281 void FileStreamWriter::OnWriteFileCompleted( |
(...skipping 14 matching lines...) Expand all Loading... |
238 } | 296 } |
239 | 297 |
240 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback, | 298 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback, |
241 int result) { | 299 int result) { |
242 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 300 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
243 callback.Run(result); | 301 callback.Run(result); |
244 TRACE_EVENT_ASYNC_END0( | 302 TRACE_EVENT_ASYNC_END0( |
245 "file_system_provider", "FileStreamWriter::Write", this); | 303 "file_system_provider", "FileStreamWriter::Write", this); |
246 } | 304 } |
247 | 305 |
| 306 void FileStreamWriter::OnAbortCompleted(const net::CompletionCallback& callback, |
| 307 base::File::Error result) { |
| 308 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 309 |
| 310 if (result != base::File::FILE_OK) |
| 311 state_ = FAILED; |
| 312 |
| 313 callback.Run(net::FileErrorToNetError(result)); |
| 314 } |
| 315 |
248 void FileStreamWriter::WriteAfterInitialized( | 316 void FileStreamWriter::WriteAfterInitialized( |
249 scoped_refptr<net::IOBuffer> buffer, | 317 scoped_refptr<net::IOBuffer> buffer, |
250 int buffer_length, | 318 int buffer_length, |
251 const net::CompletionCallback& callback) { | 319 const net::CompletionCallback& callback) { |
252 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 320 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
253 DCHECK_EQ(INITIALIZED, state_); | 321 DCHECK_EQ(INITIALIZED, state_); |
254 | 322 |
255 BrowserThread::PostTask( | 323 BrowserThread::PostTask( |
256 BrowserThread::UI, | 324 BrowserThread::UI, |
257 FROM_HERE, | 325 FROM_HERE, |
258 base::Bind(&WriteFileOnUIThread, | 326 base::Bind(&OperationRunner::WriteFileOnUIThread, |
259 file_system_, | 327 runner_, |
260 file_handle_, | |
261 buffer, | 328 buffer, |
262 current_offset_, | 329 current_offset_, |
263 buffer_length, | 330 buffer_length, |
264 base::Bind(&OnWriteFileCompletedOnUIThread, | 331 base::Bind(&FileStreamWriter::OnWriteFileCompleted, |
265 base::Bind(&FileStreamWriter::OnWriteFileCompleted, | 332 weak_ptr_factory_.GetWeakPtr(), |
266 weak_ptr_factory_.GetWeakPtr(), | 333 buffer_length, |
267 buffer_length, | 334 callback))); |
268 callback)))); | |
269 } | 335 } |
270 | 336 |
271 } // namespace file_system_provider | 337 } // namespace file_system_provider |
272 } // namespace chromeos | 338 } // namespace chromeos |
OLD | NEW |