1 // Copyright (c) 2012 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 "webkit/browser/fileapi/local_file_stream_writer.h" 6 7 #include "base/callback.h" 8 #include "base/message_loop/message_loop.h" 9 #include "net/base/file_stream.h" 10 #include "net/base/io_buffer.h" 11 #include "net/base/net_errors.h" 12 13 namespace fileapi { 14 15 namespace { 16 17 const int kOpenFlagsForWrite = base::PLATFORM_FILE_OPEN | 18 base::PLATFORM_FILE_WRITE | 19 base::PLATFORM_FILE_ASYNC; 20 21 } // namespace 22 23 FileStreamWriter* FileStreamWriter::CreateForLocalFile( 24 base::TaskRunner* task_runner, 25 const base::FilePath& file_path, 26 int64 initial_offset) { 27 return new LocalFileStreamWriter(task_runner, file_path, initial_offset); 28 } 29 30 LocalFileStreamWriter::~LocalFileStreamWriter() { 31 // Invalidate weak pointers so that we won't receive any callbacks from 32 // in-flight stream operations, which might be triggered during the file close 33 // in the FileStream destructor. 34 weak_factory_.InvalidateWeakPtrs(); 35 36 // FileStream's destructor closes the file safely, since we opened the file 37 // by its Open() method. 38 } 39 40 int LocalFileStreamWriter::Write(net::IOBuffer* buf, int buf_len, 41 const net::CompletionCallback& callback) { 42 DCHECK(!has_pending_operation_); 43 DCHECK(cancel_callback_.is_null()); 44 45 has_pending_operation_ = true; 46 if (stream_impl_) { 47 int result = InitiateWrite(buf, buf_len, callback); 48 if (result != net::ERR_IO_PENDING) 49 has_pending_operation_ = false; 50 return result; 51 } 52 return InitiateOpen(callback, 53 base::Bind(&LocalFileStreamWriter::ReadyToWrite, 54 weak_factory_.GetWeakPtr(), 55 make_scoped_refptr(buf), buf_len, callback)); 56 } 57 58 int LocalFileStreamWriter::Cancel(const net::CompletionCallback& callback) { 59 if (!has_pending_operation_) 60 return net::ERR_UNEXPECTED; 61 62 DCHECK(!callback.is_null()); 63 cancel_callback_ = callback; 64 return net::ERR_IO_PENDING; 65 } 66 67 int LocalFileStreamWriter::Flush(const net::CompletionCallback& callback) { 68 DCHECK(!has_pending_operation_); 69 DCHECK(cancel_callback_.is_null()); 70 71 // Write() is not called yet, so there's nothing to flush. 72 if (!stream_impl_) 73 return net::OK; 74 75 has_pending_operation_ = true; 76 int result = InitiateFlush(callback); 77 if (result != net::ERR_IO_PENDING) 78 has_pending_operation_ = false; 79 return result; 80 } 81 82 LocalFileStreamWriter::LocalFileStreamWriter(base::TaskRunner* task_runner, 83 const base::FilePath& file_path, 84 int64 initial_offset) 85 : file_path_(file_path), 86 initial_offset_(initial_offset), 87 task_runner_(task_runner), 88 has_pending_operation_(false), 89 weak_factory_(this) {} 90 91 int LocalFileStreamWriter::InitiateOpen( 92 const net::CompletionCallback& error_callback, 93 const base::Closure& main_operation) { 94 DCHECK(has_pending_operation_); 95 DCHECK(!stream_impl_.get()); 96 97 stream_impl_.reset(new net::FileStream(NULL, task_runner_)); 98 99 return stream_impl_->Open(file_path_, 100 kOpenFlagsForWrite, 101 base::Bind(&LocalFileStreamWriter::DidOpen, 102 weak_factory_.GetWeakPtr(), 103 error_callback, 104 main_operation)); 105 } 106 107 void LocalFileStreamWriter::DidOpen( 108 const net::CompletionCallback& error_callback, 109 const base::Closure& main_operation, 110 int result) { 111 DCHECK(has_pending_operation_); 112 DCHECK(stream_impl_.get()); 113 114 if (CancelIfRequested()) 115 return; 116 117 if (result != net::OK) { 118 has_pending_operation_ = false; 119 stream_impl_.reset(NULL); 120 error_callback.Run(result); 121 return; 122 } 123 124 InitiateSeek(error_callback, main_operation); 125 } 126 127 void LocalFileStreamWriter::InitiateSeek( 128 const net::CompletionCallback& error_callback, 129 const base::Closure& main_operation) { 130 DCHECK(has_pending_operation_); 131 DCHECK(stream_impl_.get()); 132 133 if (initial_offset_ == 0) { 134 // No need to seek. 135 main_operation.Run(); 136 return; 137 } 138 139 int result = stream_impl_->Seek(net::FROM_BEGIN, initial_offset_, 140 base::Bind(&LocalFileStreamWriter::DidSeek, 141 weak_factory_.GetWeakPtr(), 142 error_callback, 143 main_operation)); 144 if (result != net::ERR_IO_PENDING) { 145 has_pending_operation_ = false; 146 error_callback.Run(result); 147 } 148 } 149 150 void LocalFileStreamWriter::DidSeek( 151 const net::CompletionCallback& error_callback, 152 const base::Closure& main_operation, 153 int64 result) { 154 DCHECK(has_pending_operation_); 155 156 if (CancelIfRequested()) 157 return; 158 159 if (result != initial_offset_) { 160 // TODO(kinaba) add a more specific error code. 161 result = net::ERR_FAILED; 162 } 163 164 if (result < 0) { 165 has_pending_operation_ = false; 166 error_callback.Run(static_cast<int>(result)); 167 return; 168 } 169 170 main_operation.Run(); 171 } 172 173 void LocalFileStreamWriter::ReadyToWrite( 174 net::IOBuffer* buf, int buf_len, 175 const net::CompletionCallback& callback) { 176 DCHECK(has_pending_operation_); 177 178 int result = InitiateWrite(buf, buf_len, callback); 179 if (result != net::ERR_IO_PENDING) { 180 has_pending_operation_ = false; 181 callback.Run(result); 182 } 183 } 184 185 int LocalFileStreamWriter::InitiateWrite( 186 net::IOBuffer* buf, int buf_len, 187 const net::CompletionCallback& callback) { 188 DCHECK(has_pending_operation_); 189 DCHECK(stream_impl_.get()); 190 191 return stream_impl_->Write(buf, buf_len, 192 base::Bind(&LocalFileStreamWriter::DidWrite, 193 weak_factory_.GetWeakPtr(), 194 callback)); 195 } 196 197 void LocalFileStreamWriter::DidWrite(const net::CompletionCallback& callback, 198 int result) { 199 DCHECK(has_pending_operation_); 200 201 if (CancelIfRequested()) 202 return; 203 has_pending_operation_ = false; 204 callback.Run(result); 205 } 206 207 int LocalFileStreamWriter::InitiateFlush( 208 const net::CompletionCallback& callback) { 209 DCHECK(has_pending_operation_); 210 DCHECK(stream_impl_.get()); 211 212 return stream_impl_->Flush(base::Bind(&LocalFileStreamWriter::DidFlush, 213 weak_factory_.GetWeakPtr(), 214 callback)); 215 } 216 217 void LocalFileStreamWriter::DidFlush(const net::CompletionCallback& callback, 218 int result) { 219 DCHECK(has_pending_operation_); 220 221 if (CancelIfRequested()) 222 return; 223 has_pending_operation_ = false; 224 callback.Run(result); 225 } 226 227 bool LocalFileStreamWriter::CancelIfRequested() { 228 DCHECK(has_pending_operation_); 229 230 if (cancel_callback_.is_null()) 231 return false; 232 233 net::CompletionCallback pending_cancel = cancel_callback_; 234 has_pending_operation_ = false; 235 cancel_callback_.Reset(); 236 pending_cancel.Run(net::OK); 237 return true; 238 } 239 240 } // namespace fileapi 241