• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "net/base/file_stream.h"
6 
7 #include "base/location.h"
8 #include "base/message_loop/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 
16 namespace net {
17 
FileStream(NetLog * net_log,const scoped_refptr<base::TaskRunner> & task_runner)18 FileStream::FileStream(NetLog* net_log,
19                        const scoped_refptr<base::TaskRunner>& task_runner)
20       /* To allow never opened stream to be destroyed on any thread we set flags
21          as if stream was opened asynchronously. */
22     : open_flags_(base::PLATFORM_FILE_ASYNC),
23       bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
24       context_(new Context(bound_net_log_, task_runner)) {
25   bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
26 }
27 
FileStream(NetLog * net_log)28 FileStream::FileStream(NetLog* net_log)
29       /* To allow never opened stream to be destroyed on any thread we set flags
30          as if stream was opened asynchronously. */
31     : open_flags_(base::PLATFORM_FILE_ASYNC),
32       bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
33       context_(new Context(bound_net_log_,
34                            base::WorkerPool::GetTaskRunner(true /* slow */))) {
35   bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
36 }
37 
FileStream(base::PlatformFile file,int flags,NetLog * net_log,const scoped_refptr<base::TaskRunner> & task_runner)38 FileStream::FileStream(base::PlatformFile file,
39                        int flags,
40                        NetLog* net_log,
41                        const scoped_refptr<base::TaskRunner>& task_runner)
42     : open_flags_(flags),
43       bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
44       context_(new Context(file, bound_net_log_, open_flags_, task_runner)) {
45   bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
46 }
47 
FileStream(base::PlatformFile file,int flags,NetLog * net_log)48 FileStream::FileStream(base::PlatformFile file, int flags, NetLog* net_log)
49     : open_flags_(flags),
50       bound_net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_FILESTREAM)),
51       context_(new Context(file,
52                            bound_net_log_,
53                            open_flags_,
54                            base::WorkerPool::GetTaskRunner(true /* slow */))) {
55   bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
56 }
57 
~FileStream()58 FileStream::~FileStream() {
59   if (!is_async()) {
60     base::ThreadRestrictions::AssertIOAllowed();
61     context_->CloseSync();
62     context_.reset();
63   } else {
64     context_.release()->Orphan();
65   }
66 
67   bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_ALIVE);
68 }
69 
Open(const base::FilePath & path,int open_flags,const CompletionCallback & callback)70 int FileStream::Open(const base::FilePath& path, int open_flags,
71                      const CompletionCallback& callback) {
72   if (IsOpen()) {
73     DLOG(FATAL) << "File is already open!";
74     return ERR_UNEXPECTED;
75   }
76 
77   open_flags_ = open_flags;
78   DCHECK(is_async());
79   context_->OpenAsync(path, open_flags, callback);
80   return ERR_IO_PENDING;
81 }
82 
OpenSync(const base::FilePath & path,int open_flags)83 int FileStream::OpenSync(const base::FilePath& path, int open_flags) {
84   base::ThreadRestrictions::AssertIOAllowed();
85 
86   if (IsOpen()) {
87     DLOG(FATAL) << "File is already open!";
88     return ERR_UNEXPECTED;
89   }
90 
91   open_flags_ = open_flags;
92   DCHECK(!is_async());
93   return context_->OpenSync(path, open_flags_);
94 }
95 
Close(const CompletionCallback & callback)96 int FileStream::Close(const CompletionCallback& callback) {
97   DCHECK(is_async());
98   context_->CloseAsync(callback);
99   return ERR_IO_PENDING;
100 }
101 
CloseSync()102 int FileStream::CloseSync() {
103   DCHECK(!is_async());
104   base::ThreadRestrictions::AssertIOAllowed();
105   context_->CloseSync();
106   return OK;
107 }
108 
IsOpen() const109 bool FileStream::IsOpen() const {
110   return context_->file() != base::kInvalidPlatformFileValue;
111 }
112 
Seek(Whence whence,int64 offset,const Int64CompletionCallback & callback)113 int FileStream::Seek(Whence whence,
114                      int64 offset,
115                      const Int64CompletionCallback& callback) {
116   if (!IsOpen())
117     return ERR_UNEXPECTED;
118 
119   // Make sure we're async.
120   DCHECK(is_async());
121   context_->SeekAsync(whence, offset, callback);
122   return ERR_IO_PENDING;
123 }
124 
SeekSync(Whence whence,int64 offset)125 int64 FileStream::SeekSync(Whence whence, int64 offset) {
126   base::ThreadRestrictions::AssertIOAllowed();
127 
128   if (!IsOpen())
129     return ERR_UNEXPECTED;
130 
131   // If we're in async, make sure we don't have a request in flight.
132   DCHECK(!is_async() || !context_->async_in_progress());
133   return context_->SeekSync(whence, offset);
134 }
135 
Available()136 int64 FileStream::Available() {
137   base::ThreadRestrictions::AssertIOAllowed();
138 
139   if (!IsOpen())
140     return ERR_UNEXPECTED;
141 
142   int64 cur_pos = SeekSync(FROM_CURRENT, 0);
143   if (cur_pos < 0)
144     return cur_pos;
145 
146   int64 size = context_->GetFileSize();
147   if (size < 0)
148     return size;
149 
150   DCHECK_GE(size, cur_pos);
151   return size - cur_pos;
152 }
153 
Read(IOBuffer * buf,int buf_len,const CompletionCallback & callback)154 int FileStream::Read(IOBuffer* buf,
155                      int buf_len,
156                      const CompletionCallback& callback) {
157   if (!IsOpen())
158     return ERR_UNEXPECTED;
159 
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   DCHECK(is_async());
164 
165   return context_->ReadAsync(buf, buf_len, callback);
166 }
167 
ReadSync(char * buf,int buf_len)168 int FileStream::ReadSync(char* buf, int buf_len) {
169   base::ThreadRestrictions::AssertIOAllowed();
170 
171   if (!IsOpen())
172     return ERR_UNEXPECTED;
173 
174   DCHECK(!is_async());
175   // read(..., 0) will return 0, which indicates end-of-file.
176   DCHECK_GT(buf_len, 0);
177   DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
178 
179   return context_->ReadSync(buf, buf_len);
180 }
181 
ReadUntilComplete(char * buf,int buf_len)182 int FileStream::ReadUntilComplete(char *buf, int buf_len) {
183   base::ThreadRestrictions::AssertIOAllowed();
184 
185   int to_read = buf_len;
186   int bytes_total = 0;
187 
188   do {
189     int bytes_read = ReadSync(buf, to_read);
190     if (bytes_read <= 0) {
191       if (bytes_total == 0)
192         return bytes_read;
193 
194       return bytes_total;
195     }
196 
197     bytes_total += bytes_read;
198     buf += bytes_read;
199     to_read -= bytes_read;
200   } while (bytes_total < buf_len);
201 
202   return bytes_total;
203 }
204 
Write(IOBuffer * buf,int buf_len,const CompletionCallback & callback)205 int FileStream::Write(IOBuffer* buf,
206                       int buf_len,
207                       const CompletionCallback& callback) {
208   if (!IsOpen())
209     return ERR_UNEXPECTED;
210 
211   DCHECK(is_async());
212   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
213   // write(..., 0) will return 0, which indicates end-of-file.
214   DCHECK_GT(buf_len, 0);
215 
216   return context_->WriteAsync(buf, buf_len, callback);
217 }
218 
WriteSync(const char * buf,int buf_len)219 int FileStream::WriteSync(const char* buf, int buf_len) {
220   base::ThreadRestrictions::AssertIOAllowed();
221 
222   if (!IsOpen())
223     return ERR_UNEXPECTED;
224 
225   DCHECK(!is_async());
226   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
227   // write(..., 0) will return 0, which indicates end-of-file.
228   DCHECK_GT(buf_len, 0);
229 
230   return context_->WriteSync(buf, buf_len);
231 }
232 
Truncate(int64 bytes)233 int64 FileStream::Truncate(int64 bytes) {
234   base::ThreadRestrictions::AssertIOAllowed();
235 
236   if (!IsOpen())
237     return ERR_UNEXPECTED;
238 
239   // We'd better be open for writing.
240   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
241 
242   // Seek to the position to truncate from.
243   int64 seek_position = SeekSync(FROM_BEGIN, bytes);
244   if (seek_position != bytes)
245     return ERR_UNEXPECTED;
246 
247   // And truncate the file.
248   return context_->Truncate(bytes);
249 }
250 
Flush(const CompletionCallback & callback)251 int FileStream::Flush(const CompletionCallback& callback) {
252   if (!IsOpen())
253     return ERR_UNEXPECTED;
254 
255   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
256   // Make sure we're async.
257   DCHECK(is_async());
258 
259   context_->FlushAsync(callback);
260   return ERR_IO_PENDING;
261 }
262 
FlushSync()263 int FileStream::FlushSync() {
264   base::ThreadRestrictions::AssertIOAllowed();
265 
266   if (!IsOpen())
267     return ERR_UNEXPECTED;
268 
269   DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
270   return context_->FlushSync();
271 }
272 
EnableErrorStatistics()273 void FileStream::EnableErrorStatistics() {
274   context_->set_record_uma(true);
275 }
276 
SetBoundNetLogSource(const BoundNetLog & owner_bound_net_log)277 void FileStream::SetBoundNetLogSource(const BoundNetLog& owner_bound_net_log) {
278   if ((owner_bound_net_log.source().id == NetLog::Source::kInvalidId) &&
279       (bound_net_log_.source().id == NetLog::Source::kInvalidId)) {
280     // Both |BoundNetLog|s are invalid.
281     return;
282   }
283 
284   // Should never connect to itself.
285   DCHECK_NE(bound_net_log_.source().id, owner_bound_net_log.source().id);
286 
287   bound_net_log_.AddEvent(NetLog::TYPE_FILE_STREAM_BOUND_TO_OWNER,
288       owner_bound_net_log.source().ToEventParametersCallback());
289 
290   owner_bound_net_log.AddEvent(NetLog::TYPE_FILE_STREAM_SOURCE,
291       bound_net_log_.source().ToEventParametersCallback());
292 }
293 
GetPlatformFileForTesting()294 base::PlatformFile FileStream::GetPlatformFileForTesting() {
295   return context_->file();
296 }
297 
298 }  // namespace net
299