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