syncable_file_system_operation.cc revision 2385ea399aae016c0806a4f9ef3c9cfe3d2a39df
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_context.h"
15#include "webkit/browser/fileapi/file_system_operation_impl.h"
16#include "webkit/browser/fileapi/file_system_url.h"
17#include "webkit/browser/fileapi/sandbox_file_system_backend.h"
18#include "webkit/common/blob/shareable_file_reference.h"
19
20using fileapi::FileSystemURL;
21using fileapi::FileSystemOperationContext;
22using fileapi::FileSystemOperationImpl;
23
24namespace sync_file_system {
25
26namespace {
27
28void WriteCallbackAdapter(
29    const SyncableFileSystemOperation::WriteCallback& callback,
30    base::PlatformFileError status) {
31  callback.Run(status, 0, true);
32}
33
34}  // namespace
35
36class SyncableFileSystemOperation::QueueableTask
37    : public SyncableFileOperationRunner::Task {
38 public:
39  QueueableTask(base::WeakPtr<SyncableFileSystemOperation> operation,
40                const base::Closure& task)
41      : operation_(operation),
42        task_(task),
43        target_paths_(operation->target_paths_) {}
44
45  virtual ~QueueableTask() {
46    DCHECK(!operation_);
47  }
48
49  virtual void Run() OVERRIDE {
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::PLATFORM_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      AsWeakPtr(),
90      base::Bind(&FileSystemOperation::CreateFile,
91                 NewOperation()->AsWeakPtr(),
92                 url, exclusive,
93                 base::Bind(&self::DidFinish, AsWeakPtr()))));
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::PLATFORM_FILE_ERROR_NOT_FOUND);
105    return;
106  }
107  if (!is_directory_operation_enabled_) {
108    callback.Run(base::PLATFORM_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      AsWeakPtr(),
116      base::Bind(&FileSystemOperation::CreateDirectory,
117                 NewOperation()->AsWeakPtr(),
118                 url, exclusive, recursive,
119                 base::Bind(&self::DidFinish, AsWeakPtr()))));
120  operation_runner_->PostOperationTask(task.Pass());
121}
122
123void SyncableFileSystemOperation::Copy(
124    const FileSystemURL& src_url,
125    const FileSystemURL& dest_url,
126    const StatusCallback& callback) {
127  DCHECK(CalledOnValidThread());
128  if (!operation_runner_.get()) {
129    callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND);
130    return;
131  }
132  DCHECK(operation_runner_.get());
133  target_paths_.push_back(dest_url);
134  completion_callback_ = callback;
135  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
136      AsWeakPtr(),
137      base::Bind(&FileSystemOperation::Copy,
138                 NewOperation()->AsWeakPtr(),
139                 src_url, dest_url,
140                 base::Bind(&self::DidFinish, AsWeakPtr()))));
141  operation_runner_->PostOperationTask(task.Pass());
142}
143
144void SyncableFileSystemOperation::Move(
145    const FileSystemURL& src_url,
146    const FileSystemURL& dest_url,
147    const StatusCallback& callback) {
148  DCHECK(CalledOnValidThread());
149  if (!operation_runner_.get()) {
150    callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND);
151    return;
152  }
153  DCHECK(operation_runner_.get());
154  target_paths_.push_back(src_url);
155  target_paths_.push_back(dest_url);
156  completion_callback_ = callback;
157  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
158      AsWeakPtr(),
159      base::Bind(&FileSystemOperation::Move,
160                 NewOperation()->AsWeakPtr(),
161                 src_url, dest_url,
162                 base::Bind(&self::DidFinish, AsWeakPtr()))));
163  operation_runner_->PostOperationTask(task.Pass());
164}
165
166void SyncableFileSystemOperation::DirectoryExists(
167    const FileSystemURL& url,
168    const StatusCallback& callback) {
169  DCHECK(CalledOnValidThread());
170  NewOperation()->DirectoryExists(url, callback);
171}
172
173void SyncableFileSystemOperation::FileExists(
174    const FileSystemURL& url,
175    const StatusCallback& callback) {
176  DCHECK(CalledOnValidThread());
177  NewOperation()->FileExists(url, callback);
178}
179
180void SyncableFileSystemOperation::GetMetadata(
181    const FileSystemURL& url,
182    const GetMetadataCallback& callback) {
183  DCHECK(CalledOnValidThread());
184  NewOperation()->GetMetadata(url, callback);
185}
186
187void SyncableFileSystemOperation::ReadDirectory(
188    const FileSystemURL& url,
189    const ReadDirectoryCallback& callback) {
190  DCHECK(CalledOnValidThread());
191  // This is a read operation and there'd be no hard to let it go even if
192  // directory operation is disabled. (And we should allow this if it's made
193  // on the root directory)
194  NewOperation()->ReadDirectory(url, callback);
195}
196
197void SyncableFileSystemOperation::Remove(
198    const FileSystemURL& url, bool recursive,
199    const StatusCallback& callback) {
200  DCHECK(CalledOnValidThread());
201  if (!operation_runner_.get()) {
202    callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND);
203    return;
204  }
205  DCHECK(operation_runner_.get());
206  target_paths_.push_back(url);
207  completion_callback_ = callback;
208  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
209      AsWeakPtr(),
210      base::Bind(&FileSystemOperation::Remove,
211                 NewOperation()->AsWeakPtr(),
212                 url, recursive,
213                 base::Bind(&self::DidFinish, AsWeakPtr()))));
214  operation_runner_->PostOperationTask(task.Pass());
215}
216
217void SyncableFileSystemOperation::Write(
218    const FileSystemURL& url,
219    scoped_ptr<fileapi::FileWriterDelegate> writer_delegate,
220    scoped_ptr<net::URLRequest> blob_request,
221    const WriteCallback& callback) {
222  DCHECK(CalledOnValidThread());
223  if (!operation_runner_.get()) {
224    callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND, 0, true);
225    return;
226  }
227  DCHECK(operation_runner_.get());
228  target_paths_.push_back(url);
229  completion_callback_ = base::Bind(&WriteCallbackAdapter, callback);
230  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
231      AsWeakPtr(),
232      base::Bind(&FileSystemOperation::Write,
233                 NewOperation()->AsWeakPtr(),
234                 url,
235                 base::Passed(&writer_delegate),
236                 base::Passed(&blob_request),
237                 base::Bind(&self::DidWrite, AsWeakPtr(), 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::PLATFORM_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      AsWeakPtr(),
254      base::Bind(&FileSystemOperation::Truncate,
255                 NewOperation()->AsWeakPtr(),
256                 url, length,
257                 base::Bind(&self::DidFinish, AsWeakPtr()))));
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  NewOperation()->TouchFile(url, last_access_time,
268                            last_modified_time, callback);
269}
270
271void SyncableFileSystemOperation::OpenFile(
272    const FileSystemURL& url,
273    int file_flags,
274    base::ProcessHandle peer_handle,
275    const OpenFileCallback& callback) {
276  NOTREACHED();
277}
278
279void SyncableFileSystemOperation::Cancel(
280    const StatusCallback& cancel_callback) {
281  DCHECK(CalledOnValidThread());
282  DCHECK(inflight_operation_);
283  inflight_operation_->Cancel(cancel_callback);
284}
285
286void SyncableFileSystemOperation::CreateSnapshotFile(
287    const FileSystemURL& path,
288    const SnapshotFileCallback& callback) {
289  DCHECK(CalledOnValidThread());
290  NewOperation()->CreateSnapshotFile(path, callback);
291}
292
293void SyncableFileSystemOperation::CopyInForeignFile(
294    const base::FilePath& src_local_disk_path,
295    const FileSystemURL& dest_url,
296    const StatusCallback& callback) {
297  DCHECK(CalledOnValidThread());
298  if (!operation_runner_.get()) {
299    callback.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND);
300    return;
301  }
302  DCHECK(operation_runner_.get());
303  target_paths_.push_back(dest_url);
304  completion_callback_ = callback;
305  scoped_ptr<SyncableFileOperationRunner::Task> task(new QueueableTask(
306      AsWeakPtr(),
307      base::Bind(&FileSystemOperationImpl::CopyInForeignFile,
308                 NewOperation()->AsWeakPtr(),
309                 src_local_disk_path, dest_url,
310                 base::Bind(&self::DidFinish, AsWeakPtr()))));
311  operation_runner_->PostOperationTask(task.Pass());
312}
313
314SyncableFileSystemOperation::SyncableFileSystemOperation(
315    const FileSystemURL& url,
316    fileapi::FileSystemContext* file_system_context,
317    scoped_ptr<FileSystemOperationContext> operation_context)
318    : FileSystemOperationImpl(url, file_system_context,
319                              operation_context.Pass()),
320      url_(url) {
321  DCHECK(file_system_context);
322  SyncFileSystemBackend* backend =
323      SyncFileSystemBackend::GetBackend(file_system_context);
324  DCHECK(backend);
325  if (!backend->sync_context()) {
326    // Syncable FileSystem is opened in a file system context which doesn't
327    // support (or is not initialized for) the API.
328    // Returning here to leave operation_runner_ as NULL.
329    return;
330  }
331  operation_runner_ = backend->sync_context()->operation_runner();
332  is_directory_operation_enabled_ = IsSyncFSDirectoryOperationEnabled();
333}
334
335FileSystemOperationImpl* SyncableFileSystemOperation::NewOperation() {
336  DCHECK(operation_context_);
337  inflight_operation_.reset(new FileSystemOperationImpl(
338      url_, file_system_context(), operation_context_.Pass()));
339  DCHECK(inflight_operation_);
340  return inflight_operation_.get();
341}
342
343void SyncableFileSystemOperation::DidFinish(base::PlatformFileError status) {
344  DCHECK(CalledOnValidThread());
345  DCHECK(!completion_callback_.is_null());
346  if (operation_runner_.get())
347    operation_runner_->OnOperationCompleted(target_paths_);
348  completion_callback_.Run(status);
349}
350
351void SyncableFileSystemOperation::DidWrite(
352    const WriteCallback& callback,
353    base::PlatformFileError result,
354    int64 bytes,
355    bool complete) {
356  DCHECK(CalledOnValidThread());
357  if (!complete) {
358    callback.Run(result, bytes, complete);
359    return;
360  }
361  if (operation_runner_.get())
362    operation_runner_->OnOperationCompleted(target_paths_);
363  callback.Run(result, bytes, complete);
364}
365
366void SyncableFileSystemOperation::OnCancelled() {
367  DCHECK(!completion_callback_.is_null());
368  completion_callback_.Run(base::PLATFORM_FILE_ERROR_ABORT);
369}
370
371}  // namespace sync_file_system
372