OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reade r.h" | |
6 | |
7 #include "base/files/file.h" | |
8 #include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_fi le_util.h" | |
9 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h" | |
10 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_inte rface.h" | |
11 #include "content/public/browser/browser_thread.h" | |
12 #include "net/base/net_errors.h" | |
13 | |
14 using content::BrowserThread; | |
15 | |
16 namespace chromeos { | |
17 namespace file_system_provider { | |
18 namespace { | |
19 | |
20 // Dicards the callback from CloseFile(). | |
21 void EmptyStatusCallback(base::File::Error /* result */) { | |
22 } | |
23 | |
24 // Converts net::CompletionCallback to net::Int64CompletionCallback. | |
25 void Int64ToIntCompletionCallback(net::CompletionCallback callback, | |
26 int64 result) { | |
27 callback.Run(static_cast<int>(result)); | |
28 } | |
29 | |
30 // Opens a file for reading and calls the completion callback. Must be called | |
31 // on UI thread. | |
32 void OpenFileOnUIThread( | |
33 const fileapi::FileSystemURL& url, | |
34 const FileStreamReader::InitializeCompletedCallback& callback) { | |
35 // TODO(mtomasz): Check if the modification time of the file is as expected. | |
36 util::FileSystemURLParser parser(url); | |
37 if (!parser.Parse()) { | |
38 BrowserThread::PostTask( | |
39 BrowserThread::IO, | |
40 FROM_HERE, | |
41 base::Bind(callback, | |
42 base::WeakPtr<ProvidedFileSystemInterface>(), | |
43 base::FilePath(), | |
44 0 /* file_handle */, | |
45 base::File::FILE_ERROR_SECURITY)); | |
46 return; | |
47 } | |
48 | |
49 parser.file_system()->OpenFile( | |
50 parser.file_path(), | |
51 ProvidedFileSystemInterface::OPEN_FILE_MODE_READ, | |
52 false /* create */, | |
53 base::Bind( | |
54 callback, parser.file_system()->GetWeakPtr(), parser.file_path())); | |
55 } | |
56 | |
57 // Forwards results of calling OpenFileOnUIThread back to the IO thread. | |
58 void OnOpenFileCompletedOnUIThread( | |
59 const FileStreamReader::InitializeCompletedCallback& callback, | |
60 base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
61 const base::FilePath& file_path, | |
62 int file_handle, | |
63 base::File::Error result) { | |
64 BrowserThread::PostTask( | |
65 BrowserThread::IO, | |
66 FROM_HERE, | |
67 base::Bind(callback, file_system, file_path, file_handle, result)); | |
68 } | |
69 | |
70 // Closes a file. Ignores result, since it is called from a constructor. | |
71 // Must be called on UI thread. | |
72 void CloseFileOnUIThread(base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
73 int file_handle) { | |
74 if (file_system.get()) | |
75 file_system->CloseFile(file_handle, base::Bind(&EmptyStatusCallback)); | |
76 } | |
77 | |
78 // Requests reading contents of a file. In case of either success or a failure | |
79 // |callback| is executed. It can be called many times, until |has_next| is set | |
80 // to false. This function guarantees that it will succeed only if the file has | |
81 // not been changed while reading. Must be called on UI thread. | |
82 void ReadFileOnUIThread( | |
83 base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
84 int file_handle, | |
85 net::IOBuffer* buffer, | |
86 int64 offset, | |
87 int length, | |
88 const ProvidedFileSystemInterface::ReadChunkReceivedCallback& callback) { | |
89 // If the file system got unmounted, then abort the reading operation. | |
90 if (!file_system.get()) { | |
91 BrowserThread::PostTask( | |
92 BrowserThread::IO, | |
93 FROM_HERE, | |
94 base::Bind( | |
95 callback, 0, false /* has_next */, base::File::FILE_ERROR_ABORT)); | |
96 return; | |
97 } | |
98 | |
99 file_system->ReadFile(file_handle, buffer, offset, length, callback); | |
100 } | |
101 | |
102 // Forward the completion callback to IO thread. | |
103 void OnReadChunkReceivedOnUIThread( | |
104 const ProvidedFileSystemInterface::ReadChunkReceivedCallback& | |
105 chunk_received_callback, | |
106 int chunk_length, | |
107 bool has_next, | |
108 base::File::Error result) { | |
109 BrowserThread::PostTask( | |
110 BrowserThread::IO, | |
111 FROM_HERE, | |
112 base::Bind(chunk_received_callback, chunk_length, has_next, result)); | |
113 } | |
114 | |
115 // TODO(mtomasz): Comment. | |
116 void GetMetadataOnUIThread( | |
117 base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
118 const base::FilePath& file_path, | |
119 const fileapi::AsyncFileUtil::GetFileInfoCallback& callback) { | |
120 // If the file system got unmounted, then abort the get length operation. | |
121 if (!file_system.get()) { | |
122 BrowserThread::PostTask( | |
123 BrowserThread::IO, | |
124 FROM_HERE, | |
125 base::Bind(callback, base::File::FILE_ERROR_ABORT, base::File::Info())); | |
126 return; | |
127 } | |
128 | |
129 file_system->GetMetadata(file_path, callback); | |
130 } | |
131 | |
132 // Forward the completion callback to IO thread. | |
133 void OnGetMetadataReceivedOnUIThread( | |
134 const fileapi::AsyncFileUtil::GetFileInfoCallback& callback, | |
135 base::File::Error result, | |
136 const base::File::Info& file_info) { | |
137 BrowserThread::PostTask( | |
138 BrowserThread::IO, FROM_HERE, base::Bind(callback, result, file_info)); | |
139 } | |
140 | |
141 } // namespace | |
142 | |
143 FileStreamReader::FileStreamReader(fileapi::FileSystemContext* context, | |
144 const fileapi::FileSystemURL& url, | |
145 int64 initial_offset, | |
146 const base::Time& expected_modification_time) | |
147 : context_(context), | |
148 url_(url), | |
149 current_offset_(initial_offset), | |
150 current_length_(0), | |
151 expected_modification_time_(expected_modification_time), | |
152 file_handle_(0), | |
153 weak_ptr_factory_(this) { | |
154 } | |
155 | |
156 FileStreamReader::~FileStreamReader() { | |
157 CloseFileOnUIThread(file_system_, file_handle_); | |
158 } | |
159 | |
160 void FileStreamReader::Initialize( | |
161 const base::Closure& pending_closure, | |
162 const net::Int64CompletionCallback& error_callback) { | |
163 OpenFileOnUIThread( | |
164 url_, | |
165 base::Bind(&OnOpenFileCompletedOnUIThread, | |
166 base::Bind(&FileStreamReader::OnInitializeCompleted, | |
167 weak_ptr_factory_.GetWeakPtr(), | |
168 pending_closure, | |
169 error_callback))); | |
170 } | |
171 | |
172 void FileStreamReader::OnInitializeCompleted( | |
173 const base::Closure& pending_closure, | |
174 const net::Int64CompletionCallback& error_callback, | |
175 base::WeakPtr<ProvidedFileSystemInterface> file_system, | |
176 const base::FilePath& file_path, | |
177 int file_handle, | |
178 base::File::Error result) { | |
179 // In case of an error, return immediately using the |error_callback| of the | |
180 // Read() or GetLength() pending request. | |
181 if (result != base::File::FILE_OK) { | |
182 error_callback.Run(net::FileErrorToNetError(result)); | |
183 return; | |
184 } | |
185 | |
186 file_system_ = file_system; | |
187 file_path_ = file_path; | |
188 file_handle_ = file_handle; | |
189 DCHECK_LT(0, file_handle); | |
190 | |
191 // Run the task waiting for the initialization to be completed. | |
192 pending_closure.Run(); | |
193 } | |
194 | |
195 int FileStreamReader::Read(net::IOBuffer* buffer, | |
196 int buffer_length, | |
197 const net::CompletionCallback& callback) { | |
198 // Lazily initialize with the first call to Read(). | |
199 if (!file_system_.get()) { | |
200 Initialize(base::Bind(&FileStreamReader::ReadAfterInitialized, | |
201 weak_ptr_factory_.GetWeakPtr(), | |
202 buffer, | |
203 buffer_length, | |
204 callback), | |
205 base::Bind(&Int64ToIntCompletionCallback, callback)); | |
206 return net::ERR_IO_PENDING; | |
207 } | |
208 | |
209 ReadAfterInitialized(buffer, buffer_length, callback); | |
210 return net::ERR_IO_PENDING; | |
211 } | |
212 | |
213 int64 FileStreamReader::GetLength( | |
214 const net::Int64CompletionCallback& callback) { | |
215 // Lazily initialize with the first call to Read(). | |
216 if (!file_system_.get()) { | |
217 Initialize(base::Bind(&FileStreamReader::GetLengthAfterInitialized, | |
218 weak_ptr_factory_.GetWeakPtr(), | |
219 callback), | |
220 callback); | |
221 return net::ERR_IO_PENDING; | |
222 } | |
223 | |
224 GetLengthAfterInitialized(callback); | |
225 return net::ERR_IO_PENDING; | |
226 } | |
227 | |
228 void FileStreamReader::ReadAfterInitialized( | |
229 net::IOBuffer* buffer, | |
230 int buffer_length, | |
231 const net::CompletionCallback& callback) { | |
232 // If the file system got unmounted, then abort the reading operation. | |
233 if (!file_system_.get()) { | |
234 callback.Run(net::ERR_ABORTED); | |
235 return; | |
236 } | |
237 | |
238 current_length_ = 0; | |
239 BrowserThread::PostTask( | |
240 BrowserThread::UI, | |
241 FROM_HERE, | |
242 base::Bind(&ReadFileOnUIThread, | |
243 file_system_, | |
244 file_handle_, | |
245 buffer, | |
246 current_offset_, | |
247 buffer_length, | |
248 base::Bind(&OnReadChunkReceivedOnUIThread, | |
249 base::Bind(&FileStreamReader::OnReadChunkReceived, | |
250 weak_ptr_factory_.GetWeakPtr(), | |
251 callback)))); | |
252 } | |
253 | |
254 void FileStreamReader::GetLengthAfterInitialized( | |
255 const net::Int64CompletionCallback& callback) { | |
256 // If the file system got unmounted, then abort the length fetching operation. | |
257 if (!file_system_.get()) { | |
258 callback.Run(net::ERR_ABORTED); | |
259 return; | |
260 } | |
261 | |
262 BrowserThread::PostTask( | |
263 BrowserThread::UI, | |
264 FROM_HERE, | |
265 base::Bind( | |
266 &GetMetadataOnUIThread, | |
267 file_system_, | |
268 file_path_, | |
269 base::Bind( | |
270 &OnGetMetadataReceivedOnUIThread, | |
271 base::Bind(&FileStreamReader::OnGetMetadataForGetLengthReceived, | |
272 weak_ptr_factory_.GetWeakPtr(), | |
273 callback)))); | |
274 } | |
275 | |
276 void FileStreamReader::OnReadChunkReceived( | |
277 const net::CompletionCallback& callback, | |
278 int chunk_length, | |
279 bool has_next, | |
280 base::File::Error result) { | |
281 current_length_ += chunk_length; | |
282 | |
283 | |
hirono
2014/05/16 06:24:48
nit: The line is added unintentionally?
mtomasz
2014/05/16 06:31:11
Done.
| |
284 // If this is the last chunk with a success, then finalize. | |
285 if (!has_next && result == base::File::FILE_OK) { | |
286 current_offset_ += current_length_; | |
287 callback.Run(current_length_); | |
288 return; | |
289 } | |
290 | |
291 // In case of an error, abort. | |
292 if (result != base::File::FILE_OK) { | |
293 DCHECK(!has_next); | |
294 callback.Run(net::FileErrorToNetError(result)); | |
295 } | |
296 | |
297 // More data is about to come, so do not call the callback yet. | |
298 DCHECK(has_next); | |
299 } | |
300 | |
301 void FileStreamReader::OnGetMetadataForGetLengthReceived( | |
302 const net::Int64CompletionCallback& callback, | |
303 base::File::Error result, | |
304 const base::File::Info& file_info) { | |
305 // In case of an error, abort. | |
306 if (result != base::File::FILE_OK) { | |
307 callback.Run(net::FileErrorToNetError(result)); | |
308 return; | |
309 } | |
310 | |
311 DCHECK_EQ(result, base::File::FILE_OK); | |
312 callback.Run(file_info.size); | |
313 } | |
314 | |
315 } // namespace file_system_provider | |
316 } // namespace chromeos | |
OLD | NEW |