• 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 "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 
20 using fileapi::FileSystemURL;
21 
22 namespace sync_file_system {
23 
24 namespace {
25 
WriteCallbackAdapter(const SyncableFileSystemOperation::WriteCallback & callback,base::File::Error status)26 void WriteCallbackAdapter(
27     const SyncableFileSystemOperation::WriteCallback& callback,
28     base::File::Error status) {
29   callback.Run(status, 0, true);
30 }
31 
32 }  // namespace
33 
34 class SyncableFileSystemOperation::QueueableTask
35     : public SyncableFileOperationRunner::Task {
36  public:
QueueableTask(base::WeakPtr<SyncableFileSystemOperation> operation,const base::Closure & task)37   QueueableTask(base::WeakPtr<SyncableFileSystemOperation> operation,
38                 const base::Closure& task)
39       : operation_(operation),
40         task_(task),
41         target_paths_(operation->target_paths_) {}
42 
~QueueableTask()43   virtual ~QueueableTask() {
44     DCHECK(!operation_);
45   }
46 
Run()47   virtual void Run() OVERRIDE {
48     if (!operation_)
49       return;
50     DCHECK(!task_.is_null());
51     task_.Run();
52     operation_.reset();
53   }
54 
Cancel()55   virtual void Cancel() OVERRIDE {
56     DCHECK(!task_.is_null());
57     if (operation_)
58       operation_->OnCancelled();
59     task_.Reset();
60     operation_.reset();
61   }
62 
target_paths() const63   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 
~SyncableFileSystemOperation()74 SyncableFileSystemOperation::~SyncableFileSystemOperation() {}
75 
CreateFile(const FileSystemURL & url,bool exclusive,const StatusCallback & callback)76 void 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 
CreateDirectory(const FileSystemURL & url,bool exclusive,bool recursive,const StatusCallback & callback)97 void 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 
Copy(const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,const CopyProgressCallback & progress_callback,const StatusCallback & callback)123 void 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 
Move(const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,const StatusCallback & callback)146 void 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 
DirectoryExists(const FileSystemURL & url,const StatusCallback & callback)169 void SyncableFileSystemOperation::DirectoryExists(
170     const FileSystemURL& url,
171     const StatusCallback& callback) {
172   DCHECK(CalledOnValidThread());
173   impl_->DirectoryExists(url, callback);
174 }
175 
FileExists(const FileSystemURL & url,const StatusCallback & callback)176 void SyncableFileSystemOperation::FileExists(
177     const FileSystemURL& url,
178     const StatusCallback& callback) {
179   DCHECK(CalledOnValidThread());
180   impl_->FileExists(url, callback);
181 }
182 
GetMetadata(const FileSystemURL & url,const GetMetadataCallback & callback)183 void SyncableFileSystemOperation::GetMetadata(
184     const FileSystemURL& url,
185     const GetMetadataCallback& callback) {
186   DCHECK(CalledOnValidThread());
187   impl_->GetMetadata(url, callback);
188 }
189 
ReadDirectory(const FileSystemURL & url,const ReadDirectoryCallback & callback)190 void 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 
Remove(const FileSystemURL & url,bool recursive,const StatusCallback & callback)200 void 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 
Write(const FileSystemURL & url,scoped_ptr<fileapi::FileWriterDelegate> writer_delegate,scoped_ptr<net::URLRequest> blob_request,const WriteCallback & callback)220 void 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 
Truncate(const FileSystemURL & url,int64 length,const StatusCallback & callback)245 void 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 
TouchFile(const FileSystemURL & url,const base::Time & last_access_time,const base::Time & last_modified_time,const StatusCallback & callback)265 void 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 
OpenFile(const FileSystemURL & url,int file_flags,const OpenFileCallback & callback)274 void SyncableFileSystemOperation::OpenFile(
275     const FileSystemURL& url,
276     int file_flags,
277     const OpenFileCallback& callback) {
278   NOTREACHED();
279 }
280 
Cancel(const StatusCallback & cancel_callback)281 void SyncableFileSystemOperation::Cancel(
282     const StatusCallback& cancel_callback) {
283   DCHECK(CalledOnValidThread());
284   impl_->Cancel(cancel_callback);
285 }
286 
CreateSnapshotFile(const FileSystemURL & path,const SnapshotFileCallback & callback)287 void SyncableFileSystemOperation::CreateSnapshotFile(
288     const FileSystemURL& path,
289     const SnapshotFileCallback& callback) {
290   DCHECK(CalledOnValidThread());
291   impl_->CreateSnapshotFile(path, callback);
292 }
293 
CopyInForeignFile(const base::FilePath & src_local_disk_path,const FileSystemURL & dest_url,const StatusCallback & callback)294 void 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 
RemoveFile(const FileSystemURL & url,const StatusCallback & callback)315 void SyncableFileSystemOperation::RemoveFile(
316     const FileSystemURL& url,
317     const StatusCallback& callback) {
318   DCHECK(CalledOnValidThread());
319   impl_->RemoveFile(url, callback);
320 }
321 
RemoveDirectory(const FileSystemURL & url,const StatusCallback & callback)322 void SyncableFileSystemOperation::RemoveDirectory(
323     const FileSystemURL& url,
324     const StatusCallback& callback) {
325   DCHECK(CalledOnValidThread());
326   impl_->RemoveDirectory(url, callback);
327 }
328 
CopyFileLocal(const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,const CopyFileProgressCallback & progress_callback,const StatusCallback & callback)329 void 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 
MoveFileLocal(const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,const StatusCallback & callback)339 void 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 
SyncGetPlatformPath(const FileSystemURL & url,base::FilePath * platform_path)348 base::File::Error SyncableFileSystemOperation::SyncGetPlatformPath(
349     const FileSystemURL& url,
350     base::FilePath* platform_path) {
351   return impl_->SyncGetPlatformPath(url, platform_path);
352 }
353 
SyncableFileSystemOperation(const FileSystemURL & url,fileapi::FileSystemContext * file_system_context,scoped_ptr<fileapi::FileSystemOperationContext> operation_context)354 SyncableFileSystemOperation::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 
DidFinish(base::File::Error status)377 void 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 
DidWrite(const WriteCallback & callback,base::File::Error result,int64 bytes,bool complete)385 void 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 
OnCancelled()400 void 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