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