OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/base/file_stream_context.h" | 5 #include "net/base/file_stream_context.h" |
6 | 6 |
7 #include "base/location.h" | 7 #include "base/location.h" |
8 #include "base/message_loop/message_loop_proxy.h" | 8 #include "base/message_loop/message_loop_proxy.h" |
9 #include "base/task_runner_util.h" | 9 #include "base/task_runner_util.h" |
10 #include "base/threading/thread_restrictions.h" | 10 #include "base/threading/thread_restrictions.h" |
(...skipping 23 matching lines...) Expand all Loading... |
34 : result(result), | 34 : result(result), |
35 os_error(os_error) { | 35 os_error(os_error) { |
36 } | 36 } |
37 | 37 |
38 // static | 38 // static |
39 FileStream::Context::IOResult FileStream::Context::IOResult::FromOSError( | 39 FileStream::Context::IOResult FileStream::Context::IOResult::FromOSError( |
40 int64 os_error) { | 40 int64 os_error) { |
41 return IOResult(MapSystemError(os_error), os_error); | 41 return IOResult(MapSystemError(os_error), os_error); |
42 } | 42 } |
43 | 43 |
44 FileStream::Context::OpenResult::OpenResult() | 44 // --------------------------------------------------------------------- |
45 : file(base::kInvalidPlatformFileValue) { | 45 |
| 46 FileStream::Context::OpenResult::OpenResult() { |
46 } | 47 } |
47 | 48 |
48 FileStream::Context::OpenResult::OpenResult(base::PlatformFile file, | 49 FileStream::Context::OpenResult::OpenResult(base::File file, |
49 IOResult error_code) | 50 IOResult error_code) |
50 : file(file), | 51 : file(file.Pass()), |
51 error_code(error_code) { | 52 error_code(error_code) { |
52 } | 53 } |
53 | 54 |
| 55 FileStream::Context::OpenResult::OpenResult(RValue other) |
| 56 : file(other.object->file.Pass()), |
| 57 error_code(other.object->error_code) { |
| 58 } |
| 59 |
| 60 FileStream::Context::OpenResult& FileStream::Context::OpenResult::operator=( |
| 61 RValue other) { |
| 62 if (this != other.object) { |
| 63 file = other.object->file.Pass(); |
| 64 error_code = other.object->error_code; |
| 65 } |
| 66 return *this; |
| 67 } |
| 68 |
| 69 // --------------------------------------------------------------------- |
| 70 |
54 void FileStream::Context::Orphan() { | 71 void FileStream::Context::Orphan() { |
55 DCHECK(!orphaned_); | 72 DCHECK(!orphaned_); |
56 | 73 |
57 orphaned_ = true; | 74 orphaned_ = true; |
58 if (file_ != base::kInvalidPlatformFileValue) | 75 if (file_.IsValid()) |
59 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN); | 76 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN); |
60 | 77 |
61 if (!async_in_progress_) { | 78 if (!async_in_progress_) { |
62 CloseAndDelete(); | 79 CloseAndDelete(); |
63 } else if (file_ != base::kInvalidPlatformFileValue) { | 80 } else if (file_.IsValid()) { |
64 CancelIo(file_); | 81 CancelIo(file_.GetPlatformFile()); |
65 } | 82 } |
66 } | 83 } |
67 | 84 |
68 void FileStream::Context::OpenAsync(const base::FilePath& path, | 85 void FileStream::Context::OpenAsync(const base::FilePath& path, |
69 int open_flags, | 86 int open_flags, |
70 const CompletionCallback& callback) { | 87 const CompletionCallback& callback) { |
71 DCHECK(!async_in_progress_); | 88 DCHECK(!async_in_progress_); |
72 | |
73 BeginOpenEvent(path); | 89 BeginOpenEvent(path); |
74 | 90 |
75 const bool posted = base::PostTaskAndReplyWithResult( | 91 bool posted = base::PostTaskAndReplyWithResult( |
76 task_runner_.get(), | 92 task_runner_.get(), |
77 FROM_HERE, | 93 FROM_HERE, |
78 base::Bind( | 94 base::Bind( |
79 &Context::OpenFileImpl, base::Unretained(this), path, open_flags), | 95 &Context::OpenFileImpl, base::Unretained(this), path, open_flags), |
80 base::Bind(&Context::OnOpenCompleted, base::Unretained(this), callback)); | 96 base::Bind(&Context::OnOpenCompleted, base::Unretained(this), callback)); |
81 DCHECK(posted); | 97 DCHECK(posted); |
82 | 98 |
83 async_in_progress_ = true; | 99 async_in_progress_ = true; |
| 100 |
| 101 // TODO(rvargas): Figure out what to do here. For POSIX, async IO is |
| 102 // implemented by doing blocking IO on another thread, so file_ is not really |
| 103 // async, but this code has sync and async paths so it has random checks to |
| 104 // figure out what mode to use. We should probably make this class async only, |
| 105 // and make consumers of sync IO use base::File. |
| 106 async_ = true; |
84 } | 107 } |
85 | 108 |
86 int FileStream::Context::OpenSync(const base::FilePath& path, int open_flags) { | 109 int FileStream::Context::OpenSync(const base::FilePath& path, int open_flags) { |
87 DCHECK(!async_in_progress_); | 110 DCHECK(!async_in_progress_); |
88 | 111 |
89 BeginOpenEvent(path); | 112 BeginOpenEvent(path); |
90 OpenResult result = OpenFileImpl(path, open_flags); | 113 OpenResult result = OpenFileImpl(path, open_flags); |
91 file_ = result.file; | 114 if (result.file.IsValid()) { |
92 if (file_ == base::kInvalidPlatformFileValue) { | 115 file_ = result.file.Pass(); |
93 ProcessOpenError(result.error_code); | |
94 } else { | |
95 // TODO(satorux): Remove this once all async clients are migrated to use | 116 // TODO(satorux): Remove this once all async clients are migrated to use |
96 // Open(). crbug.com/114783 | 117 // Open(). crbug.com/114783 |
97 if (open_flags & base::PLATFORM_FILE_ASYNC) | 118 if (open_flags & base::File::FLAG_ASYNC) |
98 OnAsyncFileOpened(); | 119 OnAsyncFileOpened(); |
| 120 } else { |
| 121 ProcessOpenError(result.error_code); |
99 } | 122 } |
100 return result.error_code.result; | 123 return result.error_code.result; |
101 } | 124 } |
102 | 125 |
103 void FileStream::Context::CloseSync() { | 126 void FileStream::Context::CloseSync() { |
104 DCHECK(!async_in_progress_); | 127 DCHECK(!async_in_progress_); |
105 if (file_ != base::kInvalidPlatformFileValue) { | 128 if (file_.IsValid()) { |
106 base::ClosePlatformFile(file_); | 129 file_.Close(); |
107 file_ = base::kInvalidPlatformFileValue; | |
108 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN); | 130 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN); |
109 } | 131 } |
110 } | 132 } |
111 | 133 |
112 void FileStream::Context::CloseAsync(const CompletionCallback& callback) { | 134 void FileStream::Context::CloseAsync(const CompletionCallback& callback) { |
113 DCHECK(!async_in_progress_); | 135 DCHECK(!async_in_progress_); |
114 const bool posted = base::PostTaskAndReplyWithResult( | 136 bool posted = base::PostTaskAndReplyWithResult( |
115 task_runner_.get(), | 137 task_runner_.get(), |
116 FROM_HERE, | 138 FROM_HERE, |
117 base::Bind(&Context::CloseFileImpl, base::Unretained(this)), | 139 base::Bind(&Context::CloseFileImpl, base::Unretained(this)), |
118 base::Bind(&Context::ProcessAsyncResult, | 140 base::Bind(&Context::ProcessAsyncResult, |
119 base::Unretained(this), | 141 base::Unretained(this), |
120 IntToInt64(callback), | 142 IntToInt64(callback), |
121 FILE_ERROR_SOURCE_CLOSE)); | 143 FILE_ERROR_SOURCE_CLOSE)); |
122 DCHECK(posted); | 144 DCHECK(posted); |
123 | 145 |
124 async_in_progress_ = true; | 146 async_in_progress_ = true; |
125 } | 147 } |
126 | 148 |
127 void FileStream::Context::SeekAsync(Whence whence, | 149 void FileStream::Context::SeekAsync(Whence whence, |
128 int64 offset, | 150 int64 offset, |
129 const Int64CompletionCallback& callback) { | 151 const Int64CompletionCallback& callback) { |
130 DCHECK(!async_in_progress_); | 152 DCHECK(!async_in_progress_); |
131 | 153 |
132 const bool posted = base::PostTaskAndReplyWithResult( | 154 bool posted = base::PostTaskAndReplyWithResult( |
133 task_runner_.get(), | 155 task_runner_.get(), |
134 FROM_HERE, | 156 FROM_HERE, |
135 base::Bind( | 157 base::Bind( |
136 &Context::SeekFileImpl, base::Unretained(this), whence, offset), | 158 &Context::SeekFileImpl, base::Unretained(this), whence, offset), |
137 base::Bind(&Context::ProcessAsyncResult, | 159 base::Bind(&Context::ProcessAsyncResult, |
138 base::Unretained(this), | 160 base::Unretained(this), |
139 callback, | 161 callback, |
140 FILE_ERROR_SOURCE_SEEK)); | 162 FILE_ERROR_SOURCE_SEEK)); |
141 DCHECK(posted); | 163 DCHECK(posted); |
142 | 164 |
143 async_in_progress_ = true; | 165 async_in_progress_ = true; |
144 } | 166 } |
145 | 167 |
146 int64 FileStream::Context::SeekSync(Whence whence, int64 offset) { | 168 int64 FileStream::Context::SeekSync(Whence whence, int64 offset) { |
147 IOResult result = SeekFileImpl(whence, offset); | 169 IOResult result = SeekFileImpl(whence, offset); |
148 RecordError(result, FILE_ERROR_SOURCE_SEEK); | 170 RecordError(result, FILE_ERROR_SOURCE_SEEK); |
149 return result.result; | 171 return result.result; |
150 } | 172 } |
151 | 173 |
152 void FileStream::Context::FlushAsync(const CompletionCallback& callback) { | 174 void FileStream::Context::FlushAsync(const CompletionCallback& callback) { |
153 DCHECK(!async_in_progress_); | 175 DCHECK(!async_in_progress_); |
154 | 176 |
155 const bool posted = base::PostTaskAndReplyWithResult( | 177 bool posted = base::PostTaskAndReplyWithResult( |
156 task_runner_.get(), | 178 task_runner_.get(), |
157 FROM_HERE, | 179 FROM_HERE, |
158 base::Bind(&Context::FlushFileImpl, base::Unretained(this)), | 180 base::Bind(&Context::FlushFileImpl, base::Unretained(this)), |
159 base::Bind(&Context::ProcessAsyncResult, | 181 base::Bind(&Context::ProcessAsyncResult, |
160 base::Unretained(this), | 182 base::Unretained(this), |
161 IntToInt64(callback), | 183 IntToInt64(callback), |
162 FILE_ERROR_SOURCE_FLUSH)); | 184 FILE_ERROR_SOURCE_FLUSH)); |
163 DCHECK(posted); | 185 DCHECK(posted); |
164 | 186 |
165 async_in_progress_ = true; | 187 async_in_progress_ = true; |
(...skipping 24 matching lines...) Expand all Loading... |
190 } | 212 } |
191 | 213 |
192 void FileStream::Context::BeginOpenEvent(const base::FilePath& path) { | 214 void FileStream::Context::BeginOpenEvent(const base::FilePath& path) { |
193 std::string file_name = path.AsUTF8Unsafe(); | 215 std::string file_name = path.AsUTF8Unsafe(); |
194 bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_OPEN, | 216 bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_OPEN, |
195 NetLog::StringCallback("file_name", &file_name)); | 217 NetLog::StringCallback("file_name", &file_name)); |
196 } | 218 } |
197 | 219 |
198 FileStream::Context::OpenResult FileStream::Context::OpenFileImpl( | 220 FileStream::Context::OpenResult FileStream::Context::OpenFileImpl( |
199 const base::FilePath& path, int open_flags) { | 221 const base::FilePath& path, int open_flags) { |
200 base::PlatformFile file; | 222 #if defined(OS_POSIX) |
| 223 // Always use blocking IO. |
| 224 open_flags &= ~base::File::FLAG_ASYNC; |
| 225 #endif |
| 226 base::File file; |
201 #if defined(OS_ANDROID) | 227 #if defined(OS_ANDROID) |
202 if (path.IsContentUri()) { | 228 if (path.IsContentUri()) { |
203 // Check that only Read flags are set. | 229 // Check that only Read flags are set. |
204 DCHECK_EQ(open_flags & ~base::PLATFORM_FILE_ASYNC, | 230 DCHECK_EQ(open_flags & ~base::File::FLAG_ASYNC, |
205 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ); | 231 base::File::FLAG_OPEN | base::File::FLAG_READ); |
206 file = base::OpenContentUriForRead(path); | 232 file = base::OpenContentUriForRead(path); |
207 } else { | 233 } else { |
208 #endif // defined(OS_ANDROID) | 234 #endif // defined(OS_ANDROID) |
209 // FileStream::Context actually closes the file asynchronously, | 235 // FileStream::Context actually closes the file asynchronously, |
210 // independently from FileStream's destructor. It can cause problems for | 236 // independently from FileStream's destructor. It can cause problems for |
211 // users wanting to delete the file right after FileStream deletion. Thus | 237 // users wanting to delete the file right after FileStream deletion. Thus |
212 // we are always adding SHARE_DELETE flag to accommodate such use case. | 238 // we are always adding SHARE_DELETE flag to accommodate such use case. |
213 open_flags |= base::PLATFORM_FILE_SHARE_DELETE; | 239 // TODO(rvargas): This sounds like a bug, as deleting the file would |
214 file = base::CreatePlatformFile(path, open_flags, NULL, NULL); | 240 // presumably happen on the wrong thread. There should be an async delete. |
| 241 open_flags |= base::File::FLAG_SHARE_DELETE; |
| 242 file.Initialize(path, open_flags); |
215 #if defined(OS_ANDROID) | 243 #if defined(OS_ANDROID) |
216 } | 244 } |
217 #endif // defined(OS_ANDROID) | 245 #endif // defined(OS_ANDROID) |
218 if (file == base::kInvalidPlatformFileValue) | 246 if (!file.IsValid()) |
219 return OpenResult(file, IOResult::FromOSError(GetLastErrno())); | 247 return OpenResult(base::File(), IOResult::FromOSError(GetLastErrno())); |
220 | 248 |
221 return OpenResult(file, IOResult(OK, 0)); | 249 return OpenResult(file.Pass(), IOResult(OK, 0)); |
| 250 } |
| 251 |
| 252 FileStream::Context::IOResult FileStream::Context::CloseFileImpl() { |
| 253 file_.Close(); |
| 254 return IOResult(OK, 0); |
222 } | 255 } |
223 | 256 |
224 void FileStream::Context::ProcessOpenError(const IOResult& error_code) { | 257 void FileStream::Context::ProcessOpenError(const IOResult& error_code) { |
225 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN); | 258 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN); |
226 RecordError(error_code, FILE_ERROR_SOURCE_OPEN); | 259 RecordError(error_code, FILE_ERROR_SOURCE_OPEN); |
227 } | 260 } |
228 | 261 |
229 void FileStream::Context::OnOpenCompleted(const CompletionCallback& callback, | 262 void FileStream::Context::OnOpenCompleted(const CompletionCallback& callback, |
230 OpenResult open_result) { | 263 OpenResult open_result) { |
231 file_ = open_result.file; | 264 if (!open_result.file.IsValid()) { |
232 if (file_ == base::kInvalidPlatformFileValue) | |
233 ProcessOpenError(open_result.error_code); | 265 ProcessOpenError(open_result.error_code); |
234 else if (!orphaned_) | 266 } else if (!orphaned_) { |
| 267 file_ = open_result.file.Pass(); |
235 OnAsyncFileOpened(); | 268 OnAsyncFileOpened(); |
| 269 } |
236 OnAsyncCompleted(IntToInt64(callback), open_result.error_code.result); | 270 OnAsyncCompleted(IntToInt64(callback), open_result.error_code.result); |
237 } | 271 } |
238 | 272 |
239 void FileStream::Context::CloseAndDelete() { | 273 void FileStream::Context::CloseAndDelete() { |
240 DCHECK(!async_in_progress_); | 274 DCHECK(!async_in_progress_); |
241 | 275 |
242 if (file_ == base::kInvalidPlatformFileValue) { | 276 if (file_.IsValid()) { |
243 delete this; | 277 bool posted = task_runner_.get()->PostTaskAndReply( |
244 } else { | |
245 const bool posted = task_runner_->PostTaskAndReply( | |
246 FROM_HERE, | 278 FROM_HERE, |
247 base::Bind(base::IgnoreResult(&base::ClosePlatformFile), file_), | 279 base::Bind(base::IgnoreResult(&Context::CloseFileImpl), |
| 280 base::Unretained(this)), |
248 base::Bind(&Context::OnCloseCompleted, base::Unretained(this))); | 281 base::Bind(&Context::OnCloseCompleted, base::Unretained(this))); |
249 DCHECK(posted); | 282 DCHECK(posted); |
250 file_ = base::kInvalidPlatformFileValue; | 283 } else { |
| 284 delete this; |
251 } | 285 } |
252 } | 286 } |
253 | 287 |
254 void FileStream::Context::OnCloseCompleted() { | 288 void FileStream::Context::OnCloseCompleted() { |
255 delete this; | 289 delete this; |
256 } | 290 } |
257 | 291 |
258 Int64CompletionCallback FileStream::Context::IntToInt64( | 292 Int64CompletionCallback FileStream::Context::IntToInt64( |
259 const CompletionCallback& callback) { | 293 const CompletionCallback& callback) { |
260 return base::Bind(&CallInt64ToInt, callback); | 294 return base::Bind(&CallInt64ToInt, callback); |
(...skipping 15 matching lines...) Expand all Loading... |
276 // operation is in progress. | 310 // operation is in progress. |
277 async_in_progress_ = false; | 311 async_in_progress_ = false; |
278 if (orphaned_) | 312 if (orphaned_) |
279 CloseAndDelete(); | 313 CloseAndDelete(); |
280 else | 314 else |
281 callback.Run(result); | 315 callback.Run(result); |
282 } | 316 } |
283 | 317 |
284 } // namespace net | 318 } // namespace net |
285 | 319 |
OLD | NEW |