Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: net/base/file_stream_context.cc

Issue 12320003: Fix net::FileStream to handle POSIX errors correctly. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/base/file_stream_context.h ('k') | net/base/file_stream_context_posix.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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_proxy.h" 8 #include "base/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"
11 #include "base/threading/worker_pool.h" 11 #include "base/threading/worker_pool.h"
12 #include "net/base/file_stream_net_log_parameters.h" 12 #include "net/base/file_stream_net_log_parameters.h"
13 #include "net/base/net_errors.h" 13 #include "net/base/net_errors.h"
14 14
15 namespace { 15 namespace {
16 16
17 void CallInt64ToInt(const net::CompletionCallback& callback, int64 result) { 17 void CallInt64ToInt(const net::CompletionCallback& callback, int64 result) {
18 callback.Run(static_cast<int>(result)); 18 callback.Run(static_cast<int>(result));
19 } 19 }
20 20
21 } 21 }
22 22
23 namespace net { 23 namespace net {
24 24
25 FileStream::Context::IOResult::IOResult()
26 : result(OK),
27 os_error(0) {
28 }
29
30 FileStream::Context::IOResult::IOResult(int64 result, int os_error)
31 : result(result),
32 os_error(os_error) {
33 }
34
35 // static
36 FileStream::Context::IOResult FileStream::Context::IOResult::FromOSError(
37 int64 os_error) {
38 return IOResult(MapSystemError(os_error), os_error);
39 }
40
41 FileStream::Context::OpenResult::OpenResult()
42 : file(base::kInvalidPlatformFileValue) {
43 }
44
45 FileStream::Context::OpenResult::OpenResult(base::PlatformFile file,
46 IOResult error_code)
47 : file(file),
48 error_code(error_code) {
49 }
50
25 void FileStream::Context::Orphan() { 51 void FileStream::Context::Orphan() {
26 DCHECK(!orphaned_); 52 DCHECK(!orphaned_);
27 53
28 orphaned_ = true; 54 orphaned_ = true;
29 if (file_ != base::kInvalidPlatformFileValue) 55 if (file_ != base::kInvalidPlatformFileValue)
30 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN); 56 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN);
31 57
32 if (!async_in_progress_) { 58 if (!async_in_progress_) {
33 CloseAndDelete(); 59 CloseAndDelete();
34 } else if (file_ != base::kInvalidPlatformFileValue) { 60 } else if (file_ != base::kInvalidPlatformFileValue) {
(...skipping 20 matching lines...) Expand all
55 async_in_progress_ = true; 81 async_in_progress_ = true;
56 } 82 }
57 83
58 int FileStream::Context::OpenSync(const base::FilePath& path, int open_flags) { 84 int FileStream::Context::OpenSync(const base::FilePath& path, int open_flags) {
59 DCHECK(!async_in_progress_); 85 DCHECK(!async_in_progress_);
60 86
61 BeginOpenEvent(path); 87 BeginOpenEvent(path);
62 OpenResult result = OpenFileImpl(path, open_flags); 88 OpenResult result = OpenFileImpl(path, open_flags);
63 file_ = result.file; 89 file_ = result.file;
64 if (file_ == base::kInvalidPlatformFileValue) { 90 if (file_ == base::kInvalidPlatformFileValue) {
65 result.error_code = ProcessOpenError(result.error_code); 91 ProcessOpenError(result.error_code);
66 } else { 92 } else {
67 // TODO(satorux): Remove this once all async clients are migrated to use 93 // TODO(satorux): Remove this once all async clients are migrated to use
68 // Open(). crbug.com/114783 94 // Open(). crbug.com/114783
69 if (open_flags & base::PLATFORM_FILE_ASYNC) 95 if (open_flags & base::PLATFORM_FILE_ASYNC)
70 OnAsyncFileOpened(); 96 OnAsyncFileOpened();
71 } 97 }
72 return result.error_code; 98 return result.error_code.result;
73 } 99 }
74 100
75 void FileStream::Context::CloseSync() { 101 void FileStream::Context::CloseSync() {
76 DCHECK(!async_in_progress_); 102 DCHECK(!async_in_progress_);
77 if (file_ != base::kInvalidPlatformFileValue) { 103 if (file_ != base::kInvalidPlatformFileValue) {
78 base::ClosePlatformFile(file_); 104 base::ClosePlatformFile(file_);
79 file_ = base::kInvalidPlatformFileValue; 105 file_ = base::kInvalidPlatformFileValue;
80 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN); 106 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN);
81 } 107 }
82 } 108 }
83 109
84 void FileStream::Context::SeekAsync(Whence whence, 110 void FileStream::Context::SeekAsync(Whence whence,
85 int64 offset, 111 int64 offset,
86 const Int64CompletionCallback& callback) { 112 const Int64CompletionCallback& callback) {
87 DCHECK(!async_in_progress_); 113 DCHECK(!async_in_progress_);
88 114
89 const bool posted = base::PostTaskAndReplyWithResult( 115 const bool posted = base::PostTaskAndReplyWithResult(
90 base::WorkerPool::GetTaskRunner(true /* task is slow */), 116 base::WorkerPool::GetTaskRunner(true /* task is slow */),
91 FROM_HERE, 117 FROM_HERE,
92 base::Bind(&Context::SeekFileImpl, 118 base::Bind(&Context::SeekFileImpl,
93 base::Unretained(this), whence, offset), 119 base::Unretained(this), whence, offset),
94 base::Bind(&Context::ProcessAsyncResult, 120 base::Bind(&Context::ProcessAsyncResult,
95 base::Unretained(this), callback, FILE_ERROR_SOURCE_SEEK)); 121 base::Unretained(this), callback, FILE_ERROR_SOURCE_SEEK));
96 DCHECK(posted); 122 DCHECK(posted);
97 123
98 async_in_progress_ = true; 124 async_in_progress_ = true;
99 } 125 }
100 126
101 int64 FileStream::Context::SeekSync(Whence whence, int64 offset) { 127 int64 FileStream::Context::SeekSync(Whence whence, int64 offset) {
102 int64 result = SeekFileImpl(whence, offset); 128 IOResult result = SeekFileImpl(whence, offset);
103 CheckForIOError(&result, FILE_ERROR_SOURCE_SEEK); 129 RecordError(result, FILE_ERROR_SOURCE_SEEK);
104 return result; 130 return result.result;
105 } 131 }
106 132
107 void FileStream::Context::FlushAsync(const CompletionCallback& callback) { 133 void FileStream::Context::FlushAsync(const CompletionCallback& callback) {
108 DCHECK(!async_in_progress_); 134 DCHECK(!async_in_progress_);
109 135
110 const bool posted = base::PostTaskAndReplyWithResult( 136 const bool posted = base::PostTaskAndReplyWithResult(
111 base::WorkerPool::GetTaskRunner(true /* task is slow */), 137 base::WorkerPool::GetTaskRunner(true /* task is slow */),
112 FROM_HERE, 138 FROM_HERE,
113 base::Bind(&Context::FlushFileImpl, 139 base::Bind(&Context::FlushFileImpl,
114 base::Unretained(this)), 140 base::Unretained(this)),
115 base::Bind(&Context::ProcessAsyncResult, 141 base::Bind(&Context::ProcessAsyncResult,
116 base::Unretained(this), IntToInt64(callback), 142 base::Unretained(this), IntToInt64(callback),
117 FILE_ERROR_SOURCE_FLUSH)); 143 FILE_ERROR_SOURCE_FLUSH));
118 DCHECK(posted); 144 DCHECK(posted);
119 145
120 async_in_progress_ = true; 146 async_in_progress_ = true;
121 } 147 }
122 148
123 int FileStream::Context::FlushSync() { 149 int FileStream::Context::FlushSync() {
124 int64 result = FlushFileImpl(); 150 IOResult result = FlushFileImpl();
125 CheckForIOError(&result, FILE_ERROR_SOURCE_FLUSH); 151 RecordError(result, FILE_ERROR_SOURCE_FLUSH);
126 return result; 152 return result.result;
127 } 153 }
128 154
129 int FileStream::Context::RecordAndMapError(int error, 155 void FileStream::Context::RecordError(const IOResult& result,
130 FileErrorSource source) const { 156 FileErrorSource source) const {
157 if (result.result >= 0) {
158 // |result| is not an error.
159 return;
160 }
161
131 // The following check is against incorrect use or bug. File descriptor 162 // The following check is against incorrect use or bug. File descriptor
132 // shouldn't ever be closed outside of FileStream while it still tries to do 163 // shouldn't ever be closed outside of FileStream while it still tries to do
133 // something with it. 164 // something with it.
134 DCHECK(error != ERROR_BAD_FILE); 165 DCHECK_NE(result.result, ERR_INVALID_HANDLE);
135 Error net_error = MapSystemError(error);
136 166
137 if (!orphaned_) { 167 if (!orphaned_) {
138 bound_net_log_.AddEvent(NetLog::TYPE_FILE_STREAM_ERROR, 168 bound_net_log_.AddEvent(
139 base::Bind(&NetLogFileStreamErrorCallback, 169 NetLog::TYPE_FILE_STREAM_ERROR,
140 source, error, net_error)); 170 base::Bind(&NetLogFileStreamErrorCallback,
171 source, result.os_error,
172 static_cast<net::Error>(result.result)));
141 } 173 }
142 RecordFileError(error, source, record_uma_); 174
143 return net_error; 175 RecordFileError(result.os_error, source, record_uma_);
144 } 176 }
145 177
146 void FileStream::Context::BeginOpenEvent(const base::FilePath& path) { 178 void FileStream::Context::BeginOpenEvent(const base::FilePath& path) {
147 std::string file_name = path.AsUTF8Unsafe(); 179 std::string file_name = path.AsUTF8Unsafe();
148 bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_OPEN, 180 bound_net_log_.BeginEvent(NetLog::TYPE_FILE_STREAM_OPEN,
149 NetLog::StringCallback("file_name", &file_name)); 181 NetLog::StringCallback("file_name", &file_name));
150 } 182 }
151 183
152 FileStream::Context::OpenResult FileStream::Context::OpenFileImpl( 184 FileStream::Context::OpenResult FileStream::Context::OpenFileImpl(
153 const base::FilePath& path, int open_flags) { 185 const base::FilePath& path, int open_flags) {
154 // FileStream::Context actually closes the file asynchronously, independently 186 // FileStream::Context actually closes the file asynchronously, independently
155 // from FileStream's destructor. It can cause problems for users wanting to 187 // from FileStream's destructor. It can cause problems for users wanting to
156 // delete the file right after FileStream deletion. Thus we are always 188 // delete the file right after FileStream deletion. Thus we are always
157 // adding SHARE_DELETE flag to accommodate such use case. 189 // adding SHARE_DELETE flag to accommodate such use case.
158 open_flags |= base::PLATFORM_FILE_SHARE_DELETE; 190 open_flags |= base::PLATFORM_FILE_SHARE_DELETE;
159 OpenResult result; 191 base::PlatformFile file =
160 result.error_code = OK; 192 base::CreatePlatformFile(path, open_flags, NULL, NULL);
161 result.file = base::CreatePlatformFile(path, open_flags, NULL, NULL); 193 if (file == base::kInvalidPlatformFileValue)
162 if (result.file == base::kInvalidPlatformFileValue) 194 return OpenResult(file, IOResult::FromOSError(GetLastErrno()));
163 result.error_code = GetLastErrno();
164 195
165 return result; 196 return OpenResult(file, IOResult(OK, 0));
166 } 197 }
167 198
168 int FileStream::Context::ProcessOpenError(int error_code) { 199 void FileStream::Context::ProcessOpenError(const IOResult& error_code) {
169 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN); 200 bound_net_log_.EndEvent(NetLog::TYPE_FILE_STREAM_OPEN);
170 return RecordAndMapError(error_code, FILE_ERROR_SOURCE_OPEN); 201 RecordError(error_code, FILE_ERROR_SOURCE_OPEN);
171 } 202 }
172 203
173 void FileStream::Context::OnOpenCompleted(const CompletionCallback& callback, 204 void FileStream::Context::OnOpenCompleted(const CompletionCallback& callback,
174 OpenResult result) { 205 OpenResult open_result) {
175 file_ = result.file; 206 file_ = open_result.file;
176 if (file_ == base::kInvalidPlatformFileValue) 207 if (file_ == base::kInvalidPlatformFileValue)
177 result.error_code = ProcessOpenError(result.error_code); 208 ProcessOpenError(open_result.error_code);
178 else if (!orphaned_) 209 else if (!orphaned_)
179 OnAsyncFileOpened(); 210 OnAsyncFileOpened();
180 OnAsyncCompleted(IntToInt64(callback), result.error_code); 211 OnAsyncCompleted(IntToInt64(callback), open_result.error_code.result);
181 } 212 }
182 213
183 void FileStream::Context::CloseAndDelete() { 214 void FileStream::Context::CloseAndDelete() {
184 DCHECK(!async_in_progress_); 215 DCHECK(!async_in_progress_);
185 216
186 if (file_ == base::kInvalidPlatformFileValue) { 217 if (file_ == base::kInvalidPlatformFileValue) {
187 delete this; 218 delete this;
188 } else { 219 } else {
189 const bool posted = base::WorkerPool::PostTaskAndReply( 220 const bool posted = base::WorkerPool::PostTaskAndReply(
190 FROM_HERE, 221 FROM_HERE,
191 base::Bind(base::IgnoreResult(&base::ClosePlatformFile), file_), 222 base::Bind(base::IgnoreResult(&base::ClosePlatformFile), file_),
192 base::Bind(&Context::OnCloseCompleted, base::Unretained(this)), 223 base::Bind(&Context::OnCloseCompleted, base::Unretained(this)),
193 true /* task_is_slow */); 224 true /* task_is_slow */);
194 DCHECK(posted); 225 DCHECK(posted);
195 file_ = base::kInvalidPlatformFileValue; 226 file_ = base::kInvalidPlatformFileValue;
196 } 227 }
197 } 228 }
198 229
199 void FileStream::Context::OnCloseCompleted() { 230 void FileStream::Context::OnCloseCompleted() {
200 delete this; 231 delete this;
201 } 232 }
202 233
203 Int64CompletionCallback FileStream::Context::IntToInt64( 234 Int64CompletionCallback FileStream::Context::IntToInt64(
204 const CompletionCallback& callback) { 235 const CompletionCallback& callback) {
205 return base::Bind(&CallInt64ToInt, callback); 236 return base::Bind(&CallInt64ToInt, callback);
206 } 237 }
207 238
208 void FileStream::Context::CheckForIOError(int64* result,
209 FileErrorSource source) {
210 if (*result < 0)
211 *result = RecordAndMapError(static_cast<int>(*result), source);
212 }
213
214 void FileStream::Context::ProcessAsyncResult( 239 void FileStream::Context::ProcessAsyncResult(
215 const Int64CompletionCallback& callback, 240 const Int64CompletionCallback& callback,
216 FileErrorSource source, 241 FileErrorSource source,
217 int64 result) { 242 const IOResult& result) {
218 CheckForIOError(&result, source); 243 RecordError(result, source);
219 OnAsyncCompleted(callback, result); 244 OnAsyncCompleted(callback, result.result);
220 } 245 }
221 246
222 void FileStream::Context::OnAsyncCompleted( 247 void FileStream::Context::OnAsyncCompleted(
223 const Int64CompletionCallback& callback, 248 const Int64CompletionCallback& callback,
224 int64 result) { 249 int64 result) {
225 // Reset this before Run() as Run() may issue a new async operation. Also it 250 // Reset this before Run() as Run() may issue a new async operation. Also it
226 // should be reset before CloseAsync() because it shouldn't run if any async 251 // should be reset before CloseAsync() because it shouldn't run if any async
227 // operation is in progress. 252 // operation is in progress.
228 async_in_progress_ = false; 253 async_in_progress_ = false;
229 if (orphaned_) 254 if (orphaned_)
230 CloseAndDelete(); 255 CloseAndDelete();
231 else 256 else
232 callback.Run(result); 257 callback.Run(result);
233 } 258 }
234 259
235 } // namespace net 260 } // namespace net
236 261
OLDNEW
« no previous file with comments | « net/base/file_stream_context.h ('k') | net/base/file_stream_context_posix.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698