syncable_file_system_operation.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 "chrome/browser/sync_file_system/local/syncable_file_system_operation.h"
6
7#include "base/logging.h"
8#include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
9#include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
10#include "chrome/browser/sync_file_system/local/syncable_file_operation_runner.h"
11#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
12#include "net/url_request/url_request.h"
13#include "webkit/browser/fileapi/file_system_context.h"
14#include "webkit/browser/fileapi/file_system_operation.h"
15#include "webkit/browser/fileapi/file_system_operation_context.h"
16#include "webkit/browser/fileapi/file_system_url.h"
17#include "webkit/browser/fileapi/file_writer_delegate.h"
18#include "webkit/common/blob/shareable_file_reference.h"
19
20using fileapi::FileSystemURL;
21
22namespace sync_file_system {
23
24namespace {
25
26void WriteCallbackAdapter(
27    const SyncableFileSystemOperation::WriteCallback& callback,
28    base::File::Error status) {
29  callback.Run(status, 0, true);
30}
31
32}  // namespace
33
34class SyncableFileSystemOperation::QueueableTask
35    : public SyncableFileOperationRunner::Task {
36 public:
37  QueueableTask(base::WeakPtr<SyncableFileSystemOperation> operation,
38                const base::Closure& task)
39      : operation_(operation),
40        task_(task),
41        target_paths_(operation->target_paths_) {}
42
43  virtual ~QueueableTask() {
44    DCHECK(!operation_);
45  }
46
47  virtual void Run() OVERRIDE {
48    if (!operation_)
49      return;
50    DCHECK(!task_.is_null());
51    task_.Run();
52    operation_.reset();
53  }
54
55  virtual void Cancel() OVERRIDE {
56    DCHECK(!task_.is_null());
57    if (operation_)
58      operation_->OnCancelled();
59    task_.Reset();
60    operation_.reset();
61  }
62
63  virtual const std::vector<FileSystemURL>& target_paths() const OVERRIDE {
64    return target_paths_;
65  }
66
67 private:
68  base::WeakPtr<SyncableFileSystemOperation> operation_;
69  base::Closure task_;
70  std::vector<FileSystemURL> target_paths_;
71  DISALLOW_COPY_AND_ASSIGN(QueueableTask);
72};
73
74SyncableFileSystemOperation::~SyncableFileSystemOperation() {}
75
76void SyncableFileSystemOperation::CreateFile(
77    const FileSystemURL& url,
78    bool exclusive,
79    const StatusCallback& callback) {
80  DCHECK(CalledOnValidThread());
81  if (!operation_runner_.get()) {
82    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
83    return;
84  }
85  DCHECK(operation_runner_.get());
86  target_paths_.push_back(url);
87  completion_callback_ = callback;
88  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
89      weak_factory_.GetWeakPtr(),
90      base::Bind(&FileSystemOperation::CreateFile,
91                 base::Unretained(impl_.get()),
92                 url, exclusive,
93                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
94  operation_runner_->PostOperationTask(task.Pass());
95}
96
97void SyncableFileSystemOperation::CreateDirectory(
98    const FileSystemURL& url,
99    bool exclusive,
100    bool recursive,
101    const StatusCallback& callback) {
102  DCHECK(CalledOnValidThread());
103  if (!operation_runner_.get()) {
104    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
105    return;
106  }
107  if (!is_directory_operation_enabled_) {
108    callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
109    return;
110  }
111  DCHECK(operation_runner_.get());
112  target_paths_.push_back(url);
113  completion_callback_ = callback;
114  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
115      weak_factory_.GetWeakPtr(),
116      base::Bind(&FileSystemOperation::CreateDirectory,
117                 base::Unretained(impl_.get()),
118                 url, exclusive, recursive,
119                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
120  operation_runner_->PostOperationTask(task.Pass());
121}
122
123void SyncableFileSystemOperation::Copy(
124    const FileSystemURL& src_url,
125    const FileSystemURL& dest_url,
126    CopyOrMoveOption option,
127    const CopyProgressCallback& progress_callback,
128    const StatusCallback& callback) {
129  DCHECK(CalledOnValidThread());
130  if (!operation_runner_.get()) {
131    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
132    return;
133  }
134  DCHECK(operation_runner_.get());
135  target_paths_.push_back(dest_url);
136  completion_callback_ = callback;
137  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
138      weak_factory_.GetWeakPtr(),
139      base::Bind(&FileSystemOperation::Copy,
140                 base::Unretained(impl_.get()),
141                 src_url, dest_url, option, progress_callback,
142                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
143  operation_runner_->PostOperationTask(task.Pass());
144}
145
146void SyncableFileSystemOperation::Move(
147    const FileSystemURL& src_url,
148    const FileSystemURL& dest_url,
149    CopyOrMoveOption option,
150    const StatusCallback& callback) {
151  DCHECK(CalledOnValidThread());
152  if (!operation_runner_.get()) {
153    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
154    return;
155  }
156  DCHECK(operation_runner_.get());
157  target_paths_.push_back(src_url);
158  target_paths_.push_back(dest_url);
159  completion_callback_ = callback;
160  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
161      weak_factory_.GetWeakPtr(),
162      base::Bind(&FileSystemOperation::Move,
163                 base::Unretained(impl_.get()),
164                 src_url, dest_url, option,
165                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
166  operation_runner_->PostOperationTask(task.Pass());
167}
168
169void SyncableFileSystemOperation::DirectoryExists(
170    const FileSystemURL& url,
171    const StatusCallback& callback) {
172  DCHECK(CalledOnValidThread());
173  impl_->DirectoryExists(url, callback);
174}
175
176void SyncableFileSystemOperation::FileExists(
177    const FileSystemURL& url,
178    const StatusCallback& callback) {
179  DCHECK(CalledOnValidThread());
180  impl_->FileExists(url, callback);
181}
182
183void SyncableFileSystemOperation::GetMetadata(
184    const FileSystemURL& url,
185    const GetMetadataCallback& callback) {
186  DCHECK(CalledOnValidThread());
187  impl_->GetMetadata(url, callback);
188}
189
190void SyncableFileSystemOperation::ReadDirectory(
191    const FileSystemURL& url,
192    const ReadDirectoryCallback& callback) {
193  DCHECK(CalledOnValidThread());
194  // This is a read operation and there'd be no hard to let it go even if
195  // directory operation is disabled. (And we should allow this if it's made
196  // on the root directory)
197  impl_->ReadDirectory(url, callback);
198}
199
200void SyncableFileSystemOperation::Remove(
201    const FileSystemURL& url, bool recursive,
202    const StatusCallback& callback) {
203  DCHECK(CalledOnValidThread());
204  if (!operation_runner_.get()) {
205    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
206    return;
207  }
208  DCHECK(operation_runner_.get());
209  target_paths_.push_back(url);
210  completion_callback_ = callback;
211  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
212      weak_factory_.GetWeakPtr(),
213      base::Bind(&FileSystemOperation::Remove,
214                 base::Unretained(impl_.get()),
215                 url, recursive,
216                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
217  operation_runner_->PostOperationTask(task.Pass());
218}
219
220void SyncableFileSystemOperation::Write(
221    const FileSystemURL& url,
222    scoped_ptr<fileapi::FileWriterDelegate> writer_delegate,
223    scoped_ptr<net::URLRequest> blob_request,
224    const WriteCallback& callback) {
225  DCHECK(CalledOnValidThread());
226  if (!operation_runner_.get()) {
227    callback.Run(base::File::FILE_ERROR_NOT_FOUND, 0, true);
228    return;
229  }
230  DCHECK(operation_runner_.get());
231  target_paths_.push_back(url);
232  completion_callback_ = base::Bind(&WriteCallbackAdapter, callback);
233  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
234      weak_factory_.GetWeakPtr(),
235      base::Bind(&FileSystemOperation::Write,
236                 base::Unretained(impl_.get()),
237                 url,
238                 base::Passed(&writer_delegate),
239                 base::Passed(&blob_request),
240                 base::Bind(&self::DidWrite, weak_factory_.GetWeakPtr(),
241                            callback))));
242  operation_runner_->PostOperationTask(task.Pass());
243}
244
245void SyncableFileSystemOperation::Truncate(
246    const FileSystemURL& url, int64 length,
247    const StatusCallback& callback) {
248  DCHECK(CalledOnValidThread());
249  if (!operation_runner_.get()) {
250    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
251    return;
252  }
253  DCHECK(operation_runner_.get());
254  target_paths_.push_back(url);
255  completion_callback_ = callback;
256  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
257      weak_factory_.GetWeakPtr(),
258      base::Bind(&FileSystemOperation::Truncate,
259                 base::Unretained(impl_.get()),
260                 url, length,
261                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
262  operation_runner_->PostOperationTask(task.Pass());
263}
264
265void SyncableFileSystemOperation::TouchFile(
266    const FileSystemURL& url,
267    const base::Time& last_access_time,
268    const base::Time& last_modified_time,
269    const StatusCallback& callback) {
270  DCHECK(CalledOnValidThread());
271  impl_->TouchFile(url, last_access_time, last_modified_time, callback);
272}
273
274void SyncableFileSystemOperation::OpenFile(
275    const FileSystemURL& url,
276    int file_flags,
277    const OpenFileCallback& callback) {
278  NOTREACHED();
279}
280
281void SyncableFileSystemOperation::Cancel(
282    const StatusCallback& cancel_callback) {
283  DCHECK(CalledOnValidThread());
284  impl_->Cancel(cancel_callback);
285}
286
287void SyncableFileSystemOperation::CreateSnapshotFile(
288    const FileSystemURL& path,
289    const SnapshotFileCallback& callback) {
290  DCHECK(CalledOnValidThread());
291  impl_->CreateSnapshotFile(path, callback);
292}
293
294void SyncableFileSystemOperation::CopyInForeignFile(
295    const base::FilePath& src_local_disk_path,
296    const FileSystemURL& dest_url,
297    const StatusCallback& callback) {
298  DCHECK(CalledOnValidThread());
299  if (!operation_runner_.get()) {
300    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
301    return;
302  }
303  DCHECK(operation_runner_.get());
304  target_paths_.push_back(dest_url);
305  completion_callback_ = callback;
306  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
307      weak_factory_.GetWeakPtr(),
308      base::Bind(&FileSystemOperation::CopyInForeignFile,
309                 base::Unretained(impl_.get()),
310                 src_local_disk_path, dest_url,
311                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
312  operation_runner_->PostOperationTask(task.Pass());
313}
314
315void SyncableFileSystemOperation::RemoveFile(
316    const FileSystemURL& url,
317    const StatusCallback& callback) {
318  DCHECK(CalledOnValidThread());
319  impl_->RemoveFile(url, callback);
320}
321
322void SyncableFileSystemOperation::RemoveDirectory(
323    const FileSystemURL& url,
324    const StatusCallback& callback) {
325  DCHECK(CalledOnValidThread());
326  impl_->RemoveDirectory(url, callback);
327}
328
329void SyncableFileSystemOperation::CopyFileLocal(
330    const FileSystemURL& src_url,
331    const FileSystemURL& dest_url,
332    CopyOrMoveOption option,
333    const CopyFileProgressCallback& progress_callback,
334    const StatusCallback& callback) {
335  DCHECK(CalledOnValidThread());
336  impl_->CopyFileLocal(src_url, dest_url, option, progress_callback, callback);
337}
338
339void SyncableFileSystemOperation::MoveFileLocal(
340    const FileSystemURL& src_url,
341    const FileSystemURL& dest_url,
342    CopyOrMoveOption option,
343    const StatusCallback& callback) {
344  DCHECK(CalledOnValidThread());
345  impl_->MoveFileLocal(src_url, dest_url, option, callback);
346}
347
348base::File::Error SyncableFileSystemOperation::SyncGetPlatformPath(
349    const FileSystemURL& url,
350    base::FilePath* platform_path) {
351  return impl_->SyncGetPlatformPath(url, platform_path);
352}
353
354SyncableFileSystemOperation::SyncableFileSystemOperation(
355    const FileSystemURL& url,
356    fileapi::FileSystemContext* file_system_context,
357    scoped_ptr<fileapi::FileSystemOperationContext> operation_context)
358    : url_(url),
359      weak_factory_(this) {
360  DCHECK(file_system_context);
361  SyncFileSystemBackend* backend =
362      SyncFileSystemBackend::GetBackend(file_system_context);
363  DCHECK(backend);
364  if (!backend->sync_context()) {
365    // Syncable FileSystem is opened in a file system context which doesn't
366    // support (or is not initialized for) the API.
367    // Returning here to leave operation_runner_ as NULL.
368    return;
369  }
370  impl_.reset(fileapi::FileSystemOperation::Create(
371      url_, file_system_context, operation_context.Pass()));
372  operation_runner_ = backend->sync_context()->operation_runner();
373  is_directory_operation_enabled_ = IsSyncFSDirectoryOperationEnabled(
374      url.origin());
375}
376
377void SyncableFileSystemOperation::DidFinish(base::File::Error status) {
378  DCHECK(CalledOnValidThread());
379  DCHECK(!completion_callback_.is_null());
380  if (operation_runner_.get())
381    operation_runner_->OnOperationCompleted(target_paths_);
382  completion_callback_.Run(status);
383}
384
385void SyncableFileSystemOperation::DidWrite(
386    const WriteCallback& callback,
387    base::File::Error result,
388    int64 bytes,
389    bool complete) {
390  DCHECK(CalledOnValidThread());
391  if (!complete) {
392    callback.Run(result, bytes, complete);
393    return;
394  }
395  if (operation_runner_.get())
396    operation_runner_->OnOperationCompleted(target_paths_);
397  callback.Run(result, bytes, complete);
398}
399
400void SyncableFileSystemOperation::OnCancelled() {
401  DCHECK(!completion_callback_.is_null());
402  completion_callback_.Run(base::File::FILE_ERROR_ABORT);
403}
404
405}  // namespace sync_file_system
406