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