syncable_file_system_operation.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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 storage::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  DCHECK(operation_runner_.get());
108  target_paths_.push_back(url);
109  completion_callback_ = callback;
110  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
111      weak_factory_.GetWeakPtr(),
112      base::Bind(&FileSystemOperation::CreateDirectory,
113                 base::Unretained(impl_.get()),
114                 url, exclusive, recursive,
115                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
116  operation_runner_->PostOperationTask(task.Pass());
117}
118
119void SyncableFileSystemOperation::Copy(
120    const FileSystemURL& src_url,
121    const FileSystemURL& dest_url,
122    CopyOrMoveOption option,
123    const CopyProgressCallback& progress_callback,
124    const StatusCallback& callback) {
125  DCHECK(CalledOnValidThread());
126  if (!operation_runner_.get()) {
127    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
128    return;
129  }
130  DCHECK(operation_runner_.get());
131  target_paths_.push_back(dest_url);
132  completion_callback_ = callback;
133  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
134      weak_factory_.GetWeakPtr(),
135      base::Bind(&FileSystemOperation::Copy,
136                 base::Unretained(impl_.get()),
137                 src_url, dest_url, option, progress_callback,
138                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
139  operation_runner_->PostOperationTask(task.Pass());
140}
141
142void SyncableFileSystemOperation::Move(
143    const FileSystemURL& src_url,
144    const FileSystemURL& dest_url,
145    CopyOrMoveOption option,
146    const StatusCallback& callback) {
147  DCHECK(CalledOnValidThread());
148  if (!operation_runner_.get()) {
149    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
150    return;
151  }
152  DCHECK(operation_runner_.get());
153  target_paths_.push_back(src_url);
154  target_paths_.push_back(dest_url);
155  completion_callback_ = callback;
156  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
157      weak_factory_.GetWeakPtr(),
158      base::Bind(&FileSystemOperation::Move,
159                 base::Unretained(impl_.get()),
160                 src_url, dest_url, option,
161                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
162  operation_runner_->PostOperationTask(task.Pass());
163}
164
165void SyncableFileSystemOperation::DirectoryExists(
166    const FileSystemURL& url,
167    const StatusCallback& callback) {
168  DCHECK(CalledOnValidThread());
169  impl_->DirectoryExists(url, callback);
170}
171
172void SyncableFileSystemOperation::FileExists(
173    const FileSystemURL& url,
174    const StatusCallback& callback) {
175  DCHECK(CalledOnValidThread());
176  impl_->FileExists(url, callback);
177}
178
179void SyncableFileSystemOperation::GetMetadata(
180    const FileSystemURL& url,
181    const GetMetadataCallback& callback) {
182  DCHECK(CalledOnValidThread());
183  impl_->GetMetadata(url, callback);
184}
185
186void SyncableFileSystemOperation::ReadDirectory(
187    const FileSystemURL& url,
188    const ReadDirectoryCallback& callback) {
189  DCHECK(CalledOnValidThread());
190  // This is a read operation and there'd be no hard to let it go even if
191  // directory operation is disabled. (And we should allow this if it's made
192  // on the root directory)
193  impl_->ReadDirectory(url, callback);
194}
195
196void SyncableFileSystemOperation::Remove(
197    const FileSystemURL& url, bool recursive,
198    const StatusCallback& callback) {
199  DCHECK(CalledOnValidThread());
200  if (!operation_runner_.get()) {
201    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
202    return;
203  }
204  DCHECK(operation_runner_.get());
205  target_paths_.push_back(url);
206  completion_callback_ = callback;
207  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
208      weak_factory_.GetWeakPtr(),
209      base::Bind(&FileSystemOperation::Remove,
210                 base::Unretained(impl_.get()),
211                 url, recursive,
212                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
213  operation_runner_->PostOperationTask(task.Pass());
214}
215
216void SyncableFileSystemOperation::Write(
217    const FileSystemURL& url,
218    scoped_ptr<storage::FileWriterDelegate> writer_delegate,
219    scoped_ptr<net::URLRequest> blob_request,
220    const WriteCallback& callback) {
221  DCHECK(CalledOnValidThread());
222  if (!operation_runner_.get()) {
223    callback.Run(base::File::FILE_ERROR_NOT_FOUND, 0, true);
224    return;
225  }
226  DCHECK(operation_runner_.get());
227  target_paths_.push_back(url);
228  completion_callback_ = base::Bind(&WriteCallbackAdapter, callback);
229  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
230      weak_factory_.GetWeakPtr(),
231      base::Bind(&FileSystemOperation::Write,
232                 base::Unretained(impl_.get()),
233                 url,
234                 base::Passed(&writer_delegate),
235                 base::Passed(&blob_request),
236                 base::Bind(&self::DidWrite, weak_factory_.GetWeakPtr(),
237                            callback))));
238  operation_runner_->PostOperationTask(task.Pass());
239}
240
241void SyncableFileSystemOperation::Truncate(
242    const FileSystemURL& url, int64 length,
243    const StatusCallback& callback) {
244  DCHECK(CalledOnValidThread());
245  if (!operation_runner_.get()) {
246    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
247    return;
248  }
249  DCHECK(operation_runner_.get());
250  target_paths_.push_back(url);
251  completion_callback_ = callback;
252  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
253      weak_factory_.GetWeakPtr(),
254      base::Bind(&FileSystemOperation::Truncate,
255                 base::Unretained(impl_.get()),
256                 url, length,
257                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
258  operation_runner_->PostOperationTask(task.Pass());
259}
260
261void SyncableFileSystemOperation::TouchFile(
262    const FileSystemURL& url,
263    const base::Time& last_access_time,
264    const base::Time& last_modified_time,
265    const StatusCallback& callback) {
266  DCHECK(CalledOnValidThread());
267  impl_->TouchFile(url, last_access_time, last_modified_time, callback);
268}
269
270void SyncableFileSystemOperation::OpenFile(
271    const FileSystemURL& url,
272    int file_flags,
273    const OpenFileCallback& callback) {
274  NOTREACHED();
275}
276
277void SyncableFileSystemOperation::Cancel(
278    const StatusCallback& cancel_callback) {
279  DCHECK(CalledOnValidThread());
280  impl_->Cancel(cancel_callback);
281}
282
283void SyncableFileSystemOperation::CreateSnapshotFile(
284    const FileSystemURL& path,
285    const SnapshotFileCallback& callback) {
286  DCHECK(CalledOnValidThread());
287  impl_->CreateSnapshotFile(path, callback);
288}
289
290void SyncableFileSystemOperation::CopyInForeignFile(
291    const base::FilePath& src_local_disk_path,
292    const FileSystemURL& dest_url,
293    const StatusCallback& callback) {
294  DCHECK(CalledOnValidThread());
295  if (!operation_runner_.get()) {
296    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
297    return;
298  }
299  DCHECK(operation_runner_.get());
300  target_paths_.push_back(dest_url);
301  completion_callback_ = callback;
302  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
303      weak_factory_.GetWeakPtr(),
304      base::Bind(&FileSystemOperation::CopyInForeignFile,
305                 base::Unretained(impl_.get()),
306                 src_local_disk_path, dest_url,
307                 base::Bind(&self::DidFinish, weak_factory_.GetWeakPtr()))));
308  operation_runner_->PostOperationTask(task.Pass());
309}
310
311void SyncableFileSystemOperation::RemoveFile(
312    const FileSystemURL& url,
313    const StatusCallback& callback) {
314  DCHECK(CalledOnValidThread());
315  impl_->RemoveFile(url, callback);
316}
317
318void SyncableFileSystemOperation::RemoveDirectory(
319    const FileSystemURL& url,
320    const StatusCallback& callback) {
321  DCHECK(CalledOnValidThread());
322  impl_->RemoveDirectory(url, callback);
323}
324
325void SyncableFileSystemOperation::CopyFileLocal(
326    const FileSystemURL& src_url,
327    const FileSystemURL& dest_url,
328    CopyOrMoveOption option,
329    const CopyFileProgressCallback& progress_callback,
330    const StatusCallback& callback) {
331  DCHECK(CalledOnValidThread());
332  impl_->CopyFileLocal(src_url, dest_url, option, progress_callback, callback);
333}
334
335void SyncableFileSystemOperation::MoveFileLocal(
336    const FileSystemURL& src_url,
337    const FileSystemURL& dest_url,
338    CopyOrMoveOption option,
339    const StatusCallback& callback) {
340  DCHECK(CalledOnValidThread());
341  impl_->MoveFileLocal(src_url, dest_url, option, callback);
342}
343
344base::File::Error SyncableFileSystemOperation::SyncGetPlatformPath(
345    const FileSystemURL& url,
346    base::FilePath* platform_path) {
347  return impl_->SyncGetPlatformPath(url, platform_path);
348}
349
350SyncableFileSystemOperation::SyncableFileSystemOperation(
351    const FileSystemURL& url,
352    storage::FileSystemContext* file_system_context,
353    scoped_ptr<storage::FileSystemOperationContext> operation_context)
354    : url_(url), weak_factory_(this) {
355  DCHECK(file_system_context);
356  SyncFileSystemBackend* backend =
357      SyncFileSystemBackend::GetBackend(file_system_context);
358  DCHECK(backend);
359  if (!backend->sync_context()) {
360    // Syncable FileSystem is opened in a file system context which doesn't
361    // support (or is not initialized for) the API.
362    // Returning here to leave operation_runner_ as NULL.
363    return;
364  }
365  impl_.reset(storage::FileSystemOperation::Create(
366      url_, file_system_context, operation_context.Pass()));
367  operation_runner_ = backend->sync_context()->operation_runner();
368}
369
370void SyncableFileSystemOperation::DidFinish(base::File::Error status) {
371  DCHECK(CalledOnValidThread());
372  DCHECK(!completion_callback_.is_null());
373  if (operation_runner_.get())
374    operation_runner_->OnOperationCompleted(target_paths_);
375  completion_callback_.Run(status);
376}
377
378void SyncableFileSystemOperation::DidWrite(
379    const WriteCallback& callback,
380    base::File::Error result,
381    int64 bytes,
382    bool complete) {
383  DCHECK(CalledOnValidThread());
384  if (!complete) {
385    callback.Run(result, bytes, complete);
386    return;
387  }
388  if (operation_runner_.get())
389    operation_runner_->OnOperationCompleted(target_paths_);
390  callback.Run(result, bytes, complete);
391}
392
393void SyncableFileSystemOperation::OnCancelled() {
394  DCHECK(!completion_callback_.is_null());
395  completion_callback_.Run(base::File::FILE_ERROR_ABORT);
396}
397
398}  // namespace sync_file_system
399