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