Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / base / file_stream_context.cc
blob3ddf4bbf508ea596c6be81c0eb6b4e70a807149f
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/profiler/scoped_tracker.h"
10 #include "base/task_runner.h"
11 #include "base/task_runner_util.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "base/values.h"
14 #include "net/base/net_errors.h"
16 #if defined(OS_ANDROID)
17 #include "base/android/content_uri_utils.h"
18 #endif
20 namespace net {
22 namespace {
24 void CallInt64ToInt(const CompletionCallback& callback, int64_t result) {
25 callback.Run(static_cast<int>(result));
28 } // namespace
30 FileStream::Context::IOResult::IOResult()
31 : result(OK),
32 os_error(0) {
35 FileStream::Context::IOResult::IOResult(int64_t result,
36 logging::SystemErrorCode os_error)
37 : result(result), os_error(os_error) {
40 // static
41 FileStream::Context::IOResult FileStream::Context::IOResult::FromOSError(
42 logging::SystemErrorCode os_error) {
43 return IOResult(MapSystemError(os_error), os_error);
46 // ---------------------------------------------------------------------
48 FileStream::Context::OpenResult::OpenResult() {
51 FileStream::Context::OpenResult::OpenResult(base::File file,
52 IOResult error_code)
53 : file(file.Pass()),
54 error_code(error_code) {
57 FileStream::Context::OpenResult::OpenResult(RValue other)
58 : file(other.object->file.Pass()),
59 error_code(other.object->error_code) {
62 FileStream::Context::OpenResult& FileStream::Context::OpenResult::operator=(
63 RValue other) {
64 if (this != other.object) {
65 file = other.object->file.Pass();
66 error_code = other.object->error_code;
68 return *this;
71 // ---------------------------------------------------------------------
73 void FileStream::Context::Orphan() {
74 DCHECK(!orphaned_);
76 orphaned_ = true;
78 if (!async_in_progress_) {
79 CloseAndDelete();
80 } else if (file_.IsValid()) {
81 #if defined(OS_WIN)
82 CancelIo(file_.GetPlatformFile());
83 #endif
87 void FileStream::Context::Open(const base::FilePath& path,
88 int open_flags,
89 const CompletionCallback& callback) {
90 DCHECK(!async_in_progress_);
92 bool posted = base::PostTaskAndReplyWithResult(
93 task_runner_.get(),
94 FROM_HERE,
95 base::Bind(
96 &Context::OpenFileImpl, base::Unretained(this), path, open_flags),
97 base::Bind(&Context::OnOpenCompleted, base::Unretained(this), callback));
98 DCHECK(posted);
100 async_in_progress_ = true;
103 void FileStream::Context::Close(const CompletionCallback& callback) {
104 DCHECK(!async_in_progress_);
105 bool posted = base::PostTaskAndReplyWithResult(
106 task_runner_.get(),
107 FROM_HERE,
108 base::Bind(&Context::CloseFileImpl, base::Unretained(this)),
109 base::Bind(&Context::OnAsyncCompleted,
110 base::Unretained(this),
111 IntToInt64(callback)));
112 DCHECK(posted);
114 async_in_progress_ = true;
117 void FileStream::Context::Seek(int64_t offset,
118 const Int64CompletionCallback& callback) {
119 DCHECK(!async_in_progress_);
121 bool posted = base::PostTaskAndReplyWithResult(
122 task_runner_.get(), FROM_HERE,
123 base::Bind(&Context::SeekFileImpl, base::Unretained(this), offset),
124 base::Bind(&Context::OnAsyncCompleted, base::Unretained(this), callback));
125 DCHECK(posted);
127 async_in_progress_ = true;
130 void FileStream::Context::Flush(const CompletionCallback& callback) {
131 DCHECK(!async_in_progress_);
133 bool posted = base::PostTaskAndReplyWithResult(
134 task_runner_.get(),
135 FROM_HERE,
136 base::Bind(&Context::FlushFileImpl, base::Unretained(this)),
137 base::Bind(&Context::OnAsyncCompleted,
138 base::Unretained(this),
139 IntToInt64(callback)));
140 DCHECK(posted);
142 async_in_progress_ = true;
145 bool FileStream::Context::IsOpen() const {
146 return file_.IsValid();
149 FileStream::Context::OpenResult FileStream::Context::OpenFileImpl(
150 const base::FilePath& path, int open_flags) {
151 #if defined(OS_POSIX)
152 // Always use blocking IO.
153 open_flags &= ~base::File::FLAG_ASYNC;
154 #endif
155 base::File file;
156 #if defined(OS_ANDROID)
157 if (path.IsContentUri()) {
158 // Check that only Read flags are set.
159 DCHECK_EQ(open_flags & ~base::File::FLAG_ASYNC,
160 base::File::FLAG_OPEN | base::File::FLAG_READ);
161 file = base::OpenContentUriForRead(path);
162 } else {
163 #endif // defined(OS_ANDROID)
164 // FileStream::Context actually closes the file asynchronously,
165 // independently from FileStream's destructor. It can cause problems for
166 // users wanting to delete the file right after FileStream deletion. Thus
167 // we are always adding SHARE_DELETE flag to accommodate such use case.
168 // TODO(rvargas): This sounds like a bug, as deleting the file would
169 // presumably happen on the wrong thread. There should be an async delete.
170 open_flags |= base::File::FLAG_SHARE_DELETE;
171 file.Initialize(path, open_flags);
172 #if defined(OS_ANDROID)
174 #endif // defined(OS_ANDROID)
175 if (!file.IsValid())
176 return OpenResult(base::File(),
177 IOResult::FromOSError(logging::GetLastSystemErrorCode()));
179 return OpenResult(file.Pass(), IOResult(OK, 0));
182 FileStream::Context::IOResult FileStream::Context::CloseFileImpl() {
183 file_.Close();
184 return IOResult(OK, 0);
187 FileStream::Context::IOResult FileStream::Context::FlushFileImpl() {
188 if (file_.Flush())
189 return IOResult(OK, 0);
191 return IOResult::FromOSError(logging::GetLastSystemErrorCode());
194 void FileStream::Context::OnOpenCompleted(const CompletionCallback& callback,
195 OpenResult open_result) {
196 file_ = open_result.file.Pass();
197 if (file_.IsValid() && !orphaned_)
198 OnFileOpened();
200 OnAsyncCompleted(IntToInt64(callback), open_result.error_code);
203 void FileStream::Context::CloseAndDelete() {
204 // TODO(ananta)
205 // Replace this CHECK with a DCHECK once we figure out the root cause of
206 // http://crbug.com/455066
207 CHECK(!async_in_progress_);
209 if (file_.IsValid()) {
210 bool posted = task_runner_.get()->PostTask(
211 FROM_HERE,
212 base::Bind(base::IgnoreResult(&Context::CloseFileImpl),
213 base::Owned(this)));
214 DCHECK(posted);
215 } else {
216 delete this;
220 Int64CompletionCallback FileStream::Context::IntToInt64(
221 const CompletionCallback& callback) {
222 return base::Bind(&CallInt64ToInt, callback);
225 void FileStream::Context::OnAsyncCompleted(
226 const Int64CompletionCallback& callback,
227 const IOResult& result) {
228 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
229 tracked_objects::ScopedTracker tracking_profile(
230 FROM_HERE_WITH_EXPLICIT_FUNCTION(
231 "477117 FileStream::Context::OnAsyncCompleted"));
232 // Reset this before Run() as Run() may issue a new async operation. Also it
233 // should be reset before Close() because it shouldn't run if any async
234 // operation is in progress.
235 async_in_progress_ = false;
236 if (orphaned_)
237 CloseAndDelete();
238 else
239 callback.Run(result.result);
242 } // namespace net