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/chromeos/drive/local_file_reader.h"
10 #include "base/bind_helpers.h"
11 #include "base/files/file_path.h"
12 #include "base/location.h"
13 #include "base/platform_file.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/task_runner_util.h"
16 #include "net/base/completion_callback.h"
17 #include "net/base/io_buffer.h"
18 #include "net/base/net_errors.h"
25 // Opens the file at |file_path| and seeks to the |offset| from begin.
26 // Returns the net::Error code. If succeeded, |platform_file| is set to point
28 // This function should run on the blocking pool.
29 int OpenAndSeekOnBlockingPool(const base::FilePath
& file_path
,
31 base::PlatformFile
* platform_file
) {
32 DCHECK(platform_file
);
33 DCHECK_EQ(base::kInvalidPlatformFileValue
, *platform_file
);
35 // First of all, open the file.
36 const int open_flags
= base::PLATFORM_FILE_OPEN
|
37 base::PLATFORM_FILE_READ
|
38 base::PLATFORM_FILE_ASYNC
;
39 base::PlatformFileError error
= base::PLATFORM_FILE_ERROR_FAILED
;
40 base::PlatformFile file
=
41 base::CreatePlatformFile(file_path
, open_flags
, NULL
, &error
);
42 if (file
== base::kInvalidPlatformFileValue
) {
43 DCHECK_NE(base::PLATFORM_FILE_OK
, error
);
44 return net::PlatformFileErrorToNetError(error
);
47 // If succeeded, seek to the |offset| from begin.
48 int64 position
= base::SeekPlatformFile(
49 file
, base::PLATFORM_FILE_FROM_BEGIN
, offset
);
51 // If failed, close the file and return an error.
52 base::ClosePlatformFile(file
);
53 return net::ERR_FAILED
;
56 *platform_file
= file
;
60 // Reads the data from the |platform_file| and copies it to the |buffer| at
61 // most |buffer_length| size. Returns the number of copied bytes if succeeded,
62 // or the net::Error code.
63 // This function should run on the blocking pool.
64 int ReadOnBlockingPool(base::PlatformFile platform_file
,
65 scoped_refptr
<net::IOBuffer
> buffer
,
67 DCHECK_NE(base::kInvalidPlatformFileValue
, platform_file
);
68 int result
= base::ReadPlatformFileCurPosNoBestEffort(
69 platform_file
, buffer
->data(), buffer_length
);
70 return result
< 0 ? net::MapSystemError(errno
) : result
;
73 // Posts a task to close the |platform_file| into |task_runner|.
74 // Or, if |platform_file| is kInvalidPlatformFileValue, does nothing.
75 void PostCloseIfNeeded(base::TaskRunner
* task_runner
,
76 base::PlatformFile platform_file
) {
78 if (platform_file
!= base::kInvalidPlatformFileValue
) {
79 task_runner
->PostTask(
82 base::IgnoreResult(&base::ClosePlatformFile
), platform_file
));
88 class LocalFileReader::ScopedPlatformFile
{
90 explicit ScopedPlatformFile(base::TaskRunner
* task_runner
)
91 : task_runner_(task_runner
),
92 platform_file_(base::kInvalidPlatformFileValue
) {
96 ~ScopedPlatformFile() {
97 PostCloseIfNeeded(task_runner_
.get(), platform_file_
);
100 base::PlatformFile
* ptr() { return &platform_file_
; }
102 base::PlatformFile
release() {
103 base::PlatformFile result
= platform_file_
;
104 platform_file_
= base::kInvalidPlatformFileValue
;
109 scoped_refptr
<base::TaskRunner
> task_runner_
;
110 base::PlatformFile platform_file_
;
112 DISALLOW_COPY_AND_ASSIGN(ScopedPlatformFile
);
115 LocalFileReader::LocalFileReader(
116 base::SequencedTaskRunner
* sequenced_task_runner
)
117 : sequenced_task_runner_(sequenced_task_runner
),
118 platform_file_(base::kInvalidPlatformFileValue
),
119 weak_ptr_factory_(this) {
120 DCHECK(sequenced_task_runner_
.get());
123 LocalFileReader::~LocalFileReader() {
124 PostCloseIfNeeded(sequenced_task_runner_
.get(), platform_file_
);
127 void LocalFileReader::Open(const base::FilePath
& file_path
,
129 const net::CompletionCallback
& callback
) {
130 DCHECK(!callback
.is_null());
131 DCHECK_EQ(base::kInvalidPlatformFileValue
, platform_file_
);
133 ScopedPlatformFile
* platform_file
=
134 new ScopedPlatformFile(sequenced_task_runner_
.get());
135 base::PostTaskAndReplyWithResult(
136 sequenced_task_runner_
.get(),
139 &OpenAndSeekOnBlockingPool
, file_path
, offset
, platform_file
->ptr()),
140 base::Bind(&LocalFileReader::OpenAfterBlockingPoolTask
,
141 weak_ptr_factory_
.GetWeakPtr(),
143 base::Owned(platform_file
)));
146 void LocalFileReader::Read(net::IOBuffer
* in_buffer
,
148 const net::CompletionCallback
& callback
) {
149 DCHECK(!callback
.is_null());
150 DCHECK_NE(base::kInvalidPlatformFileValue
, platform_file_
);
152 scoped_refptr
<net::IOBuffer
> buffer(in_buffer
);
153 base::PostTaskAndReplyWithResult(
154 sequenced_task_runner_
.get(),
156 base::Bind(&ReadOnBlockingPool
, platform_file_
, buffer
, buffer_length
),
160 void LocalFileReader::OpenAfterBlockingPoolTask(
161 const net::CompletionCallback
& callback
,
162 ScopedPlatformFile
* platform_file
,
164 DCHECK(!callback
.is_null());
165 DCHECK(platform_file
);
166 DCHECK_EQ(base::kInvalidPlatformFileValue
, platform_file_
);
168 if (open_result
== net::OK
) {
169 DCHECK_NE(base::kInvalidPlatformFileValue
, *platform_file
->ptr());
170 platform_file_
= platform_file
->release();
173 callback
.Run(open_result
);