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_ = |
86 file_system_->WriteFile(file_handle_, buffer, offset, length, callback); | |
hirono
2014/08/06 08:33:50
Should we check file_handle_ != -1?
| |
87 } | |
88 | |
89 // Aborts the most recent operation (if exists), and calls the callback. | |
90 void AbortOnUIThread(const fileapi::AsyncFileUtil::StatusCallback& callback) { | |
91 if (abort_callback_.is_null()) { | |
92 // No operation on the file system being performed. At most a callback | |
93 // call, which will be discarded. | |
94 callback.Run(base::File::FILE_OK); | |
95 return; | |
96 } | |
97 | |
98 const ProvidedFileSystemInterface::AbortCallback abort_callback = | |
99 abort_callback_; | |
100 abort_callback_ = ProvidedFileSystemInterface::AbortCallback(); | |
101 abort_callback.Run(callback); | |
102 } | |
103 | |
104 private: | |
105 friend class base::RefCountedThreadSafe<OperationRunner>; | |
106 | |
107 virtual ~OperationRunner() {} | |
108 | |
109 // Remembers a file handle for further operations and forwards the result to | |
110 // the IO thread. | |
111 void OnOpenFileCompletedOnUIThread( | |
112 const fileapi::AsyncFileUtil::StatusCallback& callback, | |
113 int file_handle, | |
114 base::File::Error result) { | |
115 file_handle_ = file_handle; | |
116 BrowserThread::PostTask( | |
117 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); | |
118 } | |
119 | |
120 ProvidedFileSystemInterface::AbortCallback abort_callback_; | |
121 base::WeakPtr<ProvidedFileSystemInterface> file_system_; | |
122 int file_handle_; | |
123 | |
124 DISALLOW_COPY_AND_ASSIGN(OperationRunner); | |
125 }; | |
102 | 126 |
103 FileStreamWriter::FileStreamWriter(const fileapi::FileSystemURL& url, | 127 FileStreamWriter::FileStreamWriter(const fileapi::FileSystemURL& url, |
104 int64 initial_offset) | 128 int64 initial_offset) |
105 : url_(url), | 129 : url_(url), |
106 current_offset_(initial_offset), | 130 current_offset_(initial_offset), |
131 runner_(new OperationRunner), | |
107 state_(NOT_INITIALIZED), | 132 state_(NOT_INITIALIZED), |
108 file_handle_(0), | |
109 weak_ptr_factory_(this) { | 133 weak_ptr_factory_(this) { |
110 } | 134 } |
111 | 135 |
112 FileStreamWriter::~FileStreamWriter() { | 136 FileStreamWriter::~FileStreamWriter() { |
113 BrowserThread::PostTask( | 137 BrowserThread::PostTask( |
114 BrowserThread::UI, | 138 BrowserThread::UI, |
115 FROM_HERE, | 139 FROM_HERE, |
116 base::Bind(&CloseFileOnUIThread, file_system_, file_handle_)); | 140 base::Bind(&OperationRunner::CloseFileOnUIThread, runner_)); |
117 } | 141 } |
118 | 142 |
119 void FileStreamWriter::Initialize( | 143 void FileStreamWriter::Initialize( |
120 const base::Closure& pending_closure, | 144 const base::Closure& pending_closure, |
121 const net::CompletionCallback& error_callback) { | 145 const net::CompletionCallback& error_callback) { |
122 DCHECK_EQ(NOT_INITIALIZED, state_); | 146 DCHECK_EQ(NOT_INITIALIZED, state_); |
123 state_ = INITIALIZING; | 147 state_ = INITIALIZING; |
124 | 148 |
125 BrowserThread::PostTask( | 149 BrowserThread::PostTask( |
126 BrowserThread::UI, | 150 BrowserThread::UI, |
127 FROM_HERE, | 151 FROM_HERE, |
128 base::Bind(&OpenFileOnUIThread, | 152 base::Bind(&OperationRunner::OpenFileOnUIThread, |
153 runner_, | |
129 url_, | 154 url_, |
130 base::Bind(&OnOpenFileCompletedOnUIThread, | 155 base::Bind(&FileStreamWriter::OnOpenFileCompleted, |
131 base::Bind(&FileStreamWriter::OnOpenFileCompleted, | 156 weak_ptr_factory_.GetWeakPtr(), |
132 weak_ptr_factory_.GetWeakPtr(), | 157 pending_closure, |
133 pending_closure, | 158 error_callback))); |
134 error_callback)))); | |
135 } | 159 } |
136 | 160 |
137 void FileStreamWriter::OnOpenFileCompleted( | 161 void FileStreamWriter::OnOpenFileCompleted( |
138 const base::Closure& pending_closure, | 162 const base::Closure& pending_closure, |
139 const net::CompletionCallback& error_callback, | 163 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) { | 164 base::File::Error result) { |
144 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 165 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
145 DCHECK_EQ(INITIALIZING, state_); | 166 DCHECK_EQ(INITIALIZING, state_); |
146 | 167 |
147 // In case of an error, return immediately using the |error_callback| of the | 168 // In case of an error, return immediately using the |error_callback| of the |
148 // Write() pending request. | 169 // Write() pending request. |
149 if (result != base::File::FILE_OK) { | 170 if (result != base::File::FILE_OK) { |
150 state_ = FAILED; | 171 state_ = FAILED; |
151 error_callback.Run(net::FileErrorToNetError(result)); | 172 error_callback.Run(net::FileErrorToNetError(result)); |
152 return; | 173 return; |
153 } | 174 } |
154 | 175 |
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); | 176 DCHECK_EQ(base::File::FILE_OK, result); |
160 state_ = INITIALIZED; | 177 state_ = INITIALIZED; |
161 | 178 |
162 // Run the task waiting for the initialization to be completed. | 179 // Run the task waiting for the initialization to be completed. |
163 pending_closure.Run(); | 180 pending_closure.Run(); |
164 } | 181 } |
165 | 182 |
166 int FileStreamWriter::Write(net::IOBuffer* buffer, | 183 int FileStreamWriter::Write(net::IOBuffer* buffer, |
167 int buffer_length, | 184 int buffer_length, |
168 const net::CompletionCallback& callback) { | 185 const net::CompletionCallback& callback) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
202 | 219 |
203 case FAILED: | 220 case FAILED: |
204 NOTREACHED(); | 221 NOTREACHED(); |
205 break; | 222 break; |
206 } | 223 } |
207 | 224 |
208 return net::ERR_IO_PENDING; | 225 return net::ERR_IO_PENDING; |
209 } | 226 } |
210 | 227 |
211 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) { | 228 int FileStreamWriter::Cancel(const net::CompletionCallback& callback) { |
212 NOTIMPLEMENTED(); | 229 BrowserThread::PostTask( |
213 return net::ERR_FAILED; | 230 BrowserThread::UI, |
231 FROM_HERE, | |
232 base::Bind(&OperationRunner::AbortOnUIThread, | |
233 runner_, | |
234 base::Bind(&FileStreamWriter::OnAbortCompleted, | |
235 weak_ptr_factory_.GetWeakPtr(), | |
236 callback))); | |
237 return net::ERR_IO_PENDING; | |
214 } | 238 } |
215 | 239 |
216 int FileStreamWriter::Flush(const net::CompletionCallback& callback) { | 240 int FileStreamWriter::Flush(const net::CompletionCallback& callback) { |
217 if (state_ != INITIALIZED) | 241 if (state_ != INITIALIZED) |
218 return net::ERR_FAILED; | 242 return net::ERR_FAILED; |
219 | 243 |
220 return net::OK; | 244 return net::OK; |
221 } | 245 } |
222 | 246 |
223 void FileStreamWriter::OnWriteFileCompleted( | 247 void FileStreamWriter::OnWriteFileCompleted( |
(...skipping 14 matching lines...) Expand all Loading... | |
238 } | 262 } |
239 | 263 |
240 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback, | 264 void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback, |
241 int result) { | 265 int result) { |
242 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 266 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
243 callback.Run(result); | 267 callback.Run(result); |
244 TRACE_EVENT_ASYNC_END0( | 268 TRACE_EVENT_ASYNC_END0( |
245 "file_system_provider", "FileStreamWriter::Write", this); | 269 "file_system_provider", "FileStreamWriter::Write", this); |
246 } | 270 } |
247 | 271 |
272 void FileStreamWriter::OnAbortCompleted(const net::CompletionCallback& callback, | |
273 base::File::Error result) { | |
274 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
275 | |
276 if (result != base::File::FILE_OK) | |
277 state_ = FAILED; | |
278 | |
279 callback.Run(net::FileErrorToNetError(result)); | |
280 } | |
281 | |
248 void FileStreamWriter::WriteAfterInitialized( | 282 void FileStreamWriter::WriteAfterInitialized( |
249 scoped_refptr<net::IOBuffer> buffer, | 283 scoped_refptr<net::IOBuffer> buffer, |
250 int buffer_length, | 284 int buffer_length, |
251 const net::CompletionCallback& callback) { | 285 const net::CompletionCallback& callback) { |
252 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 286 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
253 DCHECK_EQ(INITIALIZED, state_); | 287 DCHECK_EQ(INITIALIZED, state_); |
254 | 288 |
255 BrowserThread::PostTask( | 289 BrowserThread::PostTask( |
256 BrowserThread::UI, | 290 BrowserThread::UI, |
257 FROM_HERE, | 291 FROM_HERE, |
258 base::Bind(&WriteFileOnUIThread, | 292 base::Bind(&OperationRunner::WriteFileOnUIThread, |
259 file_system_, | 293 runner_, |
260 file_handle_, | |
261 buffer, | 294 buffer, |
262 current_offset_, | 295 current_offset_, |
263 buffer_length, | 296 buffer_length, |
264 base::Bind(&OnWriteFileCompletedOnUIThread, | 297 base::Bind(&FileStreamWriter::OnWriteFileCompleted, |
265 base::Bind(&FileStreamWriter::OnWriteFileCompleted, | 298 weak_ptr_factory_.GetWeakPtr(), |
266 weak_ptr_factory_.GetWeakPtr(), | 299 buffer_length, |
267 buffer_length, | 300 callback))); |
268 callback)))); | |
269 } | 301 } |
270 | 302 |
271 } // namespace file_system_provider | 303 } // namespace file_system_provider |
272 } // namespace chromeos | 304 } // namespace chromeos |
OLD | NEW |