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 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 36 |
| 37 // TODO(mtomasz): Check if the modification time of the file is as expected. |
| 38 util::FileSystemURLParser parser(url); |
| 39 if (!parser.Parse()) { |
| 40 callback.Run(base::WeakPtr<ProvidedFileSystemInterface>(), |
| 41 base::FilePath(), |
| 42 0 /* file_handle */, |
| 43 base::File::FILE_ERROR_SECURITY); |
| 44 return; |
| 45 } |
| 46 |
| 47 parser.file_system()->OpenFile( |
| 48 parser.file_path(), |
| 49 ProvidedFileSystemInterface::OPEN_FILE_MODE_READ, |
| 50 false /* create */, |
| 51 base::Bind( |
| 52 callback, parser.file_system()->GetWeakPtr(), parser.file_path())); |
| 53 } |
| 54 |
| 55 // Forwards results of calling OpenFileOnUIThread back to the IO thread. |
| 56 void OnOpenFileCompletedOnUIThread( |
| 57 const FileStreamReader::InitializeCompletedCallback& callback, |
| 58 base::WeakPtr<ProvidedFileSystemInterface> file_system, |
| 59 const base::FilePath& file_path, |
| 60 int file_handle, |
| 61 base::File::Error result) { |
| 62 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 63 BrowserThread::PostTask( |
| 64 BrowserThread::IO, |
| 65 FROM_HERE, |
| 66 base::Bind(callback, file_system, file_path, file_handle, result)); |
| 67 } |
| 68 |
| 69 // Closes a file. Ignores result, since it is called from a constructor. |
| 70 // Must be called on UI thread. |
| 71 void CloseFileOnUIThread(base::WeakPtr<ProvidedFileSystemInterface> file_system, |
| 72 int file_handle) { |
| 73 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 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 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 90 |
| 91 // If the file system got unmounted, then abort the reading operation. |
| 92 if (!file_system.get()) { |
| 93 callback.Run(0, false /* has_next */, base::File::FILE_ERROR_ABORT); |
| 94 return; |
| 95 } |
| 96 |
| 97 file_system->ReadFile(file_handle, buffer, offset, length, callback); |
| 98 } |
| 99 |
| 100 // Forward the completion callback to IO thread. |
| 101 void OnReadChunkReceivedOnUIThread( |
| 102 const ProvidedFileSystemInterface::ReadChunkReceivedCallback& |
| 103 chunk_received_callback, |
| 104 int chunk_length, |
| 105 bool has_next, |
| 106 base::File::Error result) { |
| 107 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 108 BrowserThread::PostTask( |
| 109 BrowserThread::IO, |
| 110 FROM_HERE, |
| 111 base::Bind(chunk_received_callback, chunk_length, has_next, result)); |
| 112 } |
| 113 |
| 114 // Requests metadata of a file. In case of either succes or a failure, |
| 115 // |callback is executed. Must be called on UI thread. |
| 116 void GetMetadataOnUIThread( |
| 117 base::WeakPtr<ProvidedFileSystemInterface> file_system, |
| 118 const base::FilePath& file_path, |
| 119 const fileapi::AsyncFileUtil::GetFileInfoCallback& callback) { |
| 120 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 121 |
| 122 // If the file system got unmounted, then abort the get length operation. |
| 123 if (!file_system.get()) { |
| 124 callback.Run(base::File::FILE_ERROR_ABORT, base::File::Info()); |
| 125 return; |
| 126 } |
| 127 |
| 128 file_system->GetMetadata(file_path, callback); |
| 129 } |
| 130 |
| 131 // Forward the completion callback to IO thread. |
| 132 void OnGetMetadataReceivedOnUIThread( |
| 133 const fileapi::AsyncFileUtil::GetFileInfoCallback& callback, |
| 134 base::File::Error result, |
| 135 const base::File::Info& file_info) { |
| 136 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 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 : url_(url), |
| 148 current_offset_(initial_offset), |
| 149 current_length_(0), |
| 150 expected_modification_time_(expected_modification_time), |
| 151 file_handle_(0), |
| 152 weak_ptr_factory_(this) { |
| 153 } |
| 154 |
| 155 FileStreamReader::~FileStreamReader() { |
| 156 BrowserThread::PostTask( |
| 157 BrowserThread::UI, |
| 158 FROM_HERE, |
| 159 base::Bind(&CloseFileOnUIThread, file_system_, file_handle_)); |
| 160 } |
| 161 |
| 162 void FileStreamReader::Initialize( |
| 163 const base::Closure& pending_closure, |
| 164 const net::Int64CompletionCallback& error_callback) { |
| 165 BrowserThread::PostTask( |
| 166 BrowserThread::UI, |
| 167 FROM_HERE, |
| 168 base::Bind(&OpenFileOnUIThread, |
| 169 url_, |
| 170 base::Bind(&OnOpenFileCompletedOnUIThread, |
| 171 base::Bind(&FileStreamReader::OnInitializeCompleted, |
| 172 weak_ptr_factory_.GetWeakPtr(), |
| 173 pending_closure, |
| 174 error_callback)))); |
| 175 } |
| 176 |
| 177 void FileStreamReader::OnInitializeCompleted( |
| 178 const base::Closure& pending_closure, |
| 179 const net::Int64CompletionCallback& error_callback, |
| 180 base::WeakPtr<ProvidedFileSystemInterface> file_system, |
| 181 const base::FilePath& file_path, |
| 182 int file_handle, |
| 183 base::File::Error result) { |
| 184 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 185 |
| 186 // In case of an error, return immediately using the |error_callback| of the |
| 187 // Read() or GetLength() pending request. |
| 188 if (result != base::File::FILE_OK) { |
| 189 error_callback.Run(net::FileErrorToNetError(result)); |
| 190 return; |
| 191 } |
| 192 |
| 193 file_system_ = file_system; |
| 194 file_path_ = file_path; |
| 195 file_handle_ = file_handle; |
| 196 DCHECK_LT(0, file_handle); |
| 197 |
| 198 // Run the task waiting for the initialization to be completed. |
| 199 pending_closure.Run(); |
| 200 } |
| 201 |
| 202 int FileStreamReader::Read(net::IOBuffer* buffer, |
| 203 int buffer_length, |
| 204 const net::CompletionCallback& callback) { |
| 205 // Lazily initialize with the first call to Read(). |
| 206 if (!file_handle_) { |
| 207 Initialize(base::Bind(&FileStreamReader::ReadAfterInitialized, |
| 208 weak_ptr_factory_.GetWeakPtr(), |
| 209 buffer, |
| 210 buffer_length, |
| 211 callback), |
| 212 base::Bind(&Int64ToIntCompletionCallback, callback)); |
| 213 return net::ERR_IO_PENDING; |
| 214 } |
| 215 |
| 216 ReadAfterInitialized(buffer, buffer_length, callback); |
| 217 return net::ERR_IO_PENDING; |
| 218 } |
| 219 |
| 220 int64 FileStreamReader::GetLength( |
| 221 const net::Int64CompletionCallback& callback) { |
| 222 // Lazily initialize with the first call to GetLength(). |
| 223 if (!file_handle_) { |
| 224 Initialize(base::Bind(&FileStreamReader::GetLengthAfterInitialized, |
| 225 weak_ptr_factory_.GetWeakPtr(), |
| 226 callback), |
| 227 callback); |
| 228 return net::ERR_IO_PENDING; |
| 229 } |
| 230 |
| 231 GetLengthAfterInitialized(callback); |
| 232 return net::ERR_IO_PENDING; |
| 233 } |
| 234 |
| 235 void FileStreamReader::ReadAfterInitialized( |
| 236 net::IOBuffer* buffer, |
| 237 int buffer_length, |
| 238 const net::CompletionCallback& callback) { |
| 239 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 240 |
| 241 // If the file system got unmounted, then abort the reading operation. |
| 242 if (!file_handle_) { |
| 243 callback.Run(net::ERR_ABORTED); |
| 244 return; |
| 245 } |
| 246 |
| 247 current_length_ = 0; |
| 248 BrowserThread::PostTask( |
| 249 BrowserThread::UI, |
| 250 FROM_HERE, |
| 251 base::Bind(&ReadFileOnUIThread, |
| 252 file_system_, |
| 253 file_handle_, |
| 254 buffer, |
| 255 current_offset_, |
| 256 buffer_length, |
| 257 base::Bind(&OnReadChunkReceivedOnUIThread, |
| 258 base::Bind(&FileStreamReader::OnReadChunkReceived, |
| 259 weak_ptr_factory_.GetWeakPtr(), |
| 260 callback)))); |
| 261 } |
| 262 |
| 263 void FileStreamReader::GetLengthAfterInitialized( |
| 264 const net::Int64CompletionCallback& callback) { |
| 265 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 266 |
| 267 // If the file system got unmounted, then abort the length fetching operation. |
| 268 if (!file_handle_) { |
| 269 callback.Run(net::ERR_ABORTED); |
| 270 return; |
| 271 } |
| 272 |
| 273 BrowserThread::PostTask( |
| 274 BrowserThread::UI, |
| 275 FROM_HERE, |
| 276 base::Bind( |
| 277 &GetMetadataOnUIThread, |
| 278 file_system_, |
| 279 file_path_, |
| 280 base::Bind( |
| 281 &OnGetMetadataReceivedOnUIThread, |
| 282 base::Bind(&FileStreamReader::OnGetMetadataForGetLengthReceived, |
| 283 weak_ptr_factory_.GetWeakPtr(), |
| 284 callback)))); |
| 285 } |
| 286 |
| 287 void FileStreamReader::OnReadChunkReceived( |
| 288 const net::CompletionCallback& callback, |
| 289 int chunk_length, |
| 290 bool has_next, |
| 291 base::File::Error result) { |
| 292 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 293 current_length_ += chunk_length; |
| 294 |
| 295 // If this is the last chunk with a success, then finalize. |
| 296 if (!has_next && result == base::File::FILE_OK) { |
| 297 current_offset_ += current_length_; |
| 298 callback.Run(current_length_); |
| 299 return; |
| 300 } |
| 301 |
| 302 // In case of an error, abort. |
| 303 if (result != base::File::FILE_OK) { |
| 304 DCHECK(!has_next); |
| 305 callback.Run(net::FileErrorToNetError(result)); |
| 306 return; |
| 307 } |
| 308 |
| 309 // More data is about to come, so do not call the callback yet. |
| 310 DCHECK(has_next); |
| 311 } |
| 312 |
| 313 void FileStreamReader::OnGetMetadataForGetLengthReceived( |
| 314 const net::Int64CompletionCallback& callback, |
| 315 base::File::Error result, |
| 316 const base::File::Info& file_info) { |
| 317 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 318 |
| 319 // In case of an error, abort. |
| 320 if (result != base::File::FILE_OK) { |
| 321 callback.Run(net::FileErrorToNetError(result)); |
| 322 return; |
| 323 } |
| 324 |
| 325 DCHECK_EQ(result, base::File::FILE_OK); |
| 326 callback.Run(file_info.size); |
| 327 } |
| 328 |
| 329 } // namespace file_system_provider |
| 330 } // namespace chromeos |
OLD | NEW |