Chromium Code Reviews| 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)); | |
|
kinaba
2014/05/16 07:58:00
I think you can directly do callback.Run() because
mtomasz
2014/05/16 09:18:20
Done. I also added some thread checks.
| |
| 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)); | |
|
kinaba
2014/05/16 07:58:00
ditto: no need for posting.
mtomasz
2014/05/16 09:18:20
Done.
| |
| 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. | |
|
kinaba
2014/05/16 07:58:00
Comment.
mtomasz
2014/05/16 09:18:20
Done.
| |
| 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; | |
|
kinaba
2014/05/16 07:58:00
ditto: no need for posting.
mtomasz
2014/05/16 09:18:20
Done.
| |
| 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()) { | |
|
kinaba
2014/05/16 07:58:00
Dereferencing a weak pointer in different threads
mtomasz
2014/05/16 09:18:20
Oops. It is also incorrect here, since we don't wa
| |
| 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(). | |
|
kinaba
2014/05/16 07:58:00
nit: Read() => GetLength()
mtomasz
2014/05/16 09:18:20
Done.
| |
| 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 // If this is the last chunk with a success, then finalize. | |
| 284 if (!has_next && result == base::File::FILE_OK) { | |
| 285 current_offset_ += current_length_; | |
| 286 callback.Run(current_length_); | |
| 287 return; | |
| 288 } | |
| 289 | |
| 290 // In case of an error, abort. | |
| 291 if (result != base::File::FILE_OK) { | |
| 292 DCHECK(!has_next); | |
| 293 callback.Run(net::FileErrorToNetError(result)); | |
|
kinaba
2014/05/16 07:58:00
return;
mtomasz
2014/05/16 09:18:20
Done.
| |
| 294 } | |
| 295 | |
| 296 // More data is about to come, so do not call the callback yet. | |
| 297 DCHECK(has_next); | |
| 298 } | |
| 299 | |
| 300 void FileStreamReader::OnGetMetadataForGetLengthReceived( | |
| 301 const net::Int64CompletionCallback& callback, | |
| 302 base::File::Error result, | |
| 303 const base::File::Info& file_info) { | |
| 304 // In case of an error, abort. | |
| 305 if (result != base::File::FILE_OK) { | |
| 306 callback.Run(net::FileErrorToNetError(result)); | |
| 307 return; | |
| 308 } | |
| 309 | |
| 310 DCHECK_EQ(result, base::File::FILE_OK); | |
| 311 callback.Run(file_info.size); | |
| 312 } | |
| 313 | |
| 314 } // namespace file_system_provider | |
| 315 } // namespace chromeos | |
| OLD | NEW |