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