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 "chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.h"
7 #include "base/debug/trace_event.h"
8 #include "base/files/file.h"
9 #include "base/memory/ref_counted.h"
10 #include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.h"
11 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
12 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
17 using content::BrowserThread;
20 namespace file_system_provider {
23 // Dicards the callback from CloseFile().
24 void EmptyStatusCallback(base::File::Error /* result */) {
27 // Converts net::CompletionCallback to net::Int64CompletionCallback.
28 void Int64ToIntCompletionCallback(net::CompletionCallback callback,
30 callback.Run(static_cast<int>(result));
33 // Opens a file for reading and calls the completion callback. Must be called
35 void OpenFileOnUIThread(
36 const fileapi::FileSystemURL& url,
37 const FileStreamReader::OpenFileCompletedCallback& callback) {
38 DCHECK_CURRENTLY_ON(BrowserThread::UI);
40 util::FileSystemURLParser parser(url);
41 if (!parser.Parse()) {
42 callback.Run(base::WeakPtr<ProvidedFileSystemInterface>(),
45 base::File::FILE_ERROR_SECURITY);
49 parser.file_system()->OpenFile(
51 ProvidedFileSystemInterface::OPEN_FILE_MODE_READ,
53 callback, parser.file_system()->GetWeakPtr(), parser.file_path()));
56 // Forwards results of calling OpenFileOnUIThread back to the IO thread.
57 void OnOpenFileCompletedOnUIThread(
58 const FileStreamReader::OpenFileCompletedCallback& callback,
59 base::WeakPtr<ProvidedFileSystemInterface> file_system,
60 const base::FilePath& file_path,
62 base::File::Error result) {
63 DCHECK_CURRENTLY_ON(BrowserThread::UI);
64 BrowserThread::PostTask(
67 base::Bind(callback, file_system, file_path, file_handle, result));
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,
74 DCHECK_CURRENTLY_ON(BrowserThread::UI);
75 if (file_system.get())
76 file_system->CloseFile(file_handle, base::Bind(&EmptyStatusCallback));
79 // Requests reading contents of a file. In case of either success or a failure
80 // |callback| is executed. It can be called many times, until |has_more| is set
81 // to false. This function guarantees that it will succeed only if the file has
82 // not been changed while reading. Must be called on UI thread.
83 void ReadFileOnUIThread(
84 base::WeakPtr<ProvidedFileSystemInterface> file_system,
86 scoped_refptr<net::IOBuffer> buffer,
89 const ProvidedFileSystemInterface::ReadChunkReceivedCallback& callback) {
90 DCHECK_CURRENTLY_ON(BrowserThread::UI);
92 // If the file system got unmounted, then abort the reading operation.
93 if (!file_system.get()) {
94 callback.Run(0, false /* has_more */, base::File::FILE_ERROR_ABORT);
98 file_system->ReadFile(file_handle, buffer, offset, length, callback);
101 // Forward the completion callback to IO thread.
102 void OnReadChunkReceivedOnUIThread(
103 const ProvidedFileSystemInterface::ReadChunkReceivedCallback&
104 chunk_received_callback,
107 base::File::Error result) {
108 DCHECK_CURRENTLY_ON(BrowserThread::UI);
109 BrowserThread::PostTask(
112 base::Bind(chunk_received_callback, chunk_length, has_more, result));
115 // Requests metadata of a file. In case of either succes or a failure,
116 // |callback is executed. Must be called on UI thread.
117 void GetMetadataOnUIThread(
118 base::WeakPtr<ProvidedFileSystemInterface> file_system,
119 const base::FilePath& file_path,
120 const ProvidedFileSystemInterface::GetMetadataCallback& callback) {
121 DCHECK_CURRENTLY_ON(BrowserThread::UI);
123 // If the file system got unmounted, then abort the get length operation.
124 if (!file_system.get()) {
125 callback.Run(EntryMetadata(), base::File::FILE_ERROR_ABORT);
129 file_system->GetMetadata(file_path, callback);
132 // Forward the completion callback to IO thread.
133 void OnGetMetadataReceivedOnUIThread(
134 const ProvidedFileSystemInterface::GetMetadataCallback& callback,
135 const EntryMetadata& metadata,
136 base::File::Error result) {
137 DCHECK_CURRENTLY_ON(BrowserThread::UI);
138 BrowserThread::PostTask(
139 BrowserThread::IO, FROM_HERE, base::Bind(callback, metadata, result));
144 FileStreamReader::FileStreamReader(fileapi::FileSystemContext* context,
145 const fileapi::FileSystemURL& url,
146 int64 initial_offset,
147 const base::Time& expected_modification_time)
149 current_offset_(initial_offset),
151 expected_modification_time_(expected_modification_time),
152 state_(NOT_INITIALIZED),
154 weak_ptr_factory_(this) {
157 FileStreamReader::~FileStreamReader() {
158 BrowserThread::PostTask(
161 base::Bind(&CloseFileOnUIThread, file_system_, file_handle_));
164 void FileStreamReader::Initialize(
165 const base::Closure& pending_closure,
166 const net::Int64CompletionCallback& error_callback) {
167 DCHECK_EQ(NOT_INITIALIZED, state_);
168 state_ = INITIALIZING;
170 BrowserThread::PostTask(
173 base::Bind(&OpenFileOnUIThread,
175 base::Bind(&OnOpenFileCompletedOnUIThread,
176 base::Bind(&FileStreamReader::OnOpenFileCompleted,
177 weak_ptr_factory_.GetWeakPtr(),
182 void FileStreamReader::OnOpenFileCompleted(
183 const base::Closure& pending_closure,
184 const net::Int64CompletionCallback& error_callback,
185 base::WeakPtr<ProvidedFileSystemInterface> file_system,
186 const base::FilePath& file_path,
188 base::File::Error result) {
189 DCHECK_CURRENTLY_ON(BrowserThread::IO);
190 DCHECK_EQ(INITIALIZING, state_);
192 // In case of an error, return immediately using the |error_callback| of the
193 // Read() or GetLength() pending request.
194 if (result != base::File::FILE_OK) {
196 error_callback.Run(net::FileErrorToNetError(result));
200 file_system_ = file_system;
201 file_path_ = file_path;
202 file_handle_ = file_handle;
203 DCHECK_LT(0, file_handle);
205 // Verify the last modification time.
206 BrowserThread::PostTask(
209 base::Bind(&GetMetadataOnUIThread,
212 base::Bind(&OnGetMetadataReceivedOnUIThread,
213 base::Bind(&FileStreamReader::OnInitializeCompleted,
214 weak_ptr_factory_.GetWeakPtr(),
219 void FileStreamReader::OnInitializeCompleted(
220 const base::Closure& pending_closure,
221 const net::Int64CompletionCallback& error_callback,
222 const EntryMetadata& metadata,
223 base::File::Error result) {
224 DCHECK_CURRENTLY_ON(BrowserThread::IO);
225 DCHECK_EQ(INITIALIZING, state_);
227 // In case of an error, abort.
228 if (result != base::File::FILE_OK) {
230 error_callback.Run(net::FileErrorToNetError(result));
234 // If the file modification time has changed, then abort. Note, that the file
235 // may be changed without affecting the modification time.
236 if (!expected_modification_time_.is_null() &&
237 metadata.modification_time != expected_modification_time_) {
239 error_callback.Run(net::ERR_UPLOAD_FILE_CHANGED);
243 DCHECK_EQ(base::File::FILE_OK, result);
244 state_ = INITIALIZED;
246 // Run the task waiting for the initialization to be completed.
247 pending_closure.Run();
250 int FileStreamReader::Read(net::IOBuffer* buffer,
252 const net::CompletionCallback& callback) {
253 DCHECK_CURRENTLY_ON(BrowserThread::IO);
254 TRACE_EVENT_ASYNC_BEGIN1("file_system_provider",
255 "FileStreamReader::Read",
261 case NOT_INITIALIZED:
262 // Lazily initialize with the first call to Read().
263 Initialize(base::Bind(&FileStreamReader::ReadAfterInitialized,
264 weak_ptr_factory_.GetWeakPtr(),
265 make_scoped_refptr(buffer),
267 base::Bind(&FileStreamReader::OnReadCompleted,
268 weak_ptr_factory_.GetWeakPtr(),
270 base::Bind(&Int64ToIntCompletionCallback,
271 base::Bind(&FileStreamReader::OnReadCompleted,
272 weak_ptr_factory_.GetWeakPtr(),
281 ReadAfterInitialized(buffer,
283 base::Bind(&FileStreamReader::OnReadCompleted,
284 weak_ptr_factory_.GetWeakPtr(),
293 return net::ERR_IO_PENDING;
296 void FileStreamReader::OnReadCompleted(net::CompletionCallback callback,
298 DCHECK_CURRENTLY_ON(BrowserThread::IO);
299 callback.Run(static_cast<int>(result));
300 TRACE_EVENT_ASYNC_END0(
301 "file_system_provider", "FileStreamReader::Read", this);
304 int64 FileStreamReader::GetLength(
305 const net::Int64CompletionCallback& callback) {
306 DCHECK_CURRENTLY_ON(BrowserThread::IO);
309 case NOT_INITIALIZED:
310 // Lazily initialize with the first call to GetLength().
311 Initialize(base::Bind(&FileStreamReader::GetLengthAfterInitialized,
312 weak_ptr_factory_.GetWeakPtr(),
322 GetLengthAfterInitialized(callback);
330 return net::ERR_IO_PENDING;
333 void FileStreamReader::ReadAfterInitialized(
334 scoped_refptr<net::IOBuffer> buffer,
336 const net::CompletionCallback& callback) {
337 DCHECK_CURRENTLY_ON(BrowserThread::IO);
338 DCHECK_EQ(INITIALIZED, state_);
341 BrowserThread::PostTask(
344 base::Bind(&ReadFileOnUIThread,
350 base::Bind(&OnReadChunkReceivedOnUIThread,
351 base::Bind(&FileStreamReader::OnReadChunkReceived,
352 weak_ptr_factory_.GetWeakPtr(),
356 void FileStreamReader::GetLengthAfterInitialized(
357 const net::Int64CompletionCallback& callback) {
358 DCHECK_CURRENTLY_ON(BrowserThread::IO);
359 DCHECK_EQ(INITIALIZED, state_);
361 BrowserThread::PostTask(
365 &GetMetadataOnUIThread,
369 &OnGetMetadataReceivedOnUIThread,
370 base::Bind(&FileStreamReader::OnGetMetadataForGetLengthReceived,
371 weak_ptr_factory_.GetWeakPtr(),
375 void FileStreamReader::OnReadChunkReceived(
376 const net::CompletionCallback& callback,
379 base::File::Error result) {
380 DCHECK_CURRENTLY_ON(BrowserThread::IO);
381 DCHECK_EQ(INITIALIZED, state_);
383 current_length_ += chunk_length;
385 // If this is the last chunk with a success, then finalize.
386 if (!has_more && result == base::File::FILE_OK) {
387 current_offset_ += current_length_;
388 callback.Run(current_length_);
392 // In case of an error, abort.
393 if (result != base::File::FILE_OK) {
396 callback.Run(net::FileErrorToNetError(result));
400 // More data is about to come, so do not call the callback yet.
404 void FileStreamReader::OnGetMetadataForGetLengthReceived(
405 const net::Int64CompletionCallback& callback,
406 const EntryMetadata& metadata,
407 base::File::Error result) {
408 DCHECK_CURRENTLY_ON(BrowserThread::IO);
409 DCHECK_EQ(INITIALIZED, state_);
411 // In case of an error, abort.
412 if (result != base::File::FILE_OK) {
414 callback.Run(net::FileErrorToNetError(result));
418 // If the file modification time has changed, then abort. Note, that the file
419 // may be changed without affecting the modification time.
420 if (!expected_modification_time_.is_null() &&
421 metadata.modification_time != expected_modification_time_) {
422 callback.Run(net::ERR_UPLOAD_FILE_CHANGED);
426 DCHECK_EQ(base::File::FILE_OK, result);
427 callback.Run(metadata.size);
430 } // namespace file_system_provider
431 } // namespace chromeos