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.
5 #include "chrome/browser/sync_file_system/local/syncable_file_system_operation.h"
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"
20 using fileapi::FileSystemURL
;
22 namespace sync_file_system
{
26 void WriteCallbackAdapter(
27 const SyncableFileSystemOperation::WriteCallback
& callback
,
28 base::PlatformFileError status
) {
29 callback
.Run(status
, 0, true);
34 class SyncableFileSystemOperation::QueueableTask
35 : public SyncableFileOperationRunner::Task
{
37 QueueableTask(base::WeakPtr
<SyncableFileSystemOperation
> operation
,
38 const base::Closure
& task
)
39 : operation_(operation
),
41 target_paths_(operation
->target_paths_
) {}
43 virtual ~QueueableTask() {
47 virtual void Run() OVERRIDE
{
50 DCHECK(!task_
.is_null());
55 virtual void Cancel() OVERRIDE
{
56 DCHECK(!task_
.is_null());
58 operation_
->OnCancelled();
63 virtual const std::vector
<FileSystemURL
>& target_paths() const OVERRIDE
{
68 base::WeakPtr
<SyncableFileSystemOperation
> operation_
;
70 std::vector
<FileSystemURL
> target_paths_
;
71 DISALLOW_COPY_AND_ASSIGN(QueueableTask
);
74 SyncableFileSystemOperation::~SyncableFileSystemOperation() {}
76 void SyncableFileSystemOperation::CreateFile(
77 const FileSystemURL
& url
,
79 const StatusCallback
& callback
) {
80 DCHECK(CalledOnValidThread());
81 if (!operation_runner_
.get()) {
82 callback
.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND
);
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()),
93 base::Bind(&self::DidFinish
, weak_factory_
.GetWeakPtr()))));
94 operation_runner_
->PostOperationTask(task
.Pass());
97 void SyncableFileSystemOperation::CreateDirectory(
98 const FileSystemURL
& url
,
101 const StatusCallback
& callback
) {
102 DCHECK(CalledOnValidThread());
103 if (!operation_runner_
.get()) {
104 callback
.Run(base::PLATFORM_FILE_ERROR_NOT_FOUND
);
107 if (!is_directory_operation_enabled_
) {
108 callback
.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION
);
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());
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::PLATFORM_FILE_ERROR_NOT_FOUND
);
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());
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::PLATFORM_FILE_ERROR_NOT_FOUND
);
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());
169 void SyncableFileSystemOperation::DirectoryExists(
170 const FileSystemURL
& url
,
171 const StatusCallback
& callback
) {
172 DCHECK(CalledOnValidThread());
173 impl_
->DirectoryExists(url
, callback
);
176 void SyncableFileSystemOperation::FileExists(
177 const FileSystemURL
& url
,
178 const StatusCallback
& callback
) {
179 DCHECK(CalledOnValidThread());
180 impl_
->FileExists(url
, callback
);
183 void SyncableFileSystemOperation::GetMetadata(
184 const FileSystemURL
& url
,
185 const GetMetadataCallback
& callback
) {
186 DCHECK(CalledOnValidThread());
187 impl_
->GetMetadata(url
, 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
);
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::PLATFORM_FILE_ERROR_NOT_FOUND
);
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()),
216 base::Bind(&self::DidFinish
, weak_factory_
.GetWeakPtr()))));
217 operation_runner_
->PostOperationTask(task
.Pass());
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::PLATFORM_FILE_ERROR_NOT_FOUND
, 0, true);
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()),
238 base::Passed(&writer_delegate
),
239 base::Passed(&blob_request
),
240 base::Bind(&self::DidWrite
, weak_factory_
.GetWeakPtr(),
242 operation_runner_
->PostOperationTask(task
.Pass());
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::PLATFORM_FILE_ERROR_NOT_FOUND
);
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()),
261 base::Bind(&self::DidFinish
, weak_factory_
.GetWeakPtr()))));
262 operation_runner_
->PostOperationTask(task
.Pass());
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
);
274 void SyncableFileSystemOperation::OpenFile(
275 const FileSystemURL
& url
,
277 const OpenFileCallback
& callback
) {
281 void SyncableFileSystemOperation::Cancel(
282 const StatusCallback
& cancel_callback
) {
283 DCHECK(CalledOnValidThread());
284 impl_
->Cancel(cancel_callback
);
287 void SyncableFileSystemOperation::CreateSnapshotFile(
288 const FileSystemURL
& path
,
289 const SnapshotFileCallback
& callback
) {
290 DCHECK(CalledOnValidThread());
291 impl_
->CreateSnapshotFile(path
, 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::PLATFORM_FILE_ERROR_NOT_FOUND
);
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());
315 void SyncableFileSystemOperation::RemoveFile(
316 const FileSystemURL
& url
,
317 const StatusCallback
& callback
) {
318 DCHECK(CalledOnValidThread());
319 impl_
->RemoveFile(url
, callback
);
322 void SyncableFileSystemOperation::RemoveDirectory(
323 const FileSystemURL
& url
,
324 const StatusCallback
& callback
) {
325 DCHECK(CalledOnValidThread());
326 impl_
->RemoveDirectory(url
, 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
);
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
);
348 base::PlatformFileError
SyncableFileSystemOperation::SyncGetPlatformPath(
349 const FileSystemURL
& url
,
350 base::FilePath
* platform_path
) {
351 return impl_
->SyncGetPlatformPath(url
, platform_path
);
354 SyncableFileSystemOperation::SyncableFileSystemOperation(
355 const FileSystemURL
& url
,
356 fileapi::FileSystemContext
* file_system_context
,
357 scoped_ptr
<fileapi::FileSystemOperationContext
> operation_context
)
359 weak_factory_(this) {
360 DCHECK(file_system_context
);
361 SyncFileSystemBackend
* backend
=
362 SyncFileSystemBackend::GetBackend(file_system_context
);
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.
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(
377 void SyncableFileSystemOperation::DidFinish(base::PlatformFileError 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
);
385 void SyncableFileSystemOperation::DidWrite(
386 const WriteCallback
& callback
,
387 base::PlatformFileError result
,
390 DCHECK(CalledOnValidThread());
392 callback
.Run(result
, bytes
, complete
);
395 if (operation_runner_
.get())
396 operation_runner_
->OnOperationCompleted(target_paths_
);
397 callback
.Run(result
, bytes
, complete
);
400 void SyncableFileSystemOperation::OnCancelled() {
401 DCHECK(!completion_callback_
.is_null());
402 completion_callback_
.Run(base::PLATFORM_FILE_ERROR_ABORT
);
405 } // namespace sync_file_system