1 // Copyright 2013 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 "webkit/browser/fileapi/file_system_operation_runner.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "base/stl_util.h"
10 #include "net/url_request/url_request_context.h"
11 #include "webkit/browser/blob/blob_url_request_job_factory.h"
12 #include "webkit/browser/fileapi/file_observers.h"
13 #include "webkit/browser/fileapi/file_stream_writer.h"
14 #include "webkit/browser/fileapi/file_system_context.h"
15 #include "webkit/browser/fileapi/file_system_operation.h"
16 #include "webkit/browser/fileapi/file_writer_delegate.h"
17 #include "webkit/common/blob/shareable_file_reference.h"
18
19 namespace fileapi {
20
21 typedef FileSystemOperationRunner::OperationID OperationID;
22
23 class FileSystemOperationRunner::BeginOperationScoper
24 : public base::SupportsWeakPtr<
25 FileSystemOperationRunner::BeginOperationScoper> {
26 public:
BeginOperationScoper()27 BeginOperationScoper() {}
28 private:
29 DISALLOW_COPY_AND_ASSIGN(BeginOperationScoper);
30 };
31
OperationHandle()32 FileSystemOperationRunner::OperationHandle::OperationHandle() {}
~OperationHandle()33 FileSystemOperationRunner::OperationHandle::~OperationHandle() {}
34
~FileSystemOperationRunner()35 FileSystemOperationRunner::~FileSystemOperationRunner() {
36 }
37
Shutdown()38 void FileSystemOperationRunner::Shutdown() {
39 operations_.Clear();
40 }
41
CreateFile(const FileSystemURL & url,bool exclusive,const StatusCallback & callback)42 OperationID FileSystemOperationRunner::CreateFile(
43 const FileSystemURL& url,
44 bool exclusive,
45 const StatusCallback& callback) {
46 base::File::Error error = base::File::FILE_OK;
47 FileSystemOperation* operation =
48 file_system_context_->CreateFileSystemOperation(url, &error);
49
50 BeginOperationScoper scope;
51 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
52 if (!operation) {
53 DidFinish(handle, callback, error);
54 return handle.id;
55 }
56 PrepareForWrite(handle.id, url);
57 operation->CreateFile(
58 url, exclusive,
59 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
60 handle, callback));
61 return handle.id;
62 }
63
CreateDirectory(const FileSystemURL & url,bool exclusive,bool recursive,const StatusCallback & callback)64 OperationID FileSystemOperationRunner::CreateDirectory(
65 const FileSystemURL& url,
66 bool exclusive,
67 bool recursive,
68 const StatusCallback& callback) {
69 base::File::Error error = base::File::FILE_OK;
70 FileSystemOperation* operation =
71 file_system_context_->CreateFileSystemOperation(url, &error);
72 BeginOperationScoper scope;
73 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
74 if (!operation) {
75 DidFinish(handle, callback, error);
76 return handle.id;
77 }
78 PrepareForWrite(handle.id, url);
79 operation->CreateDirectory(
80 url, exclusive, recursive,
81 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
82 handle, callback));
83 return handle.id;
84 }
85
Copy(const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,const CopyProgressCallback & progress_callback,const StatusCallback & callback)86 OperationID FileSystemOperationRunner::Copy(
87 const FileSystemURL& src_url,
88 const FileSystemURL& dest_url,
89 CopyOrMoveOption option,
90 const CopyProgressCallback& progress_callback,
91 const StatusCallback& callback) {
92 base::File::Error error = base::File::FILE_OK;
93 FileSystemOperation* operation =
94 file_system_context_->CreateFileSystemOperation(dest_url, &error);
95 BeginOperationScoper scope;
96 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
97 if (!operation) {
98 DidFinish(handle, callback, error);
99 return handle.id;
100 }
101 PrepareForWrite(handle.id, dest_url);
102 PrepareForRead(handle.id, src_url);
103 operation->Copy(
104 src_url, dest_url, option,
105 progress_callback.is_null() ?
106 CopyProgressCallback() :
107 base::Bind(&FileSystemOperationRunner::OnCopyProgress, AsWeakPtr(),
108 handle, progress_callback),
109 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
110 handle, callback));
111 return handle.id;
112 }
113
Move(const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,const StatusCallback & callback)114 OperationID FileSystemOperationRunner::Move(
115 const FileSystemURL& src_url,
116 const FileSystemURL& dest_url,
117 CopyOrMoveOption option,
118 const StatusCallback& callback) {
119 base::File::Error error = base::File::FILE_OK;
120 FileSystemOperation* operation =
121 file_system_context_->CreateFileSystemOperation(dest_url, &error);
122 BeginOperationScoper scope;
123 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
124 if (!operation) {
125 DidFinish(handle, callback, error);
126 return handle.id;
127 }
128 PrepareForWrite(handle.id, dest_url);
129 PrepareForWrite(handle.id, src_url);
130 operation->Move(
131 src_url, dest_url, option,
132 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
133 handle, callback));
134 return handle.id;
135 }
136
DirectoryExists(const FileSystemURL & url,const StatusCallback & callback)137 OperationID FileSystemOperationRunner::DirectoryExists(
138 const FileSystemURL& url,
139 const StatusCallback& callback) {
140 base::File::Error error = base::File::FILE_OK;
141 FileSystemOperation* operation =
142 file_system_context_->CreateFileSystemOperation(url, &error);
143 BeginOperationScoper scope;
144 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
145 if (!operation) {
146 DidFinish(handle, callback, error);
147 return handle.id;
148 }
149 PrepareForRead(handle.id, url);
150 operation->DirectoryExists(
151 url,
152 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
153 handle, callback));
154 return handle.id;
155 }
156
FileExists(const FileSystemURL & url,const StatusCallback & callback)157 OperationID FileSystemOperationRunner::FileExists(
158 const FileSystemURL& url,
159 const StatusCallback& callback) {
160 base::File::Error error = base::File::FILE_OK;
161 FileSystemOperation* operation =
162 file_system_context_->CreateFileSystemOperation(url, &error);
163 BeginOperationScoper scope;
164 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
165 if (!operation) {
166 DidFinish(handle, callback, error);
167 return handle.id;
168 }
169 PrepareForRead(handle.id, url);
170 operation->FileExists(
171 url,
172 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
173 handle, callback));
174 return handle.id;
175 }
176
GetMetadata(const FileSystemURL & url,const GetMetadataCallback & callback)177 OperationID FileSystemOperationRunner::GetMetadata(
178 const FileSystemURL& url,
179 const GetMetadataCallback& callback) {
180 base::File::Error error = base::File::FILE_OK;
181 FileSystemOperation* operation =
182 file_system_context_->CreateFileSystemOperation(url, &error);
183 BeginOperationScoper scope;
184 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
185 if (!operation) {
186 DidGetMetadata(handle, callback, error, base::File::Info());
187 return handle.id;
188 }
189 PrepareForRead(handle.id, url);
190 operation->GetMetadata(
191 url,
192 base::Bind(&FileSystemOperationRunner::DidGetMetadata, AsWeakPtr(),
193 handle, callback));
194 return handle.id;
195 }
196
ReadDirectory(const FileSystemURL & url,const ReadDirectoryCallback & callback)197 OperationID FileSystemOperationRunner::ReadDirectory(
198 const FileSystemURL& url,
199 const ReadDirectoryCallback& callback) {
200 base::File::Error error = base::File::FILE_OK;
201 FileSystemOperation* operation =
202 file_system_context_->CreateFileSystemOperation(url, &error);
203 BeginOperationScoper scope;
204 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
205 if (!operation) {
206 DidReadDirectory(handle, callback, error, std::vector<DirectoryEntry>(),
207 false);
208 return handle.id;
209 }
210 PrepareForRead(handle.id, url);
211 operation->ReadDirectory(
212 url,
213 base::Bind(&FileSystemOperationRunner::DidReadDirectory, AsWeakPtr(),
214 handle, callback));
215 return handle.id;
216 }
217
Remove(const FileSystemURL & url,bool recursive,const StatusCallback & callback)218 OperationID FileSystemOperationRunner::Remove(
219 const FileSystemURL& url, bool recursive,
220 const StatusCallback& callback) {
221 base::File::Error error = base::File::FILE_OK;
222 FileSystemOperation* operation =
223 file_system_context_->CreateFileSystemOperation(url, &error);
224 BeginOperationScoper scope;
225 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
226 if (!operation) {
227 DidFinish(handle, callback, error);
228 return handle.id;
229 }
230 PrepareForWrite(handle.id, url);
231 operation->Remove(
232 url, recursive,
233 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
234 handle, callback));
235 return handle.id;
236 }
237
Write(const net::URLRequestContext * url_request_context,const FileSystemURL & url,scoped_ptr<webkit_blob::BlobDataHandle> blob,int64 offset,const WriteCallback & callback)238 OperationID FileSystemOperationRunner::Write(
239 const net::URLRequestContext* url_request_context,
240 const FileSystemURL& url,
241 scoped_ptr<webkit_blob::BlobDataHandle> blob,
242 int64 offset,
243 const WriteCallback& callback) {
244 base::File::Error error = base::File::FILE_OK;
245 FileSystemOperation* operation =
246 file_system_context_->CreateFileSystemOperation(url, &error);
247
248 BeginOperationScoper scope;
249 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
250 if (!operation) {
251 DidWrite(handle, callback, error, 0, true);
252 return handle.id;
253 }
254
255 scoped_ptr<FileStreamWriter> writer(
256 file_system_context_->CreateFileStreamWriter(url, offset));
257 if (!writer) {
258 // Write is not supported.
259 DidWrite(handle, callback, base::File::FILE_ERROR_SECURITY, 0, true);
260 return handle.id;
261 }
262
263 FileWriterDelegate::FlushPolicy flush_policy =
264 file_system_context_->ShouldFlushOnWriteCompletion(url.type())
265 ? FileWriterDelegate::FLUSH_ON_COMPLETION
266 : FileWriterDelegate::NO_FLUSH_ON_COMPLETION;
267 scoped_ptr<FileWriterDelegate> writer_delegate(
268 new FileWriterDelegate(writer.Pass(), flush_policy));
269
270 scoped_ptr<net::URLRequest> blob_request(
271 webkit_blob::BlobProtocolHandler::CreateBlobRequest(
272 blob.Pass(),
273 url_request_context,
274 writer_delegate.get()));
275
276 PrepareForWrite(handle.id, url);
277 operation->Write(
278 url, writer_delegate.Pass(), blob_request.Pass(),
279 base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(),
280 handle, callback));
281 return handle.id;
282 }
283
Truncate(const FileSystemURL & url,int64 length,const StatusCallback & callback)284 OperationID FileSystemOperationRunner::Truncate(
285 const FileSystemURL& url, int64 length,
286 const StatusCallback& callback) {
287 base::File::Error error = base::File::FILE_OK;
288 FileSystemOperation* operation =
289 file_system_context_->CreateFileSystemOperation(url, &error);
290 BeginOperationScoper scope;
291 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
292 if (!operation) {
293 DidFinish(handle, callback, error);
294 return handle.id;
295 }
296 PrepareForWrite(handle.id, url);
297 operation->Truncate(
298 url, length,
299 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
300 handle, callback));
301 return handle.id;
302 }
303
Cancel(OperationID id,const StatusCallback & callback)304 void FileSystemOperationRunner::Cancel(
305 OperationID id,
306 const StatusCallback& callback) {
307 if (ContainsKey(finished_operations_, id)) {
308 DCHECK(!ContainsKey(stray_cancel_callbacks_, id));
309 stray_cancel_callbacks_[id] = callback;
310 return;
311 }
312 FileSystemOperation* operation = operations_.Lookup(id);
313 if (!operation) {
314 // There is no operation with |id|.
315 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
316 return;
317 }
318 operation->Cancel(callback);
319 }
320
TouchFile(const FileSystemURL & url,const base::Time & last_access_time,const base::Time & last_modified_time,const StatusCallback & callback)321 OperationID FileSystemOperationRunner::TouchFile(
322 const FileSystemURL& url,
323 const base::Time& last_access_time,
324 const base::Time& last_modified_time,
325 const StatusCallback& callback) {
326 base::File::Error error = base::File::FILE_OK;
327 FileSystemOperation* operation =
328 file_system_context_->CreateFileSystemOperation(url, &error);
329 BeginOperationScoper scope;
330 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
331 if (!operation) {
332 DidFinish(handle, callback, error);
333 return handle.id;
334 }
335 PrepareForWrite(handle.id, url);
336 operation->TouchFile(
337 url, last_access_time, last_modified_time,
338 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
339 handle, callback));
340 return handle.id;
341 }
342
OpenFile(const FileSystemURL & url,int file_flags,const OpenFileCallback & callback)343 OperationID FileSystemOperationRunner::OpenFile(
344 const FileSystemURL& url,
345 int file_flags,
346 const OpenFileCallback& callback) {
347 base::File::Error error = base::File::FILE_OK;
348 FileSystemOperation* operation =
349 file_system_context_->CreateFileSystemOperation(url, &error);
350 BeginOperationScoper scope;
351 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
352 if (!operation) {
353 DidOpenFile(handle, callback, base::File(error), base::Closure());
354 return handle.id;
355 }
356 if (file_flags &
357 (base::File::FLAG_CREATE | base::File::FLAG_OPEN_ALWAYS |
358 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_OPEN_TRUNCATED |
359 base::File::FLAG_WRITE | base::File::FLAG_EXCLUSIVE_WRITE |
360 base::File::FLAG_DELETE_ON_CLOSE |
361 base::File::FLAG_WRITE_ATTRIBUTES)) {
362 PrepareForWrite(handle.id, url);
363 } else {
364 PrepareForRead(handle.id, url);
365 }
366 operation->OpenFile(
367 url, file_flags,
368 base::Bind(&FileSystemOperationRunner::DidOpenFile, AsWeakPtr(),
369 handle, callback));
370 return handle.id;
371 }
372
CreateSnapshotFile(const FileSystemURL & url,const SnapshotFileCallback & callback)373 OperationID FileSystemOperationRunner::CreateSnapshotFile(
374 const FileSystemURL& url,
375 const SnapshotFileCallback& callback) {
376 base::File::Error error = base::File::FILE_OK;
377 FileSystemOperation* operation =
378 file_system_context_->CreateFileSystemOperation(url, &error);
379 BeginOperationScoper scope;
380 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
381 if (!operation) {
382 DidCreateSnapshot(handle, callback, error, base::File::Info(),
383 base::FilePath(), NULL);
384 return handle.id;
385 }
386 PrepareForRead(handle.id, url);
387 operation->CreateSnapshotFile(
388 url,
389 base::Bind(&FileSystemOperationRunner::DidCreateSnapshot, AsWeakPtr(),
390 handle, callback));
391 return handle.id;
392 }
393
CopyInForeignFile(const base::FilePath & src_local_disk_path,const FileSystemURL & dest_url,const StatusCallback & callback)394 OperationID FileSystemOperationRunner::CopyInForeignFile(
395 const base::FilePath& src_local_disk_path,
396 const FileSystemURL& dest_url,
397 const StatusCallback& callback) {
398 base::File::Error error = base::File::FILE_OK;
399 FileSystemOperation* operation =
400 file_system_context_->CreateFileSystemOperation(dest_url, &error);
401 BeginOperationScoper scope;
402 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
403 if (!operation) {
404 DidFinish(handle, callback, error);
405 return handle.id;
406 }
407 operation->CopyInForeignFile(
408 src_local_disk_path, dest_url,
409 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
410 handle, callback));
411 return handle.id;
412 }
413
RemoveFile(const FileSystemURL & url,const StatusCallback & callback)414 OperationID FileSystemOperationRunner::RemoveFile(
415 const FileSystemURL& url,
416 const StatusCallback& callback) {
417 base::File::Error error = base::File::FILE_OK;
418 FileSystemOperation* operation =
419 file_system_context_->CreateFileSystemOperation(url, &error);
420 BeginOperationScoper scope;
421 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
422 if (!operation) {
423 DidFinish(handle, callback, error);
424 return handle.id;
425 }
426 operation->RemoveFile(
427 url,
428 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
429 handle, callback));
430 return handle.id;
431 }
432
RemoveDirectory(const FileSystemURL & url,const StatusCallback & callback)433 OperationID FileSystemOperationRunner::RemoveDirectory(
434 const FileSystemURL& url,
435 const StatusCallback& callback) {
436 base::File::Error error = base::File::FILE_OK;
437 FileSystemOperation* operation =
438 file_system_context_->CreateFileSystemOperation(url, &error);
439 BeginOperationScoper scope;
440 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
441 if (!operation) {
442 DidFinish(handle, callback, error);
443 return handle.id;
444 }
445 operation->RemoveDirectory(
446 url,
447 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
448 handle, callback));
449 return handle.id;
450 }
451
CopyFileLocal(const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,const CopyFileProgressCallback & progress_callback,const StatusCallback & callback)452 OperationID FileSystemOperationRunner::CopyFileLocal(
453 const FileSystemURL& src_url,
454 const FileSystemURL& dest_url,
455 CopyOrMoveOption option,
456 const CopyFileProgressCallback& progress_callback,
457 const StatusCallback& callback) {
458 base::File::Error error = base::File::FILE_OK;
459 FileSystemOperation* operation =
460 file_system_context_->CreateFileSystemOperation(src_url, &error);
461 BeginOperationScoper scope;
462 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
463 if (!operation) {
464 DidFinish(handle, callback, error);
465 return handle.id;
466 }
467 operation->CopyFileLocal(
468 src_url, dest_url, option, progress_callback,
469 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
470 handle, callback));
471 return handle.id;
472 }
473
MoveFileLocal(const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,const StatusCallback & callback)474 OperationID FileSystemOperationRunner::MoveFileLocal(
475 const FileSystemURL& src_url,
476 const FileSystemURL& dest_url,
477 CopyOrMoveOption option,
478 const StatusCallback& callback) {
479 base::File::Error error = base::File::FILE_OK;
480 FileSystemOperation* operation =
481 file_system_context_->CreateFileSystemOperation(src_url, &error);
482 BeginOperationScoper scope;
483 OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
484 if (!operation) {
485 DidFinish(handle, callback, error);
486 return handle.id;
487 }
488 operation->MoveFileLocal(
489 src_url, dest_url, option,
490 base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
491 handle, callback));
492 return handle.id;
493 }
494
SyncGetPlatformPath(const FileSystemURL & url,base::FilePath * platform_path)495 base::File::Error FileSystemOperationRunner::SyncGetPlatformPath(
496 const FileSystemURL& url,
497 base::FilePath* platform_path) {
498 base::File::Error error = base::File::FILE_OK;
499 scoped_ptr<FileSystemOperation> operation(
500 file_system_context_->CreateFileSystemOperation(url, &error));
501 if (!operation.get())
502 return error;
503 return operation->SyncGetPlatformPath(url, platform_path);
504 }
505
FileSystemOperationRunner(FileSystemContext * file_system_context)506 FileSystemOperationRunner::FileSystemOperationRunner(
507 FileSystemContext* file_system_context)
508 : file_system_context_(file_system_context) {}
509
DidFinish(const OperationHandle & handle,const StatusCallback & callback,base::File::Error rv)510 void FileSystemOperationRunner::DidFinish(
511 const OperationHandle& handle,
512 const StatusCallback& callback,
513 base::File::Error rv) {
514 if (handle.scope) {
515 finished_operations_.insert(handle.id);
516 base::MessageLoopProxy::current()->PostTask(
517 FROM_HERE, base::Bind(&FileSystemOperationRunner::DidFinish,
518 AsWeakPtr(), handle, callback, rv));
519 return;
520 }
521 callback.Run(rv);
522 FinishOperation(handle.id);
523 }
524
DidGetMetadata(const OperationHandle & handle,const GetMetadataCallback & callback,base::File::Error rv,const base::File::Info & file_info)525 void FileSystemOperationRunner::DidGetMetadata(
526 const OperationHandle& handle,
527 const GetMetadataCallback& callback,
528 base::File::Error rv,
529 const base::File::Info& file_info) {
530 if (handle.scope) {
531 finished_operations_.insert(handle.id);
532 base::MessageLoopProxy::current()->PostTask(
533 FROM_HERE, base::Bind(&FileSystemOperationRunner::DidGetMetadata,
534 AsWeakPtr(), handle, callback, rv, file_info));
535 return;
536 }
537 callback.Run(rv, file_info);
538 FinishOperation(handle.id);
539 }
540
DidReadDirectory(const OperationHandle & handle,const ReadDirectoryCallback & callback,base::File::Error rv,const std::vector<DirectoryEntry> & entries,bool has_more)541 void FileSystemOperationRunner::DidReadDirectory(
542 const OperationHandle& handle,
543 const ReadDirectoryCallback& callback,
544 base::File::Error rv,
545 const std::vector<DirectoryEntry>& entries,
546 bool has_more) {
547 if (handle.scope) {
548 finished_operations_.insert(handle.id);
549 base::MessageLoopProxy::current()->PostTask(
550 FROM_HERE, base::Bind(&FileSystemOperationRunner::DidReadDirectory,
551 AsWeakPtr(), handle, callback, rv,
552 entries, has_more));
553 return;
554 }
555 callback.Run(rv, entries, has_more);
556 if (rv != base::File::FILE_OK || !has_more)
557 FinishOperation(handle.id);
558 }
559
DidWrite(const OperationHandle & handle,const WriteCallback & callback,base::File::Error rv,int64 bytes,bool complete)560 void FileSystemOperationRunner::DidWrite(
561 const OperationHandle& handle,
562 const WriteCallback& callback,
563 base::File::Error rv,
564 int64 bytes,
565 bool complete) {
566 if (handle.scope) {
567 finished_operations_.insert(handle.id);
568 base::MessageLoopProxy::current()->PostTask(
569 FROM_HERE, base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(),
570 handle, callback, rv, bytes, complete));
571 return;
572 }
573 callback.Run(rv, bytes, complete);
574 if (rv != base::File::FILE_OK || complete)
575 FinishOperation(handle.id);
576 }
577
DidOpenFile(const OperationHandle & handle,const OpenFileCallback & callback,base::File file,const base::Closure & on_close_callback)578 void FileSystemOperationRunner::DidOpenFile(
579 const OperationHandle& handle,
580 const OpenFileCallback& callback,
581 base::File file,
582 const base::Closure& on_close_callback) {
583 if (handle.scope) {
584 finished_operations_.insert(handle.id);
585 base::MessageLoopProxy::current()->PostTask(
586 FROM_HERE, base::Bind(&FileSystemOperationRunner::DidOpenFile,
587 AsWeakPtr(), handle, callback, Passed(&file),
588 on_close_callback));
589 return;
590 }
591 callback.Run(file.Pass(), on_close_callback);
592 FinishOperation(handle.id);
593 }
594
DidCreateSnapshot(const OperationHandle & handle,const SnapshotFileCallback & callback,base::File::Error rv,const base::File::Info & file_info,const base::FilePath & platform_path,const scoped_refptr<webkit_blob::ShareableFileReference> & file_ref)595 void FileSystemOperationRunner::DidCreateSnapshot(
596 const OperationHandle& handle,
597 const SnapshotFileCallback& callback,
598 base::File::Error rv,
599 const base::File::Info& file_info,
600 const base::FilePath& platform_path,
601 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
602 if (handle.scope) {
603 finished_operations_.insert(handle.id);
604 base::MessageLoopProxy::current()->PostTask(
605 FROM_HERE, base::Bind(&FileSystemOperationRunner::DidCreateSnapshot,
606 AsWeakPtr(), handle, callback, rv, file_info,
607 platform_path, file_ref));
608 return;
609 }
610 callback.Run(rv, file_info, platform_path, file_ref);
611 FinishOperation(handle.id);
612 }
613
OnCopyProgress(const OperationHandle & handle,const CopyProgressCallback & callback,FileSystemOperation::CopyProgressType type,const FileSystemURL & source_url,const FileSystemURL & dest_url,int64 size)614 void FileSystemOperationRunner::OnCopyProgress(
615 const OperationHandle& handle,
616 const CopyProgressCallback& callback,
617 FileSystemOperation::CopyProgressType type,
618 const FileSystemURL& source_url,
619 const FileSystemURL& dest_url,
620 int64 size) {
621 if (handle.scope) {
622 base::MessageLoopProxy::current()->PostTask(
623 FROM_HERE, base::Bind(
624 &FileSystemOperationRunner::OnCopyProgress,
625 AsWeakPtr(), handle, callback, type, source_url, dest_url, size));
626 return;
627 }
628 callback.Run(type, source_url, dest_url, size);
629 }
630
PrepareForWrite(OperationID id,const FileSystemURL & url)631 void FileSystemOperationRunner::PrepareForWrite(OperationID id,
632 const FileSystemURL& url) {
633 if (file_system_context_->GetUpdateObservers(url.type())) {
634 file_system_context_->GetUpdateObservers(url.type())->Notify(
635 &FileUpdateObserver::OnStartUpdate, MakeTuple(url));
636 }
637 write_target_urls_[id].insert(url);
638 }
639
PrepareForRead(OperationID id,const FileSystemURL & url)640 void FileSystemOperationRunner::PrepareForRead(OperationID id,
641 const FileSystemURL& url) {
642 if (file_system_context_->GetAccessObservers(url.type())) {
643 file_system_context_->GetAccessObservers(url.type())->Notify(
644 &FileAccessObserver::OnAccess, MakeTuple(url));
645 }
646 }
647
648 FileSystemOperationRunner::OperationHandle
BeginOperation(FileSystemOperation * operation,base::WeakPtr<BeginOperationScoper> scope)649 FileSystemOperationRunner::BeginOperation(
650 FileSystemOperation* operation,
651 base::WeakPtr<BeginOperationScoper> scope) {
652 OperationHandle handle;
653 handle.id = operations_.Add(operation);
654 handle.scope = scope;
655 return handle;
656 }
657
FinishOperation(OperationID id)658 void FileSystemOperationRunner::FinishOperation(OperationID id) {
659 OperationToURLSet::iterator found = write_target_urls_.find(id);
660 if (found != write_target_urls_.end()) {
661 const FileSystemURLSet& urls = found->second;
662 for (FileSystemURLSet::const_iterator iter = urls.begin();
663 iter != urls.end(); ++iter) {
664 if (file_system_context_->GetUpdateObservers(iter->type())) {
665 file_system_context_->GetUpdateObservers(iter->type())->Notify(
666 &FileUpdateObserver::OnEndUpdate, MakeTuple(*iter));
667 }
668 }
669 write_target_urls_.erase(found);
670 }
671
672 // IDMap::Lookup fails if the operation is NULL, so we don't check
673 // operations_.Lookup(id) here.
674
675 operations_.Remove(id);
676 finished_operations_.erase(id);
677
678 // Dispatch stray cancel callback if exists.
679 std::map<OperationID, StatusCallback>::iterator found_cancel =
680 stray_cancel_callbacks_.find(id);
681 if (found_cancel != stray_cancel_callbacks_.end()) {
682 // This cancel has been requested after the operation has finished,
683 // so report that we failed to stop it.
684 found_cancel->second.Run(base::File::FILE_ERROR_INVALID_OPERATION);
685 stray_cancel_callbacks_.erase(found_cancel);
686 }
687 }
688
689 } // namespace fileapi
690