Roll src/third_party/WebKit 8121bc6:918aba1 (svn 188871:188878)
[chromium-blink-merge.git] / net / base / file_stream_context.cc
blob5acaab6eb63bd25078a7ced3493a415c82f103bd
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_context.h"
7 #include "base/files/file_path.h"
8 #include "base/location.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/profiler/scoped_tracker.h"
11 #include "base/task_runner.h"
12 #include "base/task_runner_util.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "base/values.h"
15 #include "net/base/net_errors.h"
17 #if defined(OS_ANDROID)
18 #include "base/android/content_uri_utils.h"
19 #endif
21 namespace net {
23 namespace {
25 void CallInt64ToInt(const CompletionCallback& callback, int64 result) {
26 callback.Run(static_cast<int>(result));
29 } // namespace
31 FileStream::Context::IOResult::IOResult()
32 : result(OK),
33 os_error(0) {
36 FileStream::Context::IOResult::IOResult(int64 result,
37 logging::SystemErrorCode os_error)
38 : result(result),
39 os_error(os_error) {
42 // static
43 FileStream::Context::IOResult FileStream::Context::IOResult::FromOSError(
44 logging::SystemErrorCode os_error) {
45 return IOResult(MapSystemError(os_error), os_error);
48 // ---------------------------------------------------------------------
50 FileStream::Context::OpenResult::OpenResult() {
53 FileStream::Context::OpenResult::OpenResult(base::File file,
54 IOResult error_code)
55 : file(file.Pass()),
56 error_code(error_code) {
59 FileStream::Context::OpenResult::OpenResult(RValue other)
60 : file(other.object->file.Pass()),
61 error_code(other.object->error_code) {
64 FileStream::Context::OpenResult& FileStream::Context::OpenResult::operator=(
65 RValue other) {
66 if (this != other.object) {
67 file = other.object->file.Pass();
68 error_code = other.object->error_code;
70 return *this;
73 // ---------------------------------------------------------------------
75 void FileStream::Context::Orphan() {
76 DCHECK(!orphaned_);
78 orphaned_ = true;
80 if (!async_in_progress_) {
81 CloseAndDelete();
82 } else if (file_.IsValid()) {
83 #if defined(OS_WIN)
84 CancelIo(file_.GetPlatformFile());
85 #endif
89 void FileStream::Context::Open(const base::FilePath& path,
90 int open_flags,
91 const CompletionCallback& callback) {
92 DCHECK(!async_in_progress_);
94 bool posted = base::PostTaskAndReplyWithResult(
95 task_runner_.get(),
96 FROM_HERE,
97 base::Bind(
98 &Context::OpenFileImpl, base::Unretained(this), path, open_flags),
99 base::Bind(&Context::OnOpenCompleted, base::Unretained(this), callback));
100 DCHECK(posted);
102 async_in_progress_ = true;
105 void FileStream::Context::Close(const CompletionCallback& callback) {
106 DCHECK(!async_in_progress_);
107 bool posted = base::PostTaskAndReplyWithResult(
108 task_runner_.get(),
109 FROM_HERE,
110 base::Bind(&Context::CloseFileImpl, base::Unretained(this)),
111 base::Bind(&Context::OnAsyncCompleted,
112 base::Unretained(this),
113 IntToInt64(callback)));
114 DCHECK(posted);
116 async_in_progress_ = true;
119 void FileStream::Context::Seek(base::File::Whence whence,
120 int64 offset,
121 const Int64CompletionCallback& callback) {
122 DCHECK(!async_in_progress_);
124 bool posted = base::PostTaskAndReplyWithResult(
125 task_runner_.get(),
126 FROM_HERE,
127 base::Bind(
128 &Context::SeekFileImpl, base::Unretained(this), whence, offset),
129 base::Bind(&Context::OnAsyncCompleted,
130 base::Unretained(this),
131 callback));
132 DCHECK(posted);
134 async_in_progress_ = true;
137 void FileStream::Context::Flush(const CompletionCallback& callback) {
138 DCHECK(!async_in_progress_);
140 bool posted = base::PostTaskAndReplyWithResult(
141 task_runner_.get(),
142 FROM_HERE,
143 base::Bind(&Context::FlushFileImpl, base::Unretained(this)),
144 base::Bind(&Context::OnAsyncCompleted,
145 base::Unretained(this),
146 IntToInt64(callback)));
147 DCHECK(posted);
149 async_in_progress_ = true;
152 FileStream::Context::OpenResult FileStream::Context::OpenFileImpl(
153 const base::FilePath& path, int open_flags) {
154 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
155 tracked_objects::ScopedTracker tracking_profile(
156 FROM_HERE_WITH_EXPLICIT_FUNCTION(
157 "423948 FileStream::Context::OpenFileImpl"));
159 #if defined(OS_POSIX)
160 // Always use blocking IO.
161 open_flags &= ~base::File::FLAG_ASYNC;
162 #endif
163 base::File file;
164 #if defined(OS_ANDROID)
165 if (path.IsContentUri()) {
166 // Check that only Read flags are set.
167 DCHECK_EQ(open_flags & ~base::File::FLAG_ASYNC,
168 base::File::FLAG_OPEN | base::File::FLAG_READ);
169 file = base::OpenContentUriForRead(path);
170 } else {
171 #endif // defined(OS_ANDROID)
172 // FileStream::Context actually closes the file asynchronously,
173 // independently from FileStream's destructor. It can cause problems for
174 // users wanting to delete the file right after FileStream deletion. Thus
175 // we are always adding SHARE_DELETE flag to accommodate such use case.
176 // TODO(rvargas): This sounds like a bug, as deleting the file would
177 // presumably happen on the wrong thread. There should be an async delete.
178 open_flags |= base::File::FLAG_SHARE_DELETE;
179 file.Initialize(path, open_flags);
180 #if defined(OS_ANDROID)
182 #endif // defined(OS_ANDROID)
183 if (!file.IsValid())
184 return OpenResult(base::File(),
185 IOResult::FromOSError(logging::GetLastSystemErrorCode()));
187 return OpenResult(file.Pass(), IOResult(OK, 0));
190 FileStream::Context::IOResult FileStream::Context::CloseFileImpl() {
191 file_.Close();
192 return IOResult(OK, 0);
195 FileStream::Context::IOResult FileStream::Context::FlushFileImpl() {
196 if (file_.Flush())
197 return IOResult(OK, 0);
199 return IOResult::FromOSError(logging::GetLastSystemErrorCode());
202 void FileStream::Context::OnOpenCompleted(const CompletionCallback& callback,
203 OpenResult open_result) {
204 file_ = open_result.file.Pass();
205 if (file_.IsValid() && !orphaned_) {
206 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
207 tracked_objects::ScopedTracker tracking_profile(
208 FROM_HERE_WITH_EXPLICIT_FUNCTION(
209 "423948 FileStream::Context::OnOpenCompleted"));
211 OnFileOpened();
214 OnAsyncCompleted(IntToInt64(callback), open_result.error_code);
217 void FileStream::Context::CloseAndDelete() {
218 DCHECK(!async_in_progress_);
220 if (file_.IsValid()) {
221 bool posted = task_runner_.get()->PostTask(
222 FROM_HERE,
223 base::Bind(base::IgnoreResult(&Context::CloseFileImpl),
224 base::Owned(this)));
225 DCHECK(posted);
226 } else {
227 delete this;
231 Int64CompletionCallback FileStream::Context::IntToInt64(
232 const CompletionCallback& callback) {
233 return base::Bind(&CallInt64ToInt, callback);
236 void FileStream::Context::OnAsyncCompleted(
237 const Int64CompletionCallback& callback,
238 const IOResult& result) {
239 // Reset this before Run() as Run() may issue a new async operation. Also it
240 // should be reset before Close() because it shouldn't run if any async
241 // operation is in progress.
242 async_in_progress_ = false;
243 if (orphaned_)
244 CloseAndDelete();
245 else
246 callback.Run(result.result);
249 } // namespace net