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.
5 #include "net/base/file_stream.h"
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"
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
);
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
);
38 FileStream::FileStream(base::PlatformFile file
,
41 const scoped_refptr
<base::TaskRunner
>& task_runner
)
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
);
48 FileStream::FileStream(base::PlatformFile file
, int flags
, NetLog
* net_log
)
50 bound_net_log_(BoundNetLog::Make(net_log
, NetLog::SOURCE_FILESTREAM
)),
51 context_(new Context(file
,
54 base::WorkerPool::GetTaskRunner(true /* slow */))) {
55 bound_net_log_
.BeginEvent(NetLog::TYPE_FILE_STREAM_ALIVE
);
58 FileStream::~FileStream() {
60 base::ThreadRestrictions::AssertIOAllowed();
61 context_
->CloseSync();
64 context_
.release()->Orphan();
67 bound_net_log_
.EndEvent(NetLog::TYPE_FILE_STREAM_ALIVE
);
70 int FileStream::Open(const base::FilePath
& path
, int open_flags
,
71 const CompletionCallback
& callback
) {
73 DLOG(FATAL
) << "File is already open!";
74 return ERR_UNEXPECTED
;
77 open_flags_
= open_flags
;
79 context_
->OpenAsync(path
, open_flags
, callback
);
80 return ERR_IO_PENDING
;
83 int FileStream::OpenSync(const base::FilePath
& path
, int open_flags
) {
84 base::ThreadRestrictions::AssertIOAllowed();
87 DLOG(FATAL
) << "File is already open!";
88 return ERR_UNEXPECTED
;
91 open_flags_
= open_flags
;
93 return context_
->OpenSync(path
, open_flags_
);
96 bool FileStream::IsOpen() const {
97 return context_
->file() != base::kInvalidPlatformFileValue
;
100 int FileStream::Seek(Whence whence
,
102 const Int64CompletionCallback
& callback
) {
104 return ERR_UNEXPECTED
;
106 // Make sure we're async.
108 context_
->SeekAsync(whence
, offset
, callback
);
109 return ERR_IO_PENDING
;
112 int64
FileStream::SeekSync(Whence whence
, int64 offset
) {
113 base::ThreadRestrictions::AssertIOAllowed();
116 return ERR_UNEXPECTED
;
118 // If we're in async, make sure we don't have a request in flight.
119 DCHECK(!is_async() || !context_
->async_in_progress());
120 return context_
->SeekSync(whence
, offset
);
123 int64
FileStream::Available() {
124 base::ThreadRestrictions::AssertIOAllowed();
127 return ERR_UNEXPECTED
;
129 int64 cur_pos
= SeekSync(FROM_CURRENT
, 0);
133 int64 size
= context_
->GetFileSize();
137 DCHECK_GE(size
, cur_pos
);
138 return size
- cur_pos
;
141 int FileStream::Read(IOBuffer
* buf
,
143 const CompletionCallback
& callback
) {
145 return ERR_UNEXPECTED
;
147 // read(..., 0) will return 0, which indicates end-of-file.
148 DCHECK_GT(buf_len
, 0);
149 DCHECK(open_flags_
& base::PLATFORM_FILE_READ
);
152 return context_
->ReadAsync(buf
, buf_len
, callback
);
155 int FileStream::ReadSync(char* buf
, int buf_len
) {
156 base::ThreadRestrictions::AssertIOAllowed();
159 return ERR_UNEXPECTED
;
162 // read(..., 0) will return 0, which indicates end-of-file.
163 DCHECK_GT(buf_len
, 0);
164 DCHECK(open_flags_
& base::PLATFORM_FILE_READ
);
166 return context_
->ReadSync(buf
, buf_len
);
169 int FileStream::ReadUntilComplete(char *buf
, int buf_len
) {
170 base::ThreadRestrictions::AssertIOAllowed();
172 int to_read
= buf_len
;
176 int bytes_read
= ReadSync(buf
, to_read
);
177 if (bytes_read
<= 0) {
178 if (bytes_total
== 0)
184 bytes_total
+= bytes_read
;
186 to_read
-= bytes_read
;
187 } while (bytes_total
< buf_len
);
192 int FileStream::Write(IOBuffer
* buf
,
194 const CompletionCallback
& callback
) {
196 return ERR_UNEXPECTED
;
199 DCHECK(open_flags_
& base::PLATFORM_FILE_WRITE
);
200 // write(..., 0) will return 0, which indicates end-of-file.
201 DCHECK_GT(buf_len
, 0);
203 return context_
->WriteAsync(buf
, buf_len
, callback
);
206 int FileStream::WriteSync(const char* buf
, int buf_len
) {
207 base::ThreadRestrictions::AssertIOAllowed();
210 return ERR_UNEXPECTED
;
213 DCHECK(open_flags_
& base::PLATFORM_FILE_WRITE
);
214 // write(..., 0) will return 0, which indicates end-of-file.
215 DCHECK_GT(buf_len
, 0);
217 return context_
->WriteSync(buf
, buf_len
);
220 int64
FileStream::Truncate(int64 bytes
) {
221 base::ThreadRestrictions::AssertIOAllowed();
224 return ERR_UNEXPECTED
;
226 // We'd better be open for writing.
227 DCHECK(open_flags_
& base::PLATFORM_FILE_WRITE
);
229 // Seek to the position to truncate from.
230 int64 seek_position
= SeekSync(FROM_BEGIN
, bytes
);
231 if (seek_position
!= bytes
)
232 return ERR_UNEXPECTED
;
234 // And truncate the file.
235 return context_
->Truncate(bytes
);
238 int FileStream::Flush(const CompletionCallback
& callback
) {
240 return ERR_UNEXPECTED
;
242 DCHECK(open_flags_
& base::PLATFORM_FILE_WRITE
);
243 // Make sure we're async.
246 context_
->FlushAsync(callback
);
247 return ERR_IO_PENDING
;
250 int FileStream::FlushSync() {
251 base::ThreadRestrictions::AssertIOAllowed();
254 return ERR_UNEXPECTED
;
256 DCHECK(open_flags_
& base::PLATFORM_FILE_WRITE
);
257 return context_
->FlushSync();
260 void FileStream::EnableErrorStatistics() {
261 context_
->set_record_uma(true);
264 void FileStream::SetBoundNetLogSource(const BoundNetLog
& owner_bound_net_log
) {
265 if ((owner_bound_net_log
.source().id
== NetLog::Source::kInvalidId
) &&
266 (bound_net_log_
.source().id
== NetLog::Source::kInvalidId
)) {
267 // Both |BoundNetLog|s are invalid.
271 // Should never connect to itself.
272 DCHECK_NE(bound_net_log_
.source().id
, owner_bound_net_log
.source().id
);
274 bound_net_log_
.AddEvent(NetLog::TYPE_FILE_STREAM_BOUND_TO_OWNER
,
275 owner_bound_net_log
.source().ToEventParametersCallback());
277 owner_bound_net_log
.AddEvent(NetLog::TYPE_FILE_STREAM_SOURCE
,
278 bound_net_log_
.source().ToEventParametersCallback());
281 base::PlatformFile
FileStream::GetPlatformFileForTesting() {
282 return context_
->file();