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 |