• 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::PlatformFileError error = base::PLATFORM_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::PlatformFileError error = base::PLATFORM_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::PlatformFileError error = base::PLATFORM_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::PlatformFileError error = base::PLATFORM_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::PlatformFileError error = base::PLATFORM_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::PlatformFileError error = base::PLATFORM_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::PlatformFileError error = base::PLATFORM_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::PlatformFileInfo());
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::PlatformFileError error = base::PLATFORM_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::PlatformFileError error = base::PLATFORM_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::PlatformFileError error = base::PLATFORM_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::PLATFORM_FILE_ERROR_SECURITY, 0, true);
260     return handle.id;
261   }
262 
263   scoped_ptr<FileWriterDelegate> writer_delegate(
264       new FileWriterDelegate(writer.Pass()));
265 
266   scoped_ptr<net::URLRequest> blob_request(
267       webkit_blob::BlobProtocolHandler::CreateBlobRequest(
268           blob.Pass(),
269           url_request_context,
270           writer_delegate.get()));
271 
272   PrepareForWrite(handle.id, url);
273   operation->Write(
274       url, writer_delegate.Pass(), blob_request.Pass(),
275       base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(),
276                  handle, callback));
277   return handle.id;
278 }
279 
Truncate(const FileSystemURL & url,int64 length,const StatusCallback & callback)280 OperationID FileSystemOperationRunner::Truncate(
281     const FileSystemURL& url, int64 length,
282     const StatusCallback& callback) {
283   base::PlatformFileError error = base::PLATFORM_FILE_OK;
284   FileSystemOperation* operation =
285       file_system_context_->CreateFileSystemOperation(url, &error);
286   BeginOperationScoper scope;
287   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
288   if (!operation) {
289     DidFinish(handle, callback, error);
290     return handle.id;
291   }
292   PrepareForWrite(handle.id, url);
293   operation->Truncate(
294       url, length,
295       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
296                  handle, callback));
297   return handle.id;
298 }
299 
Cancel(OperationID id,const StatusCallback & callback)300 void FileSystemOperationRunner::Cancel(
301     OperationID id,
302     const StatusCallback& callback) {
303   if (ContainsKey(finished_operations_, id)) {
304     DCHECK(!ContainsKey(stray_cancel_callbacks_, id));
305     stray_cancel_callbacks_[id] = callback;
306     return;
307   }
308   FileSystemOperation* operation = operations_.Lookup(id);
309   if (!operation) {
310     // There is no operation with |id|.
311     callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
312     return;
313   }
314   operation->Cancel(callback);
315 }
316 
TouchFile(const FileSystemURL & url,const base::Time & last_access_time,const base::Time & last_modified_time,const StatusCallback & callback)317 OperationID FileSystemOperationRunner::TouchFile(
318     const FileSystemURL& url,
319     const base::Time& last_access_time,
320     const base::Time& last_modified_time,
321     const StatusCallback& callback) {
322   base::PlatformFileError error = base::PLATFORM_FILE_OK;
323   FileSystemOperation* operation =
324       file_system_context_->CreateFileSystemOperation(url, &error);
325   BeginOperationScoper scope;
326   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
327   if (!operation) {
328     DidFinish(handle, callback, error);
329     return handle.id;
330   }
331   PrepareForWrite(handle.id, url);
332   operation->TouchFile(
333       url, last_access_time, last_modified_time,
334       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
335                  handle, callback));
336   return handle.id;
337 }
338 
OpenFile(const FileSystemURL & url,int file_flags,const OpenFileCallback & callback)339 OperationID FileSystemOperationRunner::OpenFile(
340     const FileSystemURL& url,
341     int file_flags,
342     const OpenFileCallback& callback) {
343   base::PlatformFileError error = base::PLATFORM_FILE_OK;
344   FileSystemOperation* operation =
345       file_system_context_->CreateFileSystemOperation(url, &error);
346   BeginOperationScoper scope;
347   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
348   if (!operation) {
349     DidOpenFile(handle, callback, error, base::kInvalidPlatformFileValue,
350                 base::Closure());
351     return handle.id;
352   }
353   if (file_flags &
354       (base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_OPEN_ALWAYS |
355        base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_OPEN_TRUNCATED |
356        base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE |
357        base::PLATFORM_FILE_DELETE_ON_CLOSE |
358        base::PLATFORM_FILE_WRITE_ATTRIBUTES)) {
359     PrepareForWrite(handle.id, url);
360   } else {
361     PrepareForRead(handle.id, url);
362   }
363   operation->OpenFile(
364       url, file_flags,
365       base::Bind(&FileSystemOperationRunner::DidOpenFile, AsWeakPtr(),
366                  handle, callback));
367   return handle.id;
368 }
369 
CreateSnapshotFile(const FileSystemURL & url,const SnapshotFileCallback & callback)370 OperationID FileSystemOperationRunner::CreateSnapshotFile(
371     const FileSystemURL& url,
372     const SnapshotFileCallback& callback) {
373   base::PlatformFileError error = base::PLATFORM_FILE_OK;
374   FileSystemOperation* operation =
375       file_system_context_->CreateFileSystemOperation(url, &error);
376   BeginOperationScoper scope;
377   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
378   if (!operation) {
379     DidCreateSnapshot(handle, callback, error, base::PlatformFileInfo(),
380                       base::FilePath(), NULL);
381     return handle.id;
382   }
383   PrepareForRead(handle.id, url);
384   operation->CreateSnapshotFile(
385       url,
386       base::Bind(&FileSystemOperationRunner::DidCreateSnapshot, AsWeakPtr(),
387                  handle, callback));
388   return handle.id;
389 }
390 
CopyInForeignFile(const base::FilePath & src_local_disk_path,const FileSystemURL & dest_url,const StatusCallback & callback)391 OperationID FileSystemOperationRunner::CopyInForeignFile(
392     const base::FilePath& src_local_disk_path,
393     const FileSystemURL& dest_url,
394     const StatusCallback& callback) {
395   base::PlatformFileError error = base::PLATFORM_FILE_OK;
396   FileSystemOperation* operation =
397       file_system_context_->CreateFileSystemOperation(dest_url, &error);
398   BeginOperationScoper scope;
399   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
400   if (!operation) {
401     DidFinish(handle, callback, error);
402     return handle.id;
403   }
404   operation->CopyInForeignFile(
405       src_local_disk_path, dest_url,
406       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
407                  handle, callback));
408   return handle.id;
409 }
410 
RemoveFile(const FileSystemURL & url,const StatusCallback & callback)411 OperationID FileSystemOperationRunner::RemoveFile(
412     const FileSystemURL& url,
413     const StatusCallback& callback) {
414   base::PlatformFileError error = base::PLATFORM_FILE_OK;
415   FileSystemOperation* operation =
416       file_system_context_->CreateFileSystemOperation(url, &error);
417   BeginOperationScoper scope;
418   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
419   if (!operation) {
420     DidFinish(handle, callback, error);
421     return handle.id;
422   }
423   operation->RemoveFile(
424       url,
425       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
426                  handle, callback));
427   return handle.id;
428 }
429 
RemoveDirectory(const FileSystemURL & url,const StatusCallback & callback)430 OperationID FileSystemOperationRunner::RemoveDirectory(
431     const FileSystemURL& url,
432     const StatusCallback& callback) {
433   base::PlatformFileError error = base::PLATFORM_FILE_OK;
434   FileSystemOperation* operation =
435       file_system_context_->CreateFileSystemOperation(url, &error);
436   BeginOperationScoper scope;
437   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
438   if (!operation) {
439     DidFinish(handle, callback, error);
440     return handle.id;
441   }
442   operation->RemoveDirectory(
443       url,
444       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
445                  handle, callback));
446   return handle.id;
447 }
448 
CopyFileLocal(const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,const CopyFileProgressCallback & progress_callback,const StatusCallback & callback)449 OperationID FileSystemOperationRunner::CopyFileLocal(
450     const FileSystemURL& src_url,
451     const FileSystemURL& dest_url,
452     CopyOrMoveOption option,
453     const CopyFileProgressCallback& progress_callback,
454     const StatusCallback& callback) {
455   base::PlatformFileError error = base::PLATFORM_FILE_OK;
456   FileSystemOperation* operation =
457       file_system_context_->CreateFileSystemOperation(src_url, &error);
458   BeginOperationScoper scope;
459   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
460   if (!operation) {
461     DidFinish(handle, callback, error);
462     return handle.id;
463   }
464   operation->CopyFileLocal(
465       src_url, dest_url, option, progress_callback,
466       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
467                  handle, callback));
468   return handle.id;
469 }
470 
MoveFileLocal(const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,const StatusCallback & callback)471 OperationID FileSystemOperationRunner::MoveFileLocal(
472     const FileSystemURL& src_url,
473     const FileSystemURL& dest_url,
474     CopyOrMoveOption option,
475     const StatusCallback& callback) {
476   base::PlatformFileError error = base::PLATFORM_FILE_OK;
477   FileSystemOperation* operation =
478       file_system_context_->CreateFileSystemOperation(src_url, &error);
479   BeginOperationScoper scope;
480   OperationHandle handle = BeginOperation(operation, scope.AsWeakPtr());
481   if (!operation) {
482     DidFinish(handle, callback, error);
483     return handle.id;
484   }
485   operation->MoveFileLocal(
486       src_url, dest_url, option,
487       base::Bind(&FileSystemOperationRunner::DidFinish, AsWeakPtr(),
488                  handle, callback));
489   return handle.id;
490 }
491 
SyncGetPlatformPath(const FileSystemURL & url,base::FilePath * platform_path)492 base::PlatformFileError FileSystemOperationRunner::SyncGetPlatformPath(
493     const FileSystemURL& url,
494     base::FilePath* platform_path) {
495   base::PlatformFileError error = base::PLATFORM_FILE_OK;
496   scoped_ptr<FileSystemOperation> operation(
497       file_system_context_->CreateFileSystemOperation(url, &error));
498   if (!operation.get())
499     return error;
500   return operation->SyncGetPlatformPath(url, platform_path);
501 }
502 
FileSystemOperationRunner(FileSystemContext * file_system_context)503 FileSystemOperationRunner::FileSystemOperationRunner(
504     FileSystemContext* file_system_context)
505     : file_system_context_(file_system_context) {}
506 
DidFinish(const OperationHandle & handle,const StatusCallback & callback,base::PlatformFileError rv)507 void FileSystemOperationRunner::DidFinish(
508     const OperationHandle& handle,
509     const StatusCallback& callback,
510     base::PlatformFileError rv) {
511   if (handle.scope) {
512     finished_operations_.insert(handle.id);
513     base::MessageLoopProxy::current()->PostTask(
514         FROM_HERE, base::Bind(&FileSystemOperationRunner::DidFinish,
515                               AsWeakPtr(), handle, callback, rv));
516     return;
517   }
518   callback.Run(rv);
519   FinishOperation(handle.id);
520 }
521 
DidGetMetadata(const OperationHandle & handle,const GetMetadataCallback & callback,base::PlatformFileError rv,const base::PlatformFileInfo & file_info)522 void FileSystemOperationRunner::DidGetMetadata(
523     const OperationHandle& handle,
524     const GetMetadataCallback& callback,
525     base::PlatformFileError rv,
526     const base::PlatformFileInfo& file_info) {
527   if (handle.scope) {
528     finished_operations_.insert(handle.id);
529     base::MessageLoopProxy::current()->PostTask(
530         FROM_HERE, base::Bind(&FileSystemOperationRunner::DidGetMetadata,
531                               AsWeakPtr(), handle, callback, rv, file_info));
532     return;
533   }
534   callback.Run(rv, file_info);
535   FinishOperation(handle.id);
536 }
537 
DidReadDirectory(const OperationHandle & handle,const ReadDirectoryCallback & callback,base::PlatformFileError rv,const std::vector<DirectoryEntry> & entries,bool has_more)538 void FileSystemOperationRunner::DidReadDirectory(
539     const OperationHandle& handle,
540     const ReadDirectoryCallback& callback,
541     base::PlatformFileError rv,
542     const std::vector<DirectoryEntry>& entries,
543     bool has_more) {
544   if (handle.scope) {
545     finished_operations_.insert(handle.id);
546     base::MessageLoopProxy::current()->PostTask(
547         FROM_HERE, base::Bind(&FileSystemOperationRunner::DidReadDirectory,
548                               AsWeakPtr(), handle, callback, rv,
549                               entries, has_more));
550     return;
551   }
552   callback.Run(rv, entries, has_more);
553   if (rv != base::PLATFORM_FILE_OK || !has_more)
554     FinishOperation(handle.id);
555 }
556 
DidWrite(const OperationHandle & handle,const WriteCallback & callback,base::PlatformFileError rv,int64 bytes,bool complete)557 void FileSystemOperationRunner::DidWrite(
558     const OperationHandle& handle,
559     const WriteCallback& callback,
560     base::PlatformFileError rv,
561     int64 bytes,
562     bool complete) {
563   if (handle.scope) {
564     finished_operations_.insert(handle.id);
565     base::MessageLoopProxy::current()->PostTask(
566         FROM_HERE, base::Bind(&FileSystemOperationRunner::DidWrite, AsWeakPtr(),
567                               handle, callback, rv, bytes, complete));
568     return;
569   }
570   callback.Run(rv, bytes, complete);
571   if (rv != base::PLATFORM_FILE_OK || complete)
572     FinishOperation(handle.id);
573 }
574 
DidOpenFile(const OperationHandle & handle,const OpenFileCallback & callback,base::PlatformFileError rv,base::PlatformFile file,const base::Closure & on_close_callback)575 void FileSystemOperationRunner::DidOpenFile(
576     const OperationHandle& handle,
577     const OpenFileCallback& callback,
578     base::PlatformFileError rv,
579     base::PlatformFile file,
580     const base::Closure& on_close_callback) {
581   if (handle.scope) {
582     finished_operations_.insert(handle.id);
583     base::MessageLoopProxy::current()->PostTask(
584         FROM_HERE, base::Bind(&FileSystemOperationRunner::DidOpenFile,
585                               AsWeakPtr(), handle, callback, rv, file,
586                               on_close_callback));
587     return;
588   }
589   callback.Run(rv, file, on_close_callback);
590   FinishOperation(handle.id);
591 }
592 
DidCreateSnapshot(const OperationHandle & handle,const SnapshotFileCallback & callback,base::PlatformFileError rv,const base::PlatformFileInfo & file_info,const base::FilePath & platform_path,const scoped_refptr<webkit_blob::ShareableFileReference> & file_ref)593 void FileSystemOperationRunner::DidCreateSnapshot(
594     const OperationHandle& handle,
595     const SnapshotFileCallback& callback,
596     base::PlatformFileError rv,
597     const base::PlatformFileInfo& file_info,
598     const base::FilePath& platform_path,
599     const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
600   if (handle.scope) {
601     finished_operations_.insert(handle.id);
602     base::MessageLoopProxy::current()->PostTask(
603         FROM_HERE, base::Bind(&FileSystemOperationRunner::DidCreateSnapshot,
604                               AsWeakPtr(), handle, callback, rv, file_info,
605                               platform_path, file_ref));
606     return;
607   }
608   callback.Run(rv, file_info, platform_path, file_ref);
609   FinishOperation(handle.id);
610 }
611 
OnCopyProgress(const OperationHandle & handle,const CopyProgressCallback & callback,FileSystemOperation::CopyProgressType type,const FileSystemURL & source_url,const FileSystemURL & dest_url,int64 size)612 void FileSystemOperationRunner::OnCopyProgress(
613     const OperationHandle& handle,
614     const CopyProgressCallback& callback,
615     FileSystemOperation::CopyProgressType type,
616     const FileSystemURL& source_url,
617     const FileSystemURL& dest_url,
618     int64 size) {
619   if (handle.scope) {
620     base::MessageLoopProxy::current()->PostTask(
621         FROM_HERE, base::Bind(
622             &FileSystemOperationRunner::OnCopyProgress,
623             AsWeakPtr(), handle, callback, type, source_url, dest_url, size));
624     return;
625   }
626   callback.Run(type, source_url, dest_url, size);
627 }
628 
PrepareForWrite(OperationID id,const FileSystemURL & url)629 void FileSystemOperationRunner::PrepareForWrite(OperationID id,
630                                                 const FileSystemURL& url) {
631   if (file_system_context_->GetUpdateObservers(url.type())) {
632     file_system_context_->GetUpdateObservers(url.type())->Notify(
633         &FileUpdateObserver::OnStartUpdate, MakeTuple(url));
634   }
635   write_target_urls_[id].insert(url);
636 }
637 
PrepareForRead(OperationID id,const FileSystemURL & url)638 void FileSystemOperationRunner::PrepareForRead(OperationID id,
639                                                const FileSystemURL& url) {
640   if (file_system_context_->GetAccessObservers(url.type())) {
641     file_system_context_->GetAccessObservers(url.type())->Notify(
642         &FileAccessObserver::OnAccess, MakeTuple(url));
643   }
644 }
645 
646 FileSystemOperationRunner::OperationHandle
BeginOperation(FileSystemOperation * operation,base::WeakPtr<BeginOperationScoper> scope)647 FileSystemOperationRunner::BeginOperation(
648     FileSystemOperation* operation,
649     base::WeakPtr<BeginOperationScoper> scope) {
650   OperationHandle handle;
651   handle.id = operations_.Add(operation);
652   handle.scope = scope;
653   return handle;
654 }
655 
FinishOperation(OperationID id)656 void FileSystemOperationRunner::FinishOperation(OperationID id) {
657   OperationToURLSet::iterator found = write_target_urls_.find(id);
658   if (found != write_target_urls_.end()) {
659     const FileSystemURLSet& urls = found->second;
660     for (FileSystemURLSet::const_iterator iter = urls.begin();
661         iter != urls.end(); ++iter) {
662       if (file_system_context_->GetUpdateObservers(iter->type())) {
663         file_system_context_->GetUpdateObservers(iter->type())->Notify(
664             &FileUpdateObserver::OnEndUpdate, MakeTuple(*iter));
665       }
666     }
667     write_target_urls_.erase(found);
668   }
669 
670   // IDMap::Lookup fails if the operation is NULL, so we don't check
671   // operations_.Lookup(id) here.
672 
673   operations_.Remove(id);
674   finished_operations_.erase(id);
675 
676   // Dispatch stray cancel callback if exists.
677   std::map<OperationID, StatusCallback>::iterator found_cancel =
678       stray_cancel_callbacks_.find(id);
679   if (found_cancel != stray_cancel_callbacks_.end()) {
680     // This cancel has been requested after the operation has finished,
681     // so report that we failed to stop it.
682     found_cancel->second.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
683     stray_cancel_callbacks_.erase(found_cancel);
684   }
685 }
686 
687 }  // namespace fileapi
688