| 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 |