file_stream_writer.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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_writer.h" 6 7#include "base/debug/trace_event.h" 8#include "base/memory/ref_counted.h" 9#include "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.h" 10#include "chrome/browser/chromeos/file_system_provider/mount_path_util.h" 11#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" 12#include "content/public/browser/browser_thread.h" 13#include "net/base/io_buffer.h" 14#include "net/base/net_errors.h" 15 16using content::BrowserThread; 17 18namespace chromeos { 19namespace file_system_provider { 20namespace { 21 22// Dicards the callback from CloseFile(). 23void EmptyStatusCallback(base::File::Error /* result */) { 24} 25 26// Opens a file for writing and calls the completion callback. Must be called 27// on UI thread. 28void OpenFileOnUIThread( 29 const fileapi::FileSystemURL& url, 30 const FileStreamWriter::OpenFileCompletedCallback& callback) { 31 DCHECK_CURRENTLY_ON(BrowserThread::UI); 32 33 util::FileSystemURLParser parser(url); 34 if (!parser.Parse()) { 35 callback.Run(base::WeakPtr<ProvidedFileSystemInterface>(), 36 base::FilePath(), 37 0 /* file_handle */, 38 base::File::FILE_ERROR_SECURITY); 39 return; 40 } 41 42 parser.file_system()->OpenFile( 43 parser.file_path(), 44 ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE, 45 base::Bind( 46 callback, parser.file_system()->GetWeakPtr(), parser.file_path())); 47} 48 49// Forwards results of calling OpenFileOnUIThread back to the IO thread. 50void OnOpenFileCompletedOnUIThread( 51 const FileStreamWriter::OpenFileCompletedCallback& callback, 52 base::WeakPtr<ProvidedFileSystemInterface> file_system, 53 const base::FilePath& file_path, 54 int file_handle, 55 base::File::Error result) { 56 DCHECK_CURRENTLY_ON(BrowserThread::UI); 57 BrowserThread::PostTask( 58 BrowserThread::IO, 59 FROM_HERE, 60 base::Bind(callback, file_system, file_path, file_handle, result)); 61} 62 63// Closes a file. Ignores result, since it is called from a constructor. 64// Must be called on UI thread. 65void CloseFileOnUIThread(base::WeakPtr<ProvidedFileSystemInterface> file_system, 66 int file_handle) { 67 DCHECK_CURRENTLY_ON(BrowserThread::UI); 68 if (file_system.get()) 69 file_system->CloseFile(file_handle, base::Bind(&EmptyStatusCallback)); 70} 71 72// Requests writing bytes to the file. In case of either success or a failure 73// |callback| is executed. Must be called on UI thread. 74void WriteFileOnUIThread( 75 base::WeakPtr<ProvidedFileSystemInterface> file_system, 76 int file_handle, 77 scoped_refptr<net::IOBuffer> buffer, 78 int64 offset, 79 int length, 80 const fileapi::AsyncFileUtil::StatusCallback& callback) { 81 DCHECK_CURRENTLY_ON(BrowserThread::UI); 82 83 // If the file system got unmounted, then abort the writing operation. 84 if (!file_system.get()) { 85 callback.Run(base::File::FILE_ERROR_ABORT); 86 return; 87 } 88 89 file_system->WriteFile(file_handle, buffer, offset, length, callback); 90} 91 92// Forward the completion callback to IO thread. 93void OnWriteFileCompletedOnUIThread( 94 const fileapi::AsyncFileUtil::StatusCallback& callback, 95 base::File::Error result) { 96 DCHECK_CURRENTLY_ON(BrowserThread::UI); 97 BrowserThread::PostTask( 98 BrowserThread::IO, FROM_HERE, base::Bind(callback, result)); 99} 100 101} // namespace 102 103FileStreamWriter::FileStreamWriter(const fileapi::FileSystemURL& url, 104 int64 initial_offset) 105 : url_(url), 106 current_offset_(initial_offset), 107 state_(NOT_INITIALIZED), 108 file_handle_(0), 109 weak_ptr_factory_(this) { 110} 111 112FileStreamWriter::~FileStreamWriter() { 113 BrowserThread::PostTask( 114 BrowserThread::UI, 115 FROM_HERE, 116 base::Bind(&CloseFileOnUIThread, file_system_, file_handle_)); 117} 118 119void FileStreamWriter::Initialize( 120 const base::Closure& pending_closure, 121 const net::CompletionCallback& error_callback) { 122 DCHECK_EQ(NOT_INITIALIZED, state_); 123 state_ = INITIALIZING; 124 125 BrowserThread::PostTask( 126 BrowserThread::UI, 127 FROM_HERE, 128 base::Bind(&OpenFileOnUIThread, 129 url_, 130 base::Bind(&OnOpenFileCompletedOnUIThread, 131 base::Bind(&FileStreamWriter::OnOpenFileCompleted, 132 weak_ptr_factory_.GetWeakPtr(), 133 pending_closure, 134 error_callback)))); 135} 136 137void FileStreamWriter::OnOpenFileCompleted( 138 const base::Closure& pending_closure, 139 const net::CompletionCallback& error_callback, 140 base::WeakPtr<ProvidedFileSystemInterface> file_system, 141 const base::FilePath& file_path, 142 int file_handle, 143 base::File::Error result) { 144 DCHECK_CURRENTLY_ON(BrowserThread::IO); 145 DCHECK_EQ(INITIALIZING, state_); 146 147 // In case of an error, return immediately using the |error_callback| of the 148 // Write() pending request. 149 if (result != base::File::FILE_OK) { 150 state_ = FAILED; 151 error_callback.Run(net::FileErrorToNetError(result)); 152 return; 153 } 154 155 file_system_ = file_system; 156 file_path_ = file_path; 157 file_handle_ = file_handle; 158 DCHECK_LT(0, file_handle); 159 DCHECK_EQ(base::File::FILE_OK, result); 160 state_ = INITIALIZED; 161 162 // Run the task waiting for the initialization to be completed. 163 pending_closure.Run(); 164} 165 166int FileStreamWriter::Write(net::IOBuffer* buffer, 167 int buffer_length, 168 const net::CompletionCallback& callback) { 169 DCHECK_CURRENTLY_ON(BrowserThread::IO); 170 TRACE_EVENT_ASYNC_BEGIN1("file_system_provider", 171 "FileStreamWriter::Write", 172 this, 173 "buffer_length", 174 buffer_length); 175 176 switch (state_) { 177 case NOT_INITIALIZED: 178 // Lazily initialize with the first call to Write(). 179 Initialize(base::Bind(&FileStreamWriter::WriteAfterInitialized, 180 weak_ptr_factory_.GetWeakPtr(), 181 make_scoped_refptr(buffer), 182 buffer_length, 183 base::Bind(&FileStreamWriter::OnWriteCompleted, 184 weak_ptr_factory_.GetWeakPtr(), 185 callback)), 186 base::Bind(&FileStreamWriter::OnWriteCompleted, 187 weak_ptr_factory_.GetWeakPtr(), 188 callback)); 189 break; 190 191 case INITIALIZING: 192 NOTREACHED(); 193 break; 194 195 case INITIALIZED: 196 WriteAfterInitialized(buffer, 197 buffer_length, 198 base::Bind(&FileStreamWriter::OnWriteCompleted, 199 weak_ptr_factory_.GetWeakPtr(), 200 callback)); 201 break; 202 203 case FAILED: 204 NOTREACHED(); 205 break; 206 } 207 208 return net::ERR_IO_PENDING; 209} 210 211int FileStreamWriter::Cancel(const net::CompletionCallback& callback) { 212 NOTIMPLEMENTED(); 213 return net::ERR_FAILED; 214} 215 216int FileStreamWriter::Flush(const net::CompletionCallback& callback) { 217 if (state_ != INITIALIZED) 218 return net::ERR_FAILED; 219 220 return net::OK; 221} 222 223void FileStreamWriter::OnWriteFileCompleted( 224 int buffer_length, 225 const net::CompletionCallback& callback, 226 base::File::Error result) { 227 DCHECK_CURRENTLY_ON(BrowserThread::IO); 228 DCHECK_EQ(INITIALIZED, state_); 229 230 if (result != base::File::FILE_OK) { 231 state_ = FAILED; 232 callback.Run(net::FileErrorToNetError(result)); 233 return; 234 } 235 236 current_offset_ += buffer_length; 237 callback.Run(buffer_length); 238} 239 240void FileStreamWriter::OnWriteCompleted(net::CompletionCallback callback, 241 int result) { 242 DCHECK_CURRENTLY_ON(BrowserThread::IO); 243 callback.Run(result); 244 TRACE_EVENT_ASYNC_END0( 245 "file_system_provider", "FileStreamWriter::Write", this); 246} 247 248void FileStreamWriter::WriteAfterInitialized( 249 scoped_refptr<net::IOBuffer> buffer, 250 int buffer_length, 251 const net::CompletionCallback& callback) { 252 DCHECK_CURRENTLY_ON(BrowserThread::IO); 253 DCHECK_EQ(INITIALIZED, state_); 254 255 BrowserThread::PostTask( 256 BrowserThread::UI, 257 FROM_HERE, 258 base::Bind(&WriteFileOnUIThread, 259 file_system_, 260 file_handle_, 261 buffer, 262 current_offset_, 263 buffer_length, 264 base::Bind(&OnWriteFileCompletedOnUIThread, 265 base::Bind(&FileStreamWriter::OnWriteFileCompleted, 266 weak_ptr_factory_.GetWeakPtr(), 267 buffer_length, 268 callback)))); 269} 270 271} // namespace file_system_provider 272} // namespace chromeos 273