OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/drive/local_file_reader.h" | 5 #include "chrome/browser/chromeos/drive/local_file_reader.h" |
6 | 6 |
7 #include <errno.h> | |
8 | |
9 #include "base/bind.h" | 7 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | |
11 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
12 #include "base/location.h" | |
13 #include "base/platform_file.h" | |
14 #include "base/sequenced_task_runner.h" | 9 #include "base/sequenced_task_runner.h" |
15 #include "base/task_runner_util.h" | |
16 #include "net/base/completion_callback.h" | 10 #include "net/base/completion_callback.h" |
17 #include "net/base/io_buffer.h" | 11 #include "net/base/io_buffer.h" |
18 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
19 | 13 |
20 namespace drive { | 14 namespace drive { |
21 namespace util { | 15 namespace util { |
22 | 16 |
23 namespace { | |
24 | |
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 | |
27 // the opened file. | |
28 // This function should run on the blocking pool. | |
29 int OpenAndSeekOnBlockingPool(const base::FilePath& file_path, | |
30 int64 offset, | |
31 base::PlatformFile* platform_file) { | |
32 DCHECK(platform_file); | |
33 DCHECK_EQ(base::kInvalidPlatformFileValue, *platform_file); | |
34 | |
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::FileErrorToNetError(static_cast<base::File::Error>(error)); | |
45 } | |
46 | |
47 // If succeeded, seek to the |offset| from begin. | |
48 int64 position = base::SeekPlatformFile( | |
49 file, base::PLATFORM_FILE_FROM_BEGIN, offset); | |
50 if (position < 0) { | |
51 // If failed, close the file and return an error. | |
52 base::ClosePlatformFile(file); | |
53 return net::ERR_FAILED; | |
54 } | |
55 | |
56 *platform_file = file; | |
57 return net::OK; | |
58 } | |
59 | |
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, | |
66 int buffer_length) { | |
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; | |
71 } | |
72 | |
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) { | |
77 DCHECK(task_runner); | |
78 if (platform_file != base::kInvalidPlatformFileValue) { | |
79 task_runner->PostTask( | |
80 FROM_HERE, | |
81 base::Bind( | |
82 base::IgnoreResult(&base::ClosePlatformFile), platform_file)); | |
83 } | |
84 } | |
85 | |
86 } // namespace | |
87 | |
88 class LocalFileReader::ScopedPlatformFile { | |
89 public: | |
90 explicit ScopedPlatformFile(base::TaskRunner* task_runner) | |
91 : task_runner_(task_runner), | |
92 platform_file_(base::kInvalidPlatformFileValue) { | |
93 DCHECK(task_runner); | |
94 } | |
95 | |
96 ~ScopedPlatformFile() { | |
97 PostCloseIfNeeded(task_runner_.get(), platform_file_); | |
98 } | |
99 | |
100 base::PlatformFile* ptr() { return &platform_file_; } | |
101 | |
102 base::PlatformFile release() { | |
103 base::PlatformFile result = platform_file_; | |
104 platform_file_ = base::kInvalidPlatformFileValue; | |
105 return result; | |
106 } | |
107 | |
108 private: | |
109 scoped_refptr<base::TaskRunner> task_runner_; | |
110 base::PlatformFile platform_file_; | |
111 | |
112 DISALLOW_COPY_AND_ASSIGN(ScopedPlatformFile); | |
113 }; | |
114 | |
115 LocalFileReader::LocalFileReader( | 17 LocalFileReader::LocalFileReader( |
116 base::SequencedTaskRunner* sequenced_task_runner) | 18 base::SequencedTaskRunner* sequenced_task_runner) |
117 : sequenced_task_runner_(sequenced_task_runner), | 19 : file_stream_(NULL, sequenced_task_runner), |
118 platform_file_(base::kInvalidPlatformFileValue), | |
119 weak_ptr_factory_(this) { | 20 weak_ptr_factory_(this) { |
120 DCHECK(sequenced_task_runner_.get()); | |
121 } | 21 } |
122 | 22 |
123 LocalFileReader::~LocalFileReader() { | 23 LocalFileReader::~LocalFileReader() { |
124 PostCloseIfNeeded(sequenced_task_runner_.get(), platform_file_); | |
125 } | 24 } |
126 | 25 |
127 void LocalFileReader::Open(const base::FilePath& file_path, | 26 void LocalFileReader::Open(const base::FilePath& file_path, |
128 int64 offset, | 27 int64 offset, |
129 const net::CompletionCallback& callback) { | 28 const net::CompletionCallback& callback) { |
130 DCHECK(!callback.is_null()); | 29 DCHECK(!callback.is_null()); |
131 DCHECK_EQ(base::kInvalidPlatformFileValue, platform_file_); | 30 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ | |
| 31 base::PLATFORM_FILE_ASYNC; |
132 | 32 |
133 ScopedPlatformFile* platform_file = | 33 int rv = file_stream_.Open(file_path, flags, |
134 new ScopedPlatformFile(sequenced_task_runner_.get()); | 34 Bind(&LocalFileReader::DidOpen, |
135 base::PostTaskAndReplyWithResult( | 35 weak_ptr_factory_.GetWeakPtr(), |
136 sequenced_task_runner_.get(), | 36 callback, offset)); |
137 FROM_HERE, | 37 DCHECK_EQ(rv, net::ERR_IO_PENDING); |
138 base::Bind( | |
139 &OpenAndSeekOnBlockingPool, file_path, offset, platform_file->ptr()), | |
140 base::Bind(&LocalFileReader::OpenAfterBlockingPoolTask, | |
141 weak_ptr_factory_.GetWeakPtr(), | |
142 callback, | |
143 base::Owned(platform_file))); | |
144 } | 38 } |
145 | 39 |
146 void LocalFileReader::Read(net::IOBuffer* in_buffer, | 40 void LocalFileReader::Read(net::IOBuffer* in_buffer, |
147 int buffer_length, | 41 int buffer_length, |
148 const net::CompletionCallback& callback) { | 42 const net::CompletionCallback& callback) { |
149 DCHECK(!callback.is_null()); | 43 DCHECK(!callback.is_null()); |
150 DCHECK_NE(base::kInvalidPlatformFileValue, platform_file_); | 44 DCHECK(file_stream_.IsOpen()); |
151 | 45 int rv = file_stream_.Read(in_buffer, buffer_length, callback); |
152 scoped_refptr<net::IOBuffer> buffer(in_buffer); | 46 DCHECK_EQ(rv, net::ERR_IO_PENDING); |
153 base::PostTaskAndReplyWithResult( | |
154 sequenced_task_runner_.get(), | |
155 FROM_HERE, | |
156 base::Bind(&ReadOnBlockingPool, platform_file_, buffer, buffer_length), | |
157 callback); | |
158 } | 47 } |
159 | 48 |
160 void LocalFileReader::OpenAfterBlockingPoolTask( | 49 void LocalFileReader::DidOpen(const net::CompletionCallback& callback, |
161 const net::CompletionCallback& callback, | 50 int64 offset, |
162 ScopedPlatformFile* platform_file, | 51 int error) { |
163 int open_result) { | 52 if (error != net::OK) |
164 DCHECK(!callback.is_null()); | 53 return callback.Run(error); |
165 DCHECK(platform_file); | |
166 DCHECK_EQ(base::kInvalidPlatformFileValue, platform_file_); | |
167 | 54 |
168 if (open_result == net::OK) { | 55 int rv = file_stream_.Seek(net::FROM_BEGIN, offset, |
169 DCHECK_NE(base::kInvalidPlatformFileValue, *platform_file->ptr()); | 56 Bind(&LocalFileReader::DidSeek, |
170 platform_file_ = platform_file->release(); | 57 weak_ptr_factory_.GetWeakPtr(), |
171 } | 58 callback, offset)); |
| 59 DCHECK_EQ(rv, net::ERR_IO_PENDING); |
| 60 } |
172 | 61 |
173 callback.Run(open_result); | 62 void LocalFileReader::DidSeek(const net::CompletionCallback& callback, |
| 63 int64 offset, |
| 64 int64 error) { |
| 65 callback.Run(error == offset ? net::OK : net::ERR_FAILED); |
174 } | 66 } |
175 | 67 |
176 } // namespace util | 68 } // namespace util |
177 } // namespace drive | 69 } // namespace drive |
OLD | NEW |