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