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