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 "webkit/browser/fileapi/file_system_context.h"
13 #include "webkit/browser/fileapi/file_system_file_util.h"
14 #include "webkit/browser/fileapi/file_system_operation_context.h"
15 #include "webkit/browser/fileapi/file_system_url.h"
16 #include "webkit/common/blob/shareable_file_reference.h"
17 #include "webkit/common/fileapi/file_system_util.h"
18
19 using base::Bind;
20 using base::Callback;
21 using base::Owned;
22 using base::PlatformFileError;
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::PLATFORM_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::PlatformFileError error_;
46 bool created_;
47 DISALLOW_COPY_AND_ASSIGN(EnsureFileExistsHelper);
48 };
49
50 class GetFileInfoHelper {
51 public:
GetFileInfoHelper()52 GetFileInfoHelper()
53 : error_(base::PLATFORM_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::PlatformFileError error_;
80 base::PlatformFileInfo file_info_;
81 base::FilePath platform_path_;
82 webkit_blob::ScopedFile scoped_file_;
83 DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper);
84 };
85
86 class ReadDirectoryHelper {
87 public:
ReadDirectoryHelper()88 ReadDirectoryHelper() : error_(base::PLATFORM_FILE_OK) {}
89
RunWork(FileSystemFileUtil * file_util,FileSystemOperationContext * context,const FileSystemURL & url)90 void RunWork(FileSystemFileUtil* file_util,
91 FileSystemOperationContext* context,
92 const FileSystemURL& url) {
93 base::PlatformFileInfo file_info;
94 base::FilePath platform_path;
95 PlatformFileError error = file_util->GetFileInfo(
96 context, url, &file_info, &platform_path);
97 if (error != base::PLATFORM_FILE_OK) {
98 error_ = error;
99 return;
100 }
101 if (!file_info.is_directory) {
102 error_ = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
103 return;
104 }
105
106 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> file_enum(
107 file_util->CreateFileEnumerator(context, url));
108
109 base::FilePath current;
110 while (!(current = file_enum->Next()).empty()) {
111 DirectoryEntry entry;
112 entry.is_directory = file_enum->IsDirectory();
113 entry.name = VirtualPath::BaseName(current).value();
114 entry.size = file_enum->Size();
115 entry.last_modified_time = file_enum->LastModifiedTime();
116 entries_.push_back(entry);
117 }
118 error_ = base::PLATFORM_FILE_OK;
119 }
120
Reply(const AsyncFileUtil::ReadDirectoryCallback & callback)121 void Reply(const AsyncFileUtil::ReadDirectoryCallback& callback) {
122 callback.Run(error_, entries_, false /* has_more */);
123 }
124
125 private:
126 base::PlatformFileError error_;
127 std::vector<DirectoryEntry> entries_;
128 DISALLOW_COPY_AND_ASSIGN(ReadDirectoryHelper);
129 };
130
RunCreateOrOpenCallback(const AsyncFileUtil::CreateOrOpenCallback & callback,base::PlatformFileError result,base::PassPlatformFile file,bool created)131 void RunCreateOrOpenCallback(
132 const AsyncFileUtil::CreateOrOpenCallback& callback,
133 base::PlatformFileError result,
134 base::PassPlatformFile file,
135 bool created) {
136 callback.Run(result, file, base::Closure());
137 }
138
139 } // namespace
140
AsyncFileUtilAdapter(FileSystemFileUtil * sync_file_util)141 AsyncFileUtilAdapter::AsyncFileUtilAdapter(
142 FileSystemFileUtil* sync_file_util)
143 : sync_file_util_(sync_file_util) {
144 DCHECK(sync_file_util_.get());
145 }
146
~AsyncFileUtilAdapter()147 AsyncFileUtilAdapter::~AsyncFileUtilAdapter() {
148 }
149
CreateOrOpen(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,int file_flags,const CreateOrOpenCallback & callback)150 void AsyncFileUtilAdapter::CreateOrOpen(
151 scoped_ptr<FileSystemOperationContext> context,
152 const FileSystemURL& url,
153 int file_flags,
154 const CreateOrOpenCallback& callback) {
155 FileSystemOperationContext* context_ptr = context.release();
156 const bool success = base::FileUtilProxy::RelayCreateOrOpen(
157 context_ptr->task_runner(),
158 Bind(&FileSystemFileUtil::CreateOrOpen, Unretained(sync_file_util_.get()),
159 context_ptr, url, file_flags),
160 Bind(&FileSystemFileUtil::Close, Unretained(sync_file_util_.get()),
161 base::Owned(context_ptr)),
162 Bind(&RunCreateOrOpenCallback, callback));
163 DCHECK(success);
164 }
165
EnsureFileExists(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,const EnsureFileExistsCallback & callback)166 void AsyncFileUtilAdapter::EnsureFileExists(
167 scoped_ptr<FileSystemOperationContext> context,
168 const FileSystemURL& url,
169 const EnsureFileExistsCallback& callback) {
170 EnsureFileExistsHelper* helper = new EnsureFileExistsHelper;
171 FileSystemOperationContext* context_ptr = context.release();
172 const bool success = context_ptr->task_runner()->PostTaskAndReply(
173 FROM_HERE,
174 Bind(&EnsureFileExistsHelper::RunWork, Unretained(helper),
175 sync_file_util_.get(), base::Owned(context_ptr), url),
176 Bind(&EnsureFileExistsHelper::Reply, Owned(helper), callback));
177 DCHECK(success);
178 }
179
CreateDirectory(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,bool exclusive,bool recursive,const StatusCallback & callback)180 void AsyncFileUtilAdapter::CreateDirectory(
181 scoped_ptr<FileSystemOperationContext> context,
182 const FileSystemURL& url,
183 bool exclusive,
184 bool recursive,
185 const StatusCallback& callback) {
186 FileSystemOperationContext* context_ptr = context.release();
187 const bool success = base::PostTaskAndReplyWithResult(
188 context_ptr->task_runner(), FROM_HERE,
189 Bind(&FileSystemFileUtil::CreateDirectory,
190 Unretained(sync_file_util_.get()),
191 base::Owned(context_ptr), url, exclusive, recursive),
192 callback);
193 DCHECK(success);
194 }
195
GetFileInfo(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,const GetFileInfoCallback & callback)196 void AsyncFileUtilAdapter::GetFileInfo(
197 scoped_ptr<FileSystemOperationContext> context,
198 const FileSystemURL& url,
199 const GetFileInfoCallback& callback) {
200 FileSystemOperationContext* context_ptr = context.release();
201 GetFileInfoHelper* helper = new GetFileInfoHelper;
202 const bool success = context_ptr->task_runner()->PostTaskAndReply(
203 FROM_HERE,
204 Bind(&GetFileInfoHelper::GetFileInfo, Unretained(helper),
205 sync_file_util_.get(), base::Owned(context_ptr), url),
206 Bind(&GetFileInfoHelper::ReplyFileInfo, Owned(helper), callback));
207 DCHECK(success);
208 }
209
ReadDirectory(scoped_ptr<FileSystemOperationContext> context,const FileSystemURL & url,const ReadDirectoryCallback & callback)210 void AsyncFileUtilAdapter::ReadDirectory(
211 scoped_ptr<FileSystemOperationContext> context,
212 const FileSystemURL& url,
213 const ReadDirectoryCallback& callback) {
214 FileSystemOperationContext* context_ptr = context.release();
215 ReadDirectoryHelper* helper = new ReadDirectoryHelper;
216 const bool success = context_ptr->task_runner()->PostTaskAndReply(
217 FROM_HERE,
218 Bind(&ReadDirectoryHelper::RunWork, Unretained(helper),
219 sync_file_util_.get(), base::Owned(context_ptr), url),
220 Bind(&ReadDirectoryHelper::Reply, Owned(helper), 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::PLATFORM_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