1 // Copyright 2014 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_proxy.h"
8 #include "base/bind_helpers.h"
9 #include "base/files/file.h"
10 #include "base/files/file_util.h"
11 #include "base/location.h"
12 #include "base/task_runner.h"
13 #include "base/task_runner_util.h"
17 void FileDeleter(base::File file
) {
26 FileHelper(FileProxy
* proxy
, File file
)
28 error_(File::FILE_ERROR_FAILED
),
29 task_runner_(proxy
->task_runner()),
30 proxy_(AsWeakPtr(proxy
)) {
35 proxy_
->SetFile(file_
.Pass());
36 else if (file_
.IsValid())
37 task_runner_
->PostTask(FROM_HERE
, Bind(&FileDeleter
, Passed(&file_
)));
45 scoped_refptr
<TaskRunner
> task_runner_
;
46 WeakPtr
<FileProxy
> proxy_
;
47 DISALLOW_COPY_AND_ASSIGN(FileHelper
);
52 class GenericFileHelper
: public FileHelper
{
54 GenericFileHelper(FileProxy
* proxy
, File file
)
55 : FileHelper(proxy
, file
.Pass()) {
60 error_
= File::FILE_OK
;
63 void SetTimes(Time last_access_time
, Time last_modified_time
) {
64 bool rv
= file_
.SetTimes(last_access_time
, last_modified_time
);
65 error_
= rv
? File::FILE_OK
: File::FILE_ERROR_FAILED
;
68 void SetLength(int64 length
) {
69 if (file_
.SetLength(length
))
70 error_
= File::FILE_OK
;
75 error_
= File::FILE_OK
;
78 void Reply(const FileProxy::StatusCallback
& callback
) {
80 if (!callback
.is_null())
85 DISALLOW_COPY_AND_ASSIGN(GenericFileHelper
);
88 class CreateOrOpenHelper
: public FileHelper
{
90 CreateOrOpenHelper(FileProxy
* proxy
, File file
)
91 : FileHelper(proxy
, file
.Pass()) {
94 void RunWork(const FilePath
& file_path
, int file_flags
) {
95 file_
.Initialize(file_path
, file_flags
);
96 error_
= file_
.IsValid() ? File::FILE_OK
: file_
.error_details();
99 void Reply(const FileProxy::StatusCallback
& callback
) {
100 DCHECK(!callback
.is_null());
102 callback
.Run(error_
);
106 DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper
);
109 class CreateTemporaryHelper
: public FileHelper
{
111 CreateTemporaryHelper(FileProxy
* proxy
, File file
)
112 : FileHelper(proxy
, file
.Pass()) {
115 void RunWork(uint32 additional_file_flags
) {
116 // TODO(darin): file_util should have a variant of CreateTemporaryFile
117 // that returns a FilePath and a File.
118 if (!CreateTemporaryFile(&file_path_
)) {
119 // TODO(davidben): base::CreateTemporaryFile should preserve the error
121 error_
= File::FILE_ERROR_FAILED
;
125 uint32 file_flags
= File::FLAG_WRITE
|
126 File::FLAG_TEMPORARY
|
127 File::FLAG_CREATE_ALWAYS
|
128 additional_file_flags
;
130 file_
.Initialize(file_path_
, file_flags
);
131 if (file_
.IsValid()) {
132 error_
= File::FILE_OK
;
134 error_
= file_
.error_details();
135 DeleteFile(file_path_
, false);
140 void Reply(const FileProxy::CreateTemporaryCallback
& callback
) {
141 DCHECK(!callback
.is_null());
143 callback
.Run(error_
, file_path_
);
148 DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper
);
151 class GetInfoHelper
: public FileHelper
{
153 GetInfoHelper(FileProxy
* proxy
, File file
)
154 : FileHelper(proxy
, file
.Pass()) {
158 if (file_
.GetInfo(&file_info_
))
159 error_
= File::FILE_OK
;
162 void Reply(const FileProxy::GetFileInfoCallback
& callback
) {
164 DCHECK(!callback
.is_null());
165 callback
.Run(error_
, file_info_
);
169 File::Info file_info_
;
170 DISALLOW_COPY_AND_ASSIGN(GetInfoHelper
);
173 class ReadHelper
: public FileHelper
{
175 ReadHelper(FileProxy
* proxy
, File file
, int bytes_to_read
)
176 : FileHelper(proxy
, file
.Pass()),
177 buffer_(new char[bytes_to_read
]),
178 bytes_to_read_(bytes_to_read
),
182 void RunWork(int64 offset
) {
183 bytes_read_
= file_
.Read(offset
, buffer_
.get(), bytes_to_read_
);
184 error_
= (bytes_read_
< 0) ? File::FILE_ERROR_FAILED
: File::FILE_OK
;
187 void Reply(const FileProxy::ReadCallback
& callback
) {
189 DCHECK(!callback
.is_null());
190 callback
.Run(error_
, buffer_
.get(), bytes_read_
);
194 scoped_ptr
<char[]> buffer_
;
197 DISALLOW_COPY_AND_ASSIGN(ReadHelper
);
200 class WriteHelper
: public FileHelper
{
202 WriteHelper(FileProxy
* proxy
,
204 const char* buffer
, int bytes_to_write
)
205 : FileHelper(proxy
, file
.Pass()),
206 buffer_(new char[bytes_to_write
]),
207 bytes_to_write_(bytes_to_write
),
209 memcpy(buffer_
.get(), buffer
, bytes_to_write
);
212 void RunWork(int64 offset
) {
213 bytes_written_
= file_
.Write(offset
, buffer_
.get(), bytes_to_write_
);
214 error_
= (bytes_written_
< 0) ? File::FILE_ERROR_FAILED
: File::FILE_OK
;
217 void Reply(const FileProxy::WriteCallback
& callback
) {
219 if (!callback
.is_null())
220 callback
.Run(error_
, bytes_written_
);
224 scoped_ptr
<char[]> buffer_
;
227 DISALLOW_COPY_AND_ASSIGN(WriteHelper
);
232 FileProxy::FileProxy(TaskRunner
* task_runner
) : task_runner_(task_runner
) {
235 FileProxy::~FileProxy() {
237 task_runner_
->PostTask(FROM_HERE
, Bind(&FileDeleter
, Passed(&file_
)));
240 bool FileProxy::CreateOrOpen(const FilePath
& file_path
,
242 const StatusCallback
& callback
) {
243 DCHECK(!file_
.IsValid());
244 CreateOrOpenHelper
* helper
= new CreateOrOpenHelper(this, File());
245 return task_runner_
->PostTaskAndReply(
247 Bind(&CreateOrOpenHelper::RunWork
, Unretained(helper
), file_path
,
249 Bind(&CreateOrOpenHelper::Reply
, Owned(helper
), callback
));
252 bool FileProxy::CreateTemporary(uint32 additional_file_flags
,
253 const CreateTemporaryCallback
& callback
) {
254 DCHECK(!file_
.IsValid());
255 CreateTemporaryHelper
* helper
= new CreateTemporaryHelper(this, File());
256 return task_runner_
->PostTaskAndReply(
258 Bind(&CreateTemporaryHelper::RunWork
, Unretained(helper
),
259 additional_file_flags
),
260 Bind(&CreateTemporaryHelper::Reply
, Owned(helper
), callback
));
263 bool FileProxy::IsValid() const {
264 return file_
.IsValid();
267 void FileProxy::SetFile(File file
) {
268 DCHECK(!file_
.IsValid());
272 File
FileProxy::TakeFile() {
276 PlatformFile
FileProxy::GetPlatformFile() const {
277 return file_
.GetPlatformFile();
280 bool FileProxy::Close(const StatusCallback
& callback
) {
281 DCHECK(file_
.IsValid());
282 GenericFileHelper
* helper
= new GenericFileHelper(this, file_
.Pass());
283 return task_runner_
->PostTaskAndReply(
285 Bind(&GenericFileHelper::Close
, Unretained(helper
)),
286 Bind(&GenericFileHelper::Reply
, Owned(helper
), callback
));
289 bool FileProxy::GetInfo(const GetFileInfoCallback
& callback
) {
290 DCHECK(file_
.IsValid());
291 GetInfoHelper
* helper
= new GetInfoHelper(this, file_
.Pass());
292 return task_runner_
->PostTaskAndReply(
294 Bind(&GetInfoHelper::RunWork
, Unretained(helper
)),
295 Bind(&GetInfoHelper::Reply
, Owned(helper
), callback
));
298 bool FileProxy::Read(int64 offset
,
300 const ReadCallback
& callback
) {
301 DCHECK(file_
.IsValid());
302 if (bytes_to_read
< 0)
305 ReadHelper
* helper
= new ReadHelper(this, file_
.Pass(), bytes_to_read
);
306 return task_runner_
->PostTaskAndReply(
308 Bind(&ReadHelper::RunWork
, Unretained(helper
), offset
),
309 Bind(&ReadHelper::Reply
, Owned(helper
), callback
));
312 bool FileProxy::Write(int64 offset
,
315 const WriteCallback
& callback
) {
316 DCHECK(file_
.IsValid());
317 if (bytes_to_write
<= 0 || buffer
== NULL
)
320 WriteHelper
* helper
=
321 new WriteHelper(this, file_
.Pass(), buffer
, bytes_to_write
);
322 return task_runner_
->PostTaskAndReply(
324 Bind(&WriteHelper::RunWork
, Unretained(helper
), offset
),
325 Bind(&WriteHelper::Reply
, Owned(helper
), callback
));
328 bool FileProxy::SetTimes(Time last_access_time
,
329 Time last_modified_time
,
330 const StatusCallback
& callback
) {
331 DCHECK(file_
.IsValid());
332 GenericFileHelper
* helper
= new GenericFileHelper(this, file_
.Pass());
333 return task_runner_
->PostTaskAndReply(
335 Bind(&GenericFileHelper::SetTimes
, Unretained(helper
), last_access_time
,
337 Bind(&GenericFileHelper::Reply
, Owned(helper
), callback
));
340 bool FileProxy::SetLength(int64 length
, const StatusCallback
& callback
) {
341 DCHECK(file_
.IsValid());
342 GenericFileHelper
* helper
= new GenericFileHelper(this, file_
.Pass());
343 return task_runner_
->PostTaskAndReply(
345 Bind(&GenericFileHelper::SetLength
, Unretained(helper
), length
),
346 Bind(&GenericFileHelper::Reply
, Owned(helper
), callback
));
349 bool FileProxy::Flush(const StatusCallback
& callback
) {
350 DCHECK(file_
.IsValid());
351 GenericFileHelper
* helper
= new GenericFileHelper(this, file_
.Pass());
352 return task_runner_
->PostTaskAndReply(
354 Bind(&GenericFileHelper::Flush
, Unretained(helper
)),
355 Bind(&GenericFileHelper::Reply
, Owned(helper
), callback
));