1 // Copyright (c) 2012 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 "base/files/file_util_proxy.h"
8 #include "base/bind_helpers.h"
9 #include "base/file_util.h"
10 #include "base/location.h"
11 #include "base/message_loop_proxy.h"
12 #include "base/task_runner.h"
13 #include "base/task_runner_util.h"
19 void CallWithTranslatedParameter(const FileUtilProxy::StatusCallback
& callback
,
21 DCHECK(!callback
.is_null());
22 callback
.Run(value
? PLATFORM_FILE_OK
: PLATFORM_FILE_ERROR_FAILED
);
25 // Helper classes or routines for individual methods.
26 class CreateOrOpenHelper
{
28 CreateOrOpenHelper(TaskRunner
* task_runner
,
29 const FileUtilProxy::CloseTask
& close_task
)
30 : task_runner_(task_runner
),
31 close_task_(close_task
),
32 file_handle_(kInvalidPlatformFileValue
),
34 error_(PLATFORM_FILE_OK
) {}
36 ~CreateOrOpenHelper() {
37 if (file_handle_
!= kInvalidPlatformFileValue
) {
38 task_runner_
->PostTask(
40 base::Bind(base::IgnoreResult(close_task_
), file_handle_
));
44 void RunWork(const FileUtilProxy::CreateOrOpenTask
& task
) {
45 error_
= task
.Run(&file_handle_
, &created_
);
48 void Reply(const FileUtilProxy::CreateOrOpenCallback
& callback
) {
49 DCHECK(!callback
.is_null());
50 callback
.Run(error_
, PassPlatformFile(&file_handle_
), created_
);
54 scoped_refptr
<TaskRunner
> task_runner_
;
55 FileUtilProxy::CloseTask close_task_
;
56 PlatformFile file_handle_
;
58 PlatformFileError error_
;
59 DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper
);
62 class CreateTemporaryHelper
{
64 explicit CreateTemporaryHelper(TaskRunner
* task_runner
)
65 : task_runner_(task_runner
),
66 file_handle_(kInvalidPlatformFileValue
),
67 error_(PLATFORM_FILE_OK
) {}
69 ~CreateTemporaryHelper() {
70 if (file_handle_
!= kInvalidPlatformFileValue
) {
71 FileUtilProxy::Close(task_runner_
, file_handle_
,
72 FileUtilProxy::StatusCallback());
76 void RunWork(int additional_file_flags
) {
77 // TODO(darin): file_util should have a variant of CreateTemporaryFile
78 // that returns a FilePath and a PlatformFile.
79 file_util::CreateTemporaryFile(&file_path_
);
83 PLATFORM_FILE_TEMPORARY
|
84 PLATFORM_FILE_CREATE_ALWAYS
|
85 additional_file_flags
;
87 error_
= PLATFORM_FILE_OK
;
88 file_handle_
= CreatePlatformFile(file_path_
, file_flags
, NULL
, &error_
);
91 void Reply(const FileUtilProxy::CreateTemporaryCallback
& callback
) {
92 DCHECK(!callback
.is_null());
93 callback
.Run(error_
, PassPlatformFile(&file_handle_
), file_path_
);
97 scoped_refptr
<TaskRunner
> task_runner_
;
98 PlatformFile file_handle_
;
100 PlatformFileError error_
;
101 DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper
);
104 class GetFileInfoHelper
{
107 : error_(PLATFORM_FILE_OK
) {}
109 void RunWorkForFilePath(const FilePath
& file_path
) {
110 if (!file_util::PathExists(file_path
)) {
111 error_
= PLATFORM_FILE_ERROR_NOT_FOUND
;
114 if (!file_util::GetFileInfo(file_path
, &file_info_
))
115 error_
= PLATFORM_FILE_ERROR_FAILED
;
118 void RunWorkForPlatformFile(PlatformFile file
) {
119 if (!GetPlatformFileInfo(file
, &file_info_
))
120 error_
= PLATFORM_FILE_ERROR_FAILED
;
123 void Reply(const FileUtilProxy::GetFileInfoCallback
& callback
) {
124 if (!callback
.is_null()) {
125 callback
.Run(error_
, file_info_
);
130 PlatformFileError error_
;
131 PlatformFileInfo file_info_
;
132 DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper
);
137 explicit ReadHelper(int bytes_to_read
)
138 : buffer_(new char[bytes_to_read
]),
139 bytes_to_read_(bytes_to_read
),
142 void RunWork(PlatformFile file
, int64 offset
) {
143 bytes_read_
= ReadPlatformFile(file
, offset
, buffer_
.get(), bytes_to_read_
);
146 void Reply(const FileUtilProxy::ReadCallback
& callback
) {
147 if (!callback
.is_null()) {
148 PlatformFileError error
=
149 (bytes_read_
< 0) ? PLATFORM_FILE_ERROR_FAILED
: PLATFORM_FILE_OK
;
150 callback
.Run(error
, buffer_
.get(), bytes_read_
);
155 scoped_ptr
<char[]> buffer_
;
158 DISALLOW_COPY_AND_ASSIGN(ReadHelper
);
163 WriteHelper(const char* buffer
, int bytes_to_write
)
164 : buffer_(new char[bytes_to_write
]),
165 bytes_to_write_(bytes_to_write
),
167 memcpy(buffer_
.get(), buffer
, bytes_to_write
);
170 void RunWork(PlatformFile file
, int64 offset
) {
171 bytes_written_
= WritePlatformFile(file
, offset
, buffer_
.get(),
175 void Reply(const FileUtilProxy::WriteCallback
& callback
) {
176 if (!callback
.is_null()) {
177 PlatformFileError error
=
178 (bytes_written_
< 0) ? PLATFORM_FILE_ERROR_FAILED
: PLATFORM_FILE_OK
;
179 callback
.Run(error
, bytes_written_
);
184 scoped_ptr
<char[]> buffer_
;
187 DISALLOW_COPY_AND_ASSIGN(WriteHelper
);
191 PlatformFileError
CreateOrOpenAdapter(
192 const FilePath
& file_path
, int file_flags
,
193 PlatformFile
* file_handle
, bool* created
) {
196 if (!file_util::DirectoryExists(file_path
.DirName())) {
197 // If its parent does not exist, should return NOT_FOUND error.
198 return PLATFORM_FILE_ERROR_NOT_FOUND
;
200 PlatformFileError error
= PLATFORM_FILE_OK
;
201 *file_handle
= CreatePlatformFile(file_path
, file_flags
, created
, &error
);
205 PlatformFileError
CloseAdapter(PlatformFile file_handle
) {
206 if (!ClosePlatformFile(file_handle
)) {
207 return PLATFORM_FILE_ERROR_FAILED
;
209 return PLATFORM_FILE_OK
;
212 PlatformFileError
DeleteAdapter(const FilePath
& file_path
, bool recursive
) {
213 if (!file_util::PathExists(file_path
)) {
214 return PLATFORM_FILE_ERROR_NOT_FOUND
;
216 if (!file_util::Delete(file_path
, recursive
)) {
217 if (!recursive
&& !file_util::IsDirectoryEmpty(file_path
)) {
218 return PLATFORM_FILE_ERROR_NOT_EMPTY
;
220 return PLATFORM_FILE_ERROR_FAILED
;
222 return PLATFORM_FILE_OK
;
228 bool FileUtilProxy::CreateOrOpen(
229 TaskRunner
* task_runner
,
230 const FilePath
& file_path
, int file_flags
,
231 const CreateOrOpenCallback
& callback
) {
232 return RelayCreateOrOpen(
234 base::Bind(&CreateOrOpenAdapter
, file_path
, file_flags
),
235 base::Bind(&CloseAdapter
),
240 bool FileUtilProxy::CreateTemporary(
241 TaskRunner
* task_runner
,
242 int additional_file_flags
,
243 const CreateTemporaryCallback
& callback
) {
244 CreateTemporaryHelper
* helper
= new CreateTemporaryHelper(task_runner
);
245 return task_runner
->PostTaskAndReply(
247 Bind(&CreateTemporaryHelper::RunWork
, Unretained(helper
),
248 additional_file_flags
),
249 Bind(&CreateTemporaryHelper::Reply
, Owned(helper
), callback
));
253 bool FileUtilProxy::Close(
254 TaskRunner
* task_runner
,
255 base::PlatformFile file_handle
,
256 const StatusCallback
& callback
) {
259 base::Bind(&CloseAdapter
),
260 file_handle
, callback
);
263 // Retrieves the information about a file. It is invalid to pass NULL for the
265 bool FileUtilProxy::GetFileInfo(
266 TaskRunner
* task_runner
,
267 const FilePath
& file_path
,
268 const GetFileInfoCallback
& callback
) {
269 GetFileInfoHelper
* helper
= new GetFileInfoHelper
;
270 return task_runner
->PostTaskAndReply(
272 Bind(&GetFileInfoHelper::RunWorkForFilePath
,
273 Unretained(helper
), file_path
),
274 Bind(&GetFileInfoHelper::Reply
, Owned(helper
), callback
));
278 bool FileUtilProxy::GetFileInfoFromPlatformFile(
279 TaskRunner
* task_runner
,
281 const GetFileInfoCallback
& callback
) {
282 GetFileInfoHelper
* helper
= new GetFileInfoHelper
;
283 return task_runner
->PostTaskAndReply(
285 Bind(&GetFileInfoHelper::RunWorkForPlatformFile
,
286 Unretained(helper
), file
),
287 Bind(&GetFileInfoHelper::Reply
, Owned(helper
), callback
));
291 bool FileUtilProxy::Delete(TaskRunner
* task_runner
,
292 const FilePath
& file_path
,
294 const StatusCallback
& callback
) {
295 return base::PostTaskAndReplyWithResult(
296 task_runner
, FROM_HERE
,
297 Bind(&DeleteAdapter
, file_path
, recursive
),
302 bool FileUtilProxy::RecursiveDelete(
303 TaskRunner
* task_runner
,
304 const FilePath
& file_path
,
305 const StatusCallback
& callback
) {
306 return base::PostTaskAndReplyWithResult(
307 task_runner
, FROM_HERE
,
308 Bind(&DeleteAdapter
, file_path
, true /* recursive */),
313 bool FileUtilProxy::Read(
314 TaskRunner
* task_runner
,
318 const ReadCallback
& callback
) {
319 if (bytes_to_read
< 0) {
322 ReadHelper
* helper
= new ReadHelper(bytes_to_read
);
323 return task_runner
->PostTaskAndReply(
325 Bind(&ReadHelper::RunWork
, Unretained(helper
), file
, offset
),
326 Bind(&ReadHelper::Reply
, Owned(helper
), callback
));
330 bool FileUtilProxy::Write(
331 TaskRunner
* task_runner
,
336 const WriteCallback
& callback
) {
337 if (bytes_to_write
<= 0 || buffer
== NULL
) {
340 WriteHelper
* helper
= new WriteHelper(buffer
, bytes_to_write
);
341 return task_runner
->PostTaskAndReply(
343 Bind(&WriteHelper::RunWork
, Unretained(helper
), file
, offset
),
344 Bind(&WriteHelper::Reply
, Owned(helper
), callback
));
348 bool FileUtilProxy::Touch(
349 TaskRunner
* task_runner
,
351 const Time
& last_access_time
,
352 const Time
& last_modified_time
,
353 const StatusCallback
& callback
) {
354 return base::PostTaskAndReplyWithResult(
357 Bind(&TouchPlatformFile
, file
,
358 last_access_time
, last_modified_time
),
359 Bind(&CallWithTranslatedParameter
, callback
));
363 bool FileUtilProxy::Touch(
364 TaskRunner
* task_runner
,
365 const FilePath
& file_path
,
366 const Time
& last_access_time
,
367 const Time
& last_modified_time
,
368 const StatusCallback
& callback
) {
369 return base::PostTaskAndReplyWithResult(
372 Bind(&file_util::TouchFile
, file_path
,
373 last_access_time
, last_modified_time
),
374 Bind(&CallWithTranslatedParameter
, callback
));
378 bool FileUtilProxy::Truncate(
379 TaskRunner
* task_runner
,
382 const StatusCallback
& callback
) {
383 return base::PostTaskAndReplyWithResult(
386 Bind(&TruncatePlatformFile
, file
, length
),
387 Bind(&CallWithTranslatedParameter
, callback
));
391 bool FileUtilProxy::Flush(
392 TaskRunner
* task_runner
,
394 const StatusCallback
& callback
) {
395 return base::PostTaskAndReplyWithResult(
398 Bind(&FlushPlatformFile
, file
),
399 Bind(&CallWithTranslatedParameter
, callback
));
403 bool FileUtilProxy::RelayCreateOrOpen(
404 TaskRunner
* task_runner
,
405 const CreateOrOpenTask
& open_task
,
406 const CloseTask
& close_task
,
407 const CreateOrOpenCallback
& callback
) {
408 CreateOrOpenHelper
* helper
= new CreateOrOpenHelper(
409 task_runner
, close_task
);
410 return task_runner
->PostTaskAndReply(
412 Bind(&CreateOrOpenHelper::RunWork
, Unretained(helper
), open_task
),
413 Bind(&CreateOrOpenHelper::Reply
, Owned(helper
), callback
));
417 bool FileUtilProxy::RelayClose(
418 TaskRunner
* task_runner
,
419 const CloseTask
& close_task
,
420 PlatformFile file_handle
,
421 const StatusCallback
& callback
) {
422 return base::PostTaskAndReplyWithResult(
423 task_runner
, FROM_HERE
, Bind(close_task
, file_handle
), callback
);