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