• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 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 "webkit/browser/fileapi/async_file_util_adapter.h"
6 
7 #include <vector>
8 
9 #include "base/bind.h"
10 #include "base/sequenced_task_runner.h"
11 #include "base/task_runner_util.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "webkit/browser/fileapi/file_system_context.h"
14 #include "webkit/browser/fileapi/file_system_file_util.h"
15 #include "webkit/browser/fileapi/file_system_operation_context.h"
16 #include "webkit/browser/fileapi/file_system_url.h"
17 #include "webkit/common/blob/shareable_file_reference.h"
18 #include "webkit/common/fileapi/file_system_util.h"
19 
20 using base::Bind;
21 using base::Callback;
22 using base::Owned;
23 using base::Unretained;
24 using webkit_blob::ShareableFileReference;
25 
26 namespace fileapi {
27 
28 namespace {
29 
30 class EnsureFileExistsHelper {
31  public:
EnsureFileExistsHelper()32   EnsureFileExistsHelper() : error_(base::File::FILE_OK), created_(false) {}
33 
RunWork(FileSystemFileUtil * file_util,FileSystemOperationContext * context,const FileSystemURL & url)34   void RunWork(FileSystemFileUtil* file_util,
35                FileSystemOperationContext* context,
36                const FileSystemURL& url) {
37     error_ = file_util->EnsureFileExists(context, url, &created_);
38   }
39 
Reply(const AsyncFileUtil::EnsureFileExistsCallback & callback)40   void Reply(const AsyncFileUtil::EnsureFileExistsCallback& callback) {
41     callback.Run(error_, created_);
42   }
43 
44  private:
45   base::File::Error error_;
46   bool created_;
47   DISALLOW_COPY_AND_ASSIGN(EnsureFileExistsHelper);
48 };
49 
50 class GetFileInfoHelper {
51  public:
GetFileInfoHelper()52   GetFileInfoHelper()
53       : error_(base::File::FILE_OK) {}
54 
GetFileInfo(FileSystemFileUtil * file_util,FileSystemOperationContext * context,const FileSystemURL & url)55   void GetFileInfo(FileSystemFileUtil* file_util,
56                    FileSystemOperationContext* context,
57                    const FileSystemURL& url) {
58     error_ = file_util->GetFileInfo(context, url, &file_info_, &platform_path_);
59   }
60 
CreateSnapshotFile(FileSystemFileUtil * file_util,FileSystemOperationContext * context,const FileSystemURL & url)61   void CreateSnapshotFile(FileSystemFileUtil* file_util,
62                           FileSystemOperationContext* context,
63                           const FileSystemURL& url) {
64     scoped_file_ = file_util->CreateSnapshotFile(
65         context, url, &error_, &file_info_, &platform_path_);
66   }
67 
ReplyFileInfo(const AsyncFileUtil::GetFileInfoCallback & callback)68   void ReplyFileInfo(const AsyncFileUtil::GetFileInfoCallback& callback) {
69     callback.Run(error_, file_info_);
70   }
71 
ReplySnapshotFile(const AsyncFileUtil::CreateSnapshotFileCallback & callback)72   void ReplySnapshotFile(
73       const AsyncFileUtil::CreateSnapshotFileCallback& callback) {
74     callback.Run(error_, file_info_, platform_path_,
75                   ShareableFileReference::GetOrCreate(scoped_file_.Pass()));
76   }
77 
78  private:
79   base::File::Error error_;
80   base::File::Info file_info_;
81   base::FilePath platform_path_;
82   webkit_blob::ScopedFile scoped_file_;
83   DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper);
84 };
85 
ReadDirectoryHelper(FileSystemFileUtil * file_util,FileSystemOperationContext * context,const FileSystemURL & url,base::SingleThreadTaskRunner * origin_loop,const AsyncFileUtil::ReadDirectoryCallback & callback)86 void ReadDirectoryHelper(FileSystemFileUtil* file_util,
87                          FileSystemOperationContext* context,
88                          const FileSystemURL& url,
89                          base::SingleThreadTaskRunner* origin_loop,
90                          const AsyncFileUtil::ReadDirectoryCallback& callback) {
91   base::File::Info file_info;
92   base::FilePath platform_path;
93   base::File::Error error = file_util->GetFileInfo(
94       context, url, &file_info, &platform_path);
95 
96   if (error == base::File::FILE_OK && !file_info.is_directory)
97     error = base::File::FILE_ERROR_NOT_A_DIRECTORY;
98 
99   std::vector<DirectoryEntry> entries;
100   if (error != base::File::FILE_OK) {
101     origin_loop->PostTask(
102         FROM_HERE, base::Bind(callback, error, entries, false /* has_more */));
103     return;
104   }
105 
106   // Note: Increasing this value may make some tests in LayoutTests meaningless.
107   // (Namely, read-directory-many.html and read-directory-sync-many.html are
108   // assuming that they are reading much more entries than this constant.)
109   const size_t kResultChunkSize = 100;
110 
111   scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum(
112       file_util->CreateFileEnumerator(context, url));
113 
114   base::FilePath current;
115   while (!(current = file_enum->Next()).empty()) {
116     DirectoryEntry entry;
117     entry.is_directory = file_enum->IsDirectory();
118     entry.name = VirtualPath::BaseName(current).value();
119     entry.size = file_enum->Size();
120     entry.last_modified_time = file_enum->LastModifiedTime();
121     entries.push_back(entry);
122 
123     if (entries.size() == kResultChunkSize) {
124       origin_loop->PostTask(
125           FROM_HERE, base::Bind(callback, base::File::FILE_OK, entries,
126                                 true /* has_more */));
127       entries.clear();
128     }
129   }
130   origin_loop->PostTask(
131       FROM_HERE, base::Bind(callback, base::File::FILE_OK, entries,
132                             false /* has_more */));
133 }
134 
RunCreateOrOpenCallback(FileSystemOperationContext * context,const AsyncFileUtil::CreateOrOpenCallback & callback,base::File file)135 void RunCreateOrOpenCallback(
136     FileSystemOperationContext* context,
137     const AsyncFileUtil::CreateOrOpenCallback& callback,
138     base::File file) {
139   callback.Run(file.Pass(), base::Closure());
140 }
141 
142 }  // namespace
143 
AsyncFileUtilAdapter(FileSystemFileUtil * sync_file_util)144 AsyncFileUtilAdapter::AsyncFileUtilAdapter(
145     FileSystemFileUtil* sync_file_util)
146     : sync_file_util_(sync_file_util) {
147   DCHECK(sync_file_util_.get());
148 }
149 
~AsyncFileUtilAdapter()150 AsyncFileUtilAdapter::~AsyncFileUtilAdapter() {
151 }
152 
CreateOrOpen(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,int file_flags,const CreateOrOpenCallback & callback)153 void AsyncFileUtilAdapter::CreateOrOpen(
154     scoped_ptr<FileSystemOperationContext> context,
155     const FileSystemURL& url,
156     int file_flags,
157     const CreateOrOpenCallback& callback) {
158   FileSystemOperationContext* context_ptr = context.release();
159   base::PostTaskAndReplyWithResult(
160       context_ptr->task_runner(),
161       FROM_HERE,
162       Bind(&FileSystemFileUtil::CreateOrOpen, Unretained(sync_file_util_.get()),
163            context_ptr, url, file_flags),
164       Bind(&RunCreateOrOpenCallback, base::Owned(context_ptr), callback));
165 }
166 
EnsureFileExists(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,const EnsureFileExistsCallback & callback)167 void AsyncFileUtilAdapter::EnsureFileExists(
168     scoped_ptr<FileSystemOperationContext> context,
169     const FileSystemURL& url,
170     const EnsureFileExistsCallback& callback) {
171   EnsureFileExistsHelper* helper = new EnsureFileExistsHelper;
172   FileSystemOperationContext* context_ptr = context.release();
173   const bool success = context_ptr->task_runner()->PostTaskAndReply(
174       FROM_HERE,
175       Bind(&EnsureFileExistsHelper::RunWork, Unretained(helper),
176            sync_file_util_.get(), base::Owned(context_ptr), url),
177       Bind(&EnsureFileExistsHelper::Reply, Owned(helper), callback));
178   DCHECK(success);
179 }
180 
CreateDirectory(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,bool exclusive,bool recursive,const StatusCallback & callback)181 void AsyncFileUtilAdapter::CreateDirectory(
182     scoped_ptr<FileSystemOperationContext> context,
183     const FileSystemURL& url,
184     bool exclusive,
185     bool recursive,
186     const StatusCallback& callback) {
187   FileSystemOperationContext* context_ptr = context.release();
188   const bool success = base::PostTaskAndReplyWithResult(
189       context_ptr->task_runner(), FROM_HERE,
190       Bind(&FileSystemFileUtil::CreateDirectory,
191            Unretained(sync_file_util_.get()),
192            base::Owned(context_ptr), url, exclusive, recursive),
193       callback);
194   DCHECK(success);
195 }
196 
GetFileInfo(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,const GetFileInfoCallback & callback)197 void AsyncFileUtilAdapter::GetFileInfo(
198     scoped_ptr<FileSystemOperationContext> context,
199     const FileSystemURL& url,
200     const GetFileInfoCallback& callback) {
201   FileSystemOperationContext* context_ptr = context.release();
202   GetFileInfoHelper* helper = new GetFileInfoHelper;
203   const bool success = context_ptr->task_runner()->PostTaskAndReply(
204       FROM_HERE,
205       Bind(&GetFileInfoHelper::GetFileInfo, Unretained(helper),
206            sync_file_util_.get(), base::Owned(context_ptr), url),
207       Bind(&GetFileInfoHelper::ReplyFileInfo, Owned(helper), callback));
208   DCHECK(success);
209 }
210 
ReadDirectory(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,const ReadDirectoryCallback & callback)211 void AsyncFileUtilAdapter::ReadDirectory(
212     scoped_ptr<FileSystemOperationContext> context,
213     const FileSystemURL& url,
214     const ReadDirectoryCallback& callback) {
215   FileSystemOperationContext* context_ptr = context.release();
216   const bool success = context_ptr->task_runner()->PostTask(
217       FROM_HERE,
218       Bind(&ReadDirectoryHelper,
219            sync_file_util_.get(), base::Owned(context_ptr), url,
220            base::ThreadTaskRunnerHandle::Get(), callback));
221   DCHECK(success);
222 }
223 
Touch(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,const base::Time & last_access_time,const base::Time & last_modified_time,const StatusCallback & callback)224 void AsyncFileUtilAdapter::Touch(
225     scoped_ptr<FileSystemOperationContext> context,
226     const FileSystemURL& url,
227     const base::Time& last_access_time,
228     const base::Time& last_modified_time,
229     const StatusCallback& callback) {
230   FileSystemOperationContext* context_ptr = context.release();
231   const bool success = base::PostTaskAndReplyWithResult(
232       context_ptr->task_runner(), FROM_HERE,
233       Bind(&FileSystemFileUtil::Touch, Unretained(sync_file_util_.get()),
234            base::Owned(context_ptr), url,
235            last_access_time, last_modified_time),
236       callback);
237   DCHECK(success);
238 }
239 
Truncate(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,int64 length,const StatusCallback & callback)240 void AsyncFileUtilAdapter::Truncate(
241     scoped_ptr<FileSystemOperationContext> context,
242     const FileSystemURL& url,
243     int64 length,
244     const StatusCallback& callback) {
245   FileSystemOperationContext* context_ptr = context.release();
246   const bool success = base::PostTaskAndReplyWithResult(
247       context_ptr->task_runner(), FROM_HERE,
248       Bind(&FileSystemFileUtil::Truncate, Unretained(sync_file_util_.get()),
249            base::Owned(context_ptr), url, length),
250       callback);
251   DCHECK(success);
252 }
253 
CopyFileLocal(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,const CopyFileProgressCallback & progress_callback,const StatusCallback & callback)254 void AsyncFileUtilAdapter::CopyFileLocal(
255     scoped_ptr<FileSystemOperationContext> context,
256     const FileSystemURL& src_url,
257     const FileSystemURL& dest_url,
258     CopyOrMoveOption option,
259     const CopyFileProgressCallback& progress_callback,
260     const StatusCallback& callback) {
261   // TODO(hidehiko): Support progress_callback.
262   FileSystemOperationContext* context_ptr = context.release();
263   const bool success = base::PostTaskAndReplyWithResult(
264       context_ptr->task_runner(), FROM_HERE,
265       Bind(&FileSystemFileUtil::CopyOrMoveFile,
266            Unretained(sync_file_util_.get()), base::Owned(context_ptr),
267            src_url, dest_url, option, true /* copy */),
268       callback);
269   DCHECK(success);
270 }
271 
MoveFileLocal(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & src_url,const FileSystemURL & dest_url,CopyOrMoveOption option,const StatusCallback & callback)272 void AsyncFileUtilAdapter::MoveFileLocal(
273     scoped_ptr<FileSystemOperationContext> context,
274     const FileSystemURL& src_url,
275     const FileSystemURL& dest_url,
276     CopyOrMoveOption option,
277     const StatusCallback& callback) {
278   FileSystemOperationContext* context_ptr = context.release();
279   const bool success = base::PostTaskAndReplyWithResult(
280       context_ptr->task_runner(), FROM_HERE,
281       Bind(&FileSystemFileUtil::CopyOrMoveFile,
282            Unretained(sync_file_util_.get()), base::Owned(context_ptr),
283            src_url, dest_url, option, false /* copy */),
284       callback);
285   DCHECK(success);
286 }
287 
CopyInForeignFile(scoped_ptr<FileSystemOperationContext> context,const base::FilePath & src_file_path,const FileSystemURL & dest_url,const StatusCallback & callback)288 void AsyncFileUtilAdapter::CopyInForeignFile(
289       scoped_ptr<FileSystemOperationContext> context,
290       const base::FilePath& src_file_path,
291       const FileSystemURL& dest_url,
292       const StatusCallback& callback) {
293   FileSystemOperationContext* context_ptr = context.release();
294   const bool success = base::PostTaskAndReplyWithResult(
295       context_ptr->task_runner(), FROM_HERE,
296       Bind(&FileSystemFileUtil::CopyInForeignFile,
297            Unretained(sync_file_util_.get()),
298            base::Owned(context_ptr), src_file_path, dest_url),
299       callback);
300   DCHECK(success);
301 }
302 
DeleteFile(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,const StatusCallback & callback)303 void AsyncFileUtilAdapter::DeleteFile(
304     scoped_ptr<FileSystemOperationContext> context,
305     const FileSystemURL& url,
306     const StatusCallback& callback) {
307   FileSystemOperationContext* context_ptr = context.release();
308   const bool success = base::PostTaskAndReplyWithResult(
309       context_ptr->task_runner(), FROM_HERE,
310       Bind(&FileSystemFileUtil::DeleteFile,
311            Unretained(sync_file_util_.get()),
312            base::Owned(context_ptr), url),
313       callback);
314   DCHECK(success);
315 }
316 
DeleteDirectory(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,const StatusCallback & callback)317 void AsyncFileUtilAdapter::DeleteDirectory(
318     scoped_ptr<FileSystemOperationContext> context,
319     const FileSystemURL& url,
320     const StatusCallback& callback) {
321   FileSystemOperationContext* context_ptr = context.release();
322   const bool success = base::PostTaskAndReplyWithResult(
323       context_ptr->task_runner(), FROM_HERE,
324       Bind(&FileSystemFileUtil::DeleteDirectory,
325            Unretained(sync_file_util_.get()),
326            base::Owned(context_ptr), url),
327       callback);
328   DCHECK(success);
329 }
330 
DeleteRecursively(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,const StatusCallback & callback)331 void AsyncFileUtilAdapter::DeleteRecursively(
332     scoped_ptr<FileSystemOperationContext> context,
333     const FileSystemURL& url,
334     const StatusCallback& callback) {
335   callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
336 }
337 
CreateSnapshotFile(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,const CreateSnapshotFileCallback & callback)338 void AsyncFileUtilAdapter::CreateSnapshotFile(
339     scoped_ptr<FileSystemOperationContext> context,
340     const FileSystemURL& url,
341     const CreateSnapshotFileCallback& callback) {
342   FileSystemOperationContext* context_ptr = context.release();
343   GetFileInfoHelper* helper = new GetFileInfoHelper;
344   const bool success = context_ptr->task_runner()->PostTaskAndReply(
345       FROM_HERE,
346       Bind(&GetFileInfoHelper::CreateSnapshotFile, Unretained(helper),
347            sync_file_util_.get(), base::Owned(context_ptr), url),
348       Bind(&GetFileInfoHelper::ReplySnapshotFile, Owned(helper), callback));
349   DCHECK(success);
350 }
351 
352 }  // namespace fileapi
353