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 "net/base/file_stream.h" 6 7 #include "base/location.h" 8 #include "base/message_loop/message_loop_proxy.h" 9 #include "base/task_runner_util.h" 10 #include "base/threading/thread_restrictions.h" 11 #include "base/threading/worker_pool.h" 12 #include "net/base/file_stream_context.h" 13 #include "net/base/file_stream_net_log_parameters.h" 14 #include "net/base/net_errors.h" 15 16 namespace net { 17 18 FileStream::FileStream(NetLog* net_log, 19 const scoped_refptr<base::TaskRunner>& task_runner) 20 /* To allow never opened stream to be destroyed on any thread we set flags 21 as if stream was opened asynchronously. */ 22 : open_flags_(base::PLATFORM_FILE_ASYNC), 23 bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)), 24 context_(new Context(bound_net_log_, task_runner)) { 25 bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE); 26 } 27 28 FileStream::FileStream(NetLog* net_log) 29 /* To allow never opened stream to be destroyed on any thread we set flags 30 as if stream was opened asynchronously. */ 31 : open_flags_(base::PLATFORM_FILE_ASYNC), 32 bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)), 33 context_(new Context(bound_net_log_, 34 base::WorkerPool::GetTaskRunner(true /* slow */))) { 35 bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE); 36 } 37 38 FileStream::FileStream(base::PlatformFile file, 39 int flags, 40 NetLog* net_log, 41 const scoped_refptr<base::TaskRunner>& task_runner) 42 : open_flags_(flags), 43 bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)), 44 context_(new Context(file, bound_net_log_, open_flags_, task_runner)) { 45 bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE); 46 } 47 48 FileStream::FileStream(base::PlatformFile file, int flags, NetLog* net_log) 49 : open_flags_(flags), 50 bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)), 51 context_(new Context(file, 52 bound_net_log_, 53 open_flags_, 54 base::WorkerPool::GetTaskRunner(true /* slow */))) { 55 bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE); 56 } 57 58 FileStream::~FileStream() { 59 if (!is_async()) { 60 base::ThreadRestrictions::AssertIOAllowed(); 61 context_->CloseSync(); 62 context_.reset(); 63 } else { 64 context_.release()->Orphan(); 65 } 66 67 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_ALIVE); 68 } 69 70 int FileStream::Open(const base::FilePath& path, int open_flags, 71 const CompletionCallback& callback) { 72 if (IsOpen()) { 73 DLOG(FATAL) << "File is already open!"; 74 return ERR_UNEXPECTED; 75 } 76 77 open_flags_ = open_flags; 78 DCHECK(is_async()); 79 context_->OpenAsync(path, open_flags, callback); 80 return ERR_IO_PENDING; 81 } 82 83 int FileStream::OpenSync(const base::FilePath& path, int open_flags) { 84 base::ThreadRestrictions::AssertIOAllowed(); 85 86 if (IsOpen()) { 87 DLOG(FATAL) << "File is already open!"; 88 return ERR_UNEXPECTED; 89 } 90 91 open_flags_ = open_flags; 92 DCHECK(!is_async()); 93 return context_->OpenSync(path, open_flags_); 94 } 95 96 int FileStream::Close(const CompletionCallback& callback) { 97 DCHECK(is_async()); 98 context_->CloseAsync(callback); 99 return ERR_IO_PENDING; 100 } 101 102 int FileStream::CloseSync() { 103 DCHECK(!is_async()); 104 base::ThreadRestrictions::AssertIOAllowed(); 105 context_->CloseSync(); 106 return OK; 107 } 108 109 bool FileStream::IsOpen() const { 110 return context_->file() != base::kInvalidPlatformFileValue; 111 } 112 113 int FileStream::Seek(Whence whence, 114 int64 offset, 115 const Int64CompletionCallback& callback) { 116 if (!IsOpen()) 117 return ERR_UNEXPECTED; 118 119 // Make sure we're async. 120 DCHECK(is_async()); 121 context_->SeekAsync(whence, offset, callback); 122 return ERR_IO_PENDING; 123 } 124 125 int64 FileStream::SeekSync(Whence whence, int64 offset) { 126 base::ThreadRestrictions::AssertIOAllowed(); 127 128 if (!IsOpen()) 129 return ERR_UNEXPECTED; 130 131 // If we're in async, make sure we don't have a request in flight. 132 DCHECK(!is_async() || !context_->async_in_progress()); 133 return context_->SeekSync(whence, offset); 134 } 135 136 int64 FileStream::Available() { 137 base::ThreadRestrictions::AssertIOAllowed(); 138 139 if (!IsOpen()) 140 return ERR_UNEXPECTED; 141 142 int64 cur_pos = SeekSync(FROM_CURRENT, 0); 143 if (cur_pos < 0) 144 return cur_pos; 145 146 int64 size = context_->GetFileSize(); 147 if (size < 0) 148 return size; 149 150 DCHECK_GE(size, cur_pos); 151 return size - cur_pos; 152 } 153 154 int FileStream::Read(IOBuffer* buf, 155 int buf_len, 156 const CompletionCallback& callback) { 157 if (!IsOpen()) 158 return ERR_UNEXPECTED; 159 160 // read(..., 0) will return 0, which indicates end-of-file. 161 DCHECK_GT(buf_len, 0); 162 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); 163 DCHECK(is_async()); 164 165 return context_->ReadAsync(buf, buf_len, callback); 166 } 167 168 int FileStream::ReadSync(char* buf, int buf_len) { 169 base::ThreadRestrictions::AssertIOAllowed(); 170 171 if (!IsOpen()) 172 return ERR_UNEXPECTED; 173 174 DCHECK(!is_async()); 175 // read(..., 0) will return 0, which indicates end-of-file. 176 DCHECK_GT(buf_len, 0); 177 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); 178 179 return context_->ReadSync(buf, buf_len); 180 } 181 182 int FileStream::ReadUntilComplete(char *buf, int buf_len) { 183 base::ThreadRestrictions::AssertIOAllowed(); 184 185 int to_read = buf_len; 186 int bytes_total = 0; 187 188 do { 189 int bytes_read = ReadSync(buf, to_read); 190 if (bytes_read <= 0) { 191 if (bytes_total == 0) 192 return bytes_read; 193 194 return bytes_total; 195 } 196 197 bytes_total += bytes_read; 198 buf += bytes_read; 199 to_read -= bytes_read; 200 } while (bytes_total < buf_len); 201 202 return bytes_total; 203 } 204 205 int FileStream::Write(IOBuffer* buf, 206 int buf_len, 207 const CompletionCallback& callback) { 208 if (!IsOpen()) 209 return ERR_UNEXPECTED; 210 211 DCHECK(is_async()); 212 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 213 // write(..., 0) will return 0, which indicates end-of-file. 214 DCHECK_GT(buf_len, 0); 215 216 return context_->WriteAsync(buf, buf_len, callback); 217 } 218 219 int FileStream::WriteSync(const char* buf, int buf_len) { 220 base::ThreadRestrictions::AssertIOAllowed(); 221 222 if (!IsOpen()) 223 return ERR_UNEXPECTED; 224 225 DCHECK(!is_async()); 226 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 227 // write(..., 0) will return 0, which indicates end-of-file. 228 DCHECK_GT(buf_len, 0); 229 230 return context_->WriteSync(buf, buf_len); 231 } 232 233 int64 FileStream::Truncate(int64 bytes) { 234 base::ThreadRestrictions::AssertIOAllowed(); 235 236 if (!IsOpen()) 237 return ERR_UNEXPECTED; 238 239 // We'd better be open for writing. 240 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 241 242 // Seek to the position to truncate from. 243 int64 seek_position = SeekSync(FROM_BEGIN, bytes); 244 if (seek_position != bytes) 245 return ERR_UNEXPECTED; 246 247 // And truncate the file. 248 return context_->Truncate(bytes); 249 } 250 251 int FileStream::Flush(const CompletionCallback& callback) { 252 if (!IsOpen()) 253 return ERR_UNEXPECTED; 254 255 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 256 // Make sure we're async. 257 DCHECK(is_async()); 258 259 context_->FlushAsync(callback); 260 return ERR_IO_PENDING; 261 } 262 263 int FileStream::FlushSync() { 264 base::ThreadRestrictions::AssertIOAllowed(); 265 266 if (!IsOpen()) 267 return ERR_UNEXPECTED; 268 269 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 270 return context_->FlushSync(); 271 } 272 273 void FileStream::EnableErrorStatistics() { 274 context_->set_record_uma(true); 275 } 276 277 void FileStream::SetBoundNetLogSource(const BoundNetLog& owner_bound_net_log) { 278 if ((owner_bound_net_log.source().id == NetLog::Source::kInvalidId) && 279 (bound_net_log_.source().id == NetLog::Source::kInvalidId)) { 280 // Both |BoundNetLog|s are invalid. 281 return; 282 } 283 284 // Should never connect to itself. 285 DCHECK_NE(bound_net_log_.source().id, owner_bound_net_log.source().id); 286 287 bound_net_log_.AddEvent(NetLog::TYPE_FILE_STREAM_BOUND_TO_OWNER, 288 owner_bound_net_log.source().ToEventParametersCallback()); 289 290 owner_bound_net_log.AddEvent(NetLog::TYPE_FILE_STREAM_SOURCE, 291 bound_net_log_.source().ToEventParametersCallback()); 292 } 293 294 base::PlatformFile FileStream::GetPlatformFileForTesting() { 295 return context_->file(); 296 } 297 298 } // namespace net 299