OLD | NEW |
| (Empty) |
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_context.h" | |
6 | |
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" | |
16 | |
17 #if defined(OS_ANDROID) | |
18 #include "base/android/content_uri_utils.h" | |
19 #endif | |
20 | |
21 namespace net { | |
22 | |
23 namespace { | |
24 | |
25 void CallInt64ToInt(const CompletionCallback& callback, int64 result) { | |
26 callback.Run(static_cast<int>(result)); | |
27 } | |
28 | |
29 } // namespace | |
30 | |
31 FileStream::Context::IOResult::IOResult() | |
32 : result(OK), | |
33 os_error(0) { | |
34 } | |
35 | |
36 FileStream::Context::IOResult::IOResult(int64 result, | |
37 logging::SystemErrorCode os_error) | |
38 : result(result), | |
39 os_error(os_error) { | |
40 } | |
41 | |
42 // static | |
43 FileStream::Context::IOResult FileStream::Context::IOResult::FromOSError( | |
44 logging::SystemErrorCode os_error) { | |
45 return IOResult(MapSystemError(os_error), os_error); | |
46 } | |
47 | |
48 // --------------------------------------------------------------------- | |
49 | |
50 FileStream::Context::OpenResult::OpenResult() { | |
51 } | |
52 | |
53 FileStream::Context::OpenResult::OpenResult(base::File file, | |
54 IOResult error_code) | |
55 : file(file.Pass()), | |
56 error_code(error_code) { | |
57 } | |
58 | |
59 FileStream::Context::OpenResult::OpenResult(RValue other) | |
60 : file(other.object->file.Pass()), | |
61 error_code(other.object->error_code) { | |
62 } | |
63 | |
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; | |
69 } | |
70 return *this; | |
71 } | |
72 | |
73 // --------------------------------------------------------------------- | |
74 | |
75 void FileStream::Context::Orphan() { | |
76 DCHECK(!orphaned_); | |
77 | |
78 orphaned_ = true; | |
79 | |
80 if (!async_in_progress_) { | |
81 CloseAndDelete(); | |
82 } else if (file_.IsValid()) { | |
83 #if defined(OS_WIN) | |
84 CancelIo(file_.GetPlatformFile()); | |
85 #endif | |
86 } | |
87 } | |
88 | |
89 void FileStream::Context::Open(const base::FilePath& path, | |
90 int open_flags, | |
91 const CompletionCallback& callback) { | |
92 DCHECK(!async_in_progress_); | |
93 | |
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); | |
101 | |
102 async_in_progress_ = true; | |
103 } | |
104 | |
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); | |
115 | |
116 async_in_progress_ = true; | |
117 } | |
118 | |
119 void FileStream::Context::Seek(base::File::Whence whence, | |
120 int64 offset, | |
121 const Int64CompletionCallback& callback) { | |
122 DCHECK(!async_in_progress_); | |
123 | |
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); | |
133 | |
134 async_in_progress_ = true; | |
135 } | |
136 | |
137 void FileStream::Context::Flush(const CompletionCallback& callback) { | |
138 DCHECK(!async_in_progress_); | |
139 | |
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); | |
148 | |
149 async_in_progress_ = true; | |
150 } | |
151 | |
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")); | |
158 | |
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) | |
181 } | |
182 #endif // defined(OS_ANDROID) | |
183 if (!file.IsValid()) | |
184 return OpenResult(base::File(), | |
185 IOResult::FromOSError(logging::GetLastSystemErrorCode())); | |
186 | |
187 return OpenResult(file.Pass(), IOResult(OK, 0)); | |
188 } | |
189 | |
190 FileStream::Context::IOResult FileStream::Context::CloseFileImpl() { | |
191 file_.Close(); | |
192 return IOResult(OK, 0); | |
193 } | |
194 | |
195 FileStream::Context::IOResult FileStream::Context::FlushFileImpl() { | |
196 if (file_.Flush()) | |
197 return IOResult(OK, 0); | |
198 | |
199 return IOResult::FromOSError(logging::GetLastSystemErrorCode()); | |
200 } | |
201 | |
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")); | |
210 | |
211 OnFileOpened(); | |
212 } | |
213 | |
214 OnAsyncCompleted(IntToInt64(callback), open_result.error_code); | |
215 } | |
216 | |
217 void FileStream::Context::CloseAndDelete() { | |
218 // TODO(ananta) | |
219 // Replace this CHECK with a DCHECK once we figure out the root cause of | |
220 // http://crbug.com/455066 | |
221 CHECK(!async_in_progress_); | |
222 | |
223 if (file_.IsValid()) { | |
224 bool posted = task_runner_.get()->PostTask( | |
225 FROM_HERE, | |
226 base::Bind(base::IgnoreResult(&Context::CloseFileImpl), | |
227 base::Owned(this))); | |
228 DCHECK(posted); | |
229 } else { | |
230 delete this; | |
231 } | |
232 } | |
233 | |
234 Int64CompletionCallback FileStream::Context::IntToInt64( | |
235 const CompletionCallback& callback) { | |
236 return base::Bind(&CallInt64ToInt, callback); | |
237 } | |
238 | |
239 void FileStream::Context::OnAsyncCompleted( | |
240 const Int64CompletionCallback& callback, | |
241 const IOResult& result) { | |
242 // Reset this before Run() as Run() may issue a new async operation. Also it | |
243 // should be reset before Close() because it shouldn't run if any async | |
244 // operation is in progress. | |
245 async_in_progress_ = false; | |
246 if (orphaned_) | |
247 CloseAndDelete(); | |
248 else | |
249 callback.Run(result.result); | |
250 } | |
251 | |
252 } // namespace net | |
OLD | NEW |