• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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