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(const CompletionCallback& callback) { | 219 int FileStream::Flush(const CompletionCallback& callback) { |
82 return impl_.Flush(callback); | 220 if (!IsOpen()) |
| 221 return ERR_UNEXPECTED; |
| 222 |
| 223 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); |
| 224 // Make sure we're async. |
| 225 DCHECK(is_async()); |
| 226 |
| 227 context_->FlushAsync(callback); |
| 228 return ERR_IO_PENDING; |
83 } | 229 } |
84 | 230 |
85 int FileStream::FlushSync() { | 231 int FileStream::FlushSync() { |
86 return impl_.FlushSync(); | 232 base::ThreadRestrictions::AssertIOAllowed(); |
| 233 |
| 234 if (!IsOpen()) |
| 235 return ERR_UNEXPECTED; |
| 236 |
| 237 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); |
| 238 return context_->FlushSync(); |
87 } | 239 } |
88 | 240 |
89 void FileStream::EnableErrorStatistics() { | 241 void FileStream::EnableErrorStatistics() { |
90 impl_.EnableErrorStatistics(); | 242 context_->set_record_uma(true); |
91 } | 243 } |
92 | 244 |
93 void FileStream::SetBoundNetLogSource( | 245 void FileStream::SetBoundNetLogSource( |
94 const net::BoundNetLog& owner_bound_net_log) { | 246 const net::BoundNetLog& owner_bound_net_log) { |
95 impl_.SetBoundNetLogSource(owner_bound_net_log); | 247 if ((owner_bound_net_log.source().id == net::NetLog::Source::kInvalidId) && |
| 248 (bound_net_log_.source().id == net::NetLog::Source::kInvalidId)) { |
| 249 // Both |BoundNetLog|s are invalid. |
| 250 return; |
| 251 } |
| 252 |
| 253 // Should never connect to itself. |
| 254 DCHECK_NE(bound_net_log_.source().id, owner_bound_net_log.source().id); |
| 255 |
| 256 bound_net_log_.AddEvent( |
| 257 net::NetLog::TYPE_FILE_STREAM_BOUND_TO_OWNER, |
| 258 owner_bound_net_log.source().ToEventParametersCallback()); |
| 259 |
| 260 owner_bound_net_log.AddEvent( |
| 261 net::NetLog::TYPE_FILE_STREAM_SOURCE, |
| 262 bound_net_log_.source().ToEventParametersCallback()); |
96 } | 263 } |
97 | 264 |
98 base::PlatformFile FileStream::GetPlatformFileForTesting() { | 265 base::PlatformFile FileStream::GetPlatformFileForTesting() { |
99 return impl_.GetPlatformFileForTesting(); | 266 return context_->file(); |
100 } | 267 } |
101 | 268 |
102 } // namespace net | 269 } // namespace net |
OLD | NEW |