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 "base/files/file_util_proxy.h" | 5 #include "base/files/file_util_proxy.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/files/file.h" | |
11 #include "base/location.h" | 10 #include "base/location.h" |
12 #include "base/message_loop/message_loop_proxy.h" | |
13 #include "base/task_runner.h" | 11 #include "base/task_runner.h" |
14 #include "base/task_runner_util.h" | 12 #include "base/task_runner_util.h" |
15 | 13 |
16 namespace base { | 14 namespace base { |
17 | 15 |
18 namespace { | 16 namespace { |
19 | 17 |
20 void CallWithTranslatedParameter(const FileUtilProxy::StatusCallback& callback, | 18 void CallWithTranslatedParameter(const FileUtilProxy::StatusCallback& callback, |
21 bool value) { | 19 bool value) { |
22 DCHECK(!callback.is_null()); | 20 DCHECK(!callback.is_null()); |
23 callback.Run(value ? File::FILE_OK : File::FILE_ERROR_FAILED); | 21 callback.Run(value ? File::FILE_OK : File::FILE_ERROR_FAILED); |
24 } | 22 } |
25 | 23 |
26 // Helper classes or routines for individual methods. | |
27 class CreateOrOpenHelper { | |
28 public: | |
29 CreateOrOpenHelper(TaskRunner* task_runner, | |
30 const FileUtilProxy::CloseTask& close_task) | |
31 : task_runner_(task_runner), | |
32 close_task_(close_task), | |
33 file_handle_(kInvalidPlatformFileValue), | |
34 created_(false), | |
35 error_(File::FILE_OK) {} | |
36 | |
37 ~CreateOrOpenHelper() { | |
38 if (file_handle_ != kInvalidPlatformFileValue) { | |
39 task_runner_->PostTask( | |
40 FROM_HERE, | |
41 base::Bind(base::IgnoreResult(close_task_), file_handle_)); | |
42 } | |
43 } | |
44 | |
45 void RunWork(const FileUtilProxy::CreateOrOpenTask& task) { | |
46 error_ = task.Run(&file_handle_, &created_); | |
47 } | |
48 | |
49 void Reply(const FileUtilProxy::CreateOrOpenCallback& callback) { | |
50 DCHECK(!callback.is_null()); | |
51 callback.Run(error_, PassPlatformFile(&file_handle_), created_); | |
52 } | |
53 | |
54 private: | |
55 scoped_refptr<TaskRunner> task_runner_; | |
56 FileUtilProxy::CloseTask close_task_; | |
57 PlatformFile file_handle_; | |
58 bool created_; | |
59 File::Error error_; | |
60 DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper); | |
61 }; | |
62 | |
63 class CreateTemporaryHelper { | |
64 public: | |
65 explicit CreateTemporaryHelper(TaskRunner* task_runner) | |
66 : task_runner_(task_runner), | |
67 file_handle_(kInvalidPlatformFileValue), | |
68 error_(File::FILE_OK) {} | |
69 | |
70 ~CreateTemporaryHelper() { | |
71 if (file_handle_ != kInvalidPlatformFileValue) { | |
72 FileUtilProxy::Close( | |
73 task_runner_.get(), file_handle_, FileUtilProxy::StatusCallback()); | |
74 } | |
75 } | |
76 | |
77 void RunWork(int additional_file_flags) { | |
78 // TODO(darin): file_util should have a variant of CreateTemporaryFile | |
79 // that returns a FilePath and a PlatformFile. | |
80 if (!base::CreateTemporaryFile(&file_path_)) { | |
81 // TODO(davidben): base::CreateTemporaryFile should preserve the error | |
82 // code. | |
83 error_ = File::FILE_ERROR_FAILED; | |
84 return; | |
85 } | |
86 | |
87 int file_flags = | |
88 PLATFORM_FILE_WRITE | | |
89 PLATFORM_FILE_TEMPORARY | | |
90 PLATFORM_FILE_CREATE_ALWAYS | | |
91 additional_file_flags; | |
92 | |
93 File file(file_path_, file_flags); | |
94 if (!file.IsValid()) { | |
95 base::DeleteFile(file_path_, false); | |
96 file_path_.clear(); | |
97 error_ = file.error_details(); | |
98 return; | |
99 } | |
100 error_ = File::FILE_OK; | |
101 file_handle_ = file.TakePlatformFile(); | |
102 } | |
103 | |
104 void Reply(const FileUtilProxy::CreateTemporaryCallback& callback) { | |
105 DCHECK(!callback.is_null()); | |
106 callback.Run(error_, PassPlatformFile(&file_handle_), file_path_); | |
107 } | |
108 | |
109 private: | |
110 scoped_refptr<TaskRunner> task_runner_; | |
111 PlatformFile file_handle_; | |
112 FilePath file_path_; | |
113 File::Error error_; | |
114 DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper); | |
115 }; | |
116 | |
117 class GetFileInfoHelper { | 24 class GetFileInfoHelper { |
118 public: | 25 public: |
119 GetFileInfoHelper() | 26 GetFileInfoHelper() |
120 : error_(File::FILE_OK) {} | 27 : error_(File::FILE_OK) {} |
121 | 28 |
122 void RunWorkForFilePath(const FilePath& file_path) { | 29 void RunWorkForFilePath(const FilePath& file_path) { |
123 if (!PathExists(file_path)) { | 30 if (!PathExists(file_path)) { |
124 error_ = File::FILE_ERROR_NOT_FOUND; | 31 error_ = File::FILE_ERROR_NOT_FOUND; |
125 return; | 32 return; |
126 } | 33 } |
127 // TODO(rvargas): switch this file to base::File. | 34 if (!GetFileInfo(file_path, &file_info_)) |
128 if (!GetFileInfo(file_path, reinterpret_cast<File::Info*>(&file_info_))) | |
129 error_ = File::FILE_ERROR_FAILED; | 35 error_ = File::FILE_ERROR_FAILED; |
130 } | 36 } |
131 | 37 |
132 void RunWorkForPlatformFile(PlatformFile file) { | |
133 if (!GetPlatformFileInfo( | |
134 file, reinterpret_cast<PlatformFileInfo*>(&file_info_))) { | |
135 error_ = File::FILE_ERROR_FAILED; | |
136 } | |
137 } | |
138 | |
139 void Reply(const FileUtilProxy::GetFileInfoCallback& callback) { | 38 void Reply(const FileUtilProxy::GetFileInfoCallback& callback) { |
140 if (!callback.is_null()) { | 39 if (!callback.is_null()) { |
141 callback.Run(error_, file_info_); | 40 callback.Run(error_, file_info_); |
142 } | 41 } |
143 } | 42 } |
144 | 43 |
145 private: | 44 private: |
146 File::Error error_; | 45 File::Error error_; |
147 File::Info file_info_; | 46 File::Info file_info_; |
148 DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper); | 47 DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper); |
149 }; | 48 }; |
150 | 49 |
151 class ReadHelper { | |
152 public: | |
153 explicit ReadHelper(int bytes_to_read) | |
154 : buffer_(new char[bytes_to_read]), | |
155 bytes_to_read_(bytes_to_read), | |
156 bytes_read_(0) {} | |
157 | |
158 void RunWork(PlatformFile file, int64 offset) { | |
159 bytes_read_ = ReadPlatformFile(file, offset, buffer_.get(), bytes_to_read_); | |
160 } | |
161 | |
162 void Reply(const FileUtilProxy::ReadCallback& callback) { | |
163 if (!callback.is_null()) { | |
164 File::Error error = | |
165 (bytes_read_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK; | |
166 callback.Run(error, buffer_.get(), bytes_read_); | |
167 } | |
168 } | |
169 | |
170 private: | |
171 scoped_ptr<char[]> buffer_; | |
172 int bytes_to_read_; | |
173 int bytes_read_; | |
174 DISALLOW_COPY_AND_ASSIGN(ReadHelper); | |
175 }; | |
176 | |
177 class WriteHelper { | |
178 public: | |
179 WriteHelper(const char* buffer, int bytes_to_write) | |
180 : buffer_(new char[bytes_to_write]), | |
181 bytes_to_write_(bytes_to_write), | |
182 bytes_written_(0) { | |
183 memcpy(buffer_.get(), buffer, bytes_to_write); | |
184 } | |
185 | |
186 void RunWork(PlatformFile file, int64 offset) { | |
187 bytes_written_ = WritePlatformFile(file, offset, buffer_.get(), | |
188 bytes_to_write_); | |
189 } | |
190 | |
191 void Reply(const FileUtilProxy::WriteCallback& callback) { | |
192 if (!callback.is_null()) { | |
193 File::Error error = | |
194 (bytes_written_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK; | |
195 callback.Run(error, bytes_written_); | |
196 } | |
197 } | |
198 | |
199 private: | |
200 scoped_ptr<char[]> buffer_; | |
201 int bytes_to_write_; | |
202 int bytes_written_; | |
203 DISALLOW_COPY_AND_ASSIGN(WriteHelper); | |
204 }; | |
205 | |
206 File::Error CreateOrOpenAdapter( | |
207 const FilePath& file_path, int file_flags, | |
208 PlatformFile* file_handle, bool* created) { | |
209 DCHECK(file_handle); | |
210 DCHECK(created); | |
211 if (!DirectoryExists(file_path.DirName())) { | |
212 // If its parent does not exist, should return NOT_FOUND error. | |
213 return File::FILE_ERROR_NOT_FOUND; | |
214 } | |
215 | |
216 File file(file_path, file_flags); | |
217 if (!file.IsValid()) | |
218 return file.error_details(); | |
219 | |
220 *file_handle = file.TakePlatformFile(); | |
221 *created = file.created(); | |
222 return File::FILE_OK; | |
223 } | |
224 | |
225 File::Error CloseAdapter(PlatformFile file_handle) { | |
226 if (!ClosePlatformFile(file_handle)) { | |
227 return File::FILE_ERROR_FAILED; | |
228 } | |
229 return File::FILE_OK; | |
230 } | |
231 | |
232 File::Error DeleteAdapter(const FilePath& file_path, bool recursive) { | 50 File::Error DeleteAdapter(const FilePath& file_path, bool recursive) { |
233 if (!PathExists(file_path)) { | 51 if (!PathExists(file_path)) { |
234 return File::FILE_ERROR_NOT_FOUND; | 52 return File::FILE_ERROR_NOT_FOUND; |
235 } | 53 } |
236 if (!base::DeleteFile(file_path, recursive)) { | 54 if (!base::DeleteFile(file_path, recursive)) { |
237 if (!recursive && !base::IsDirectoryEmpty(file_path)) { | 55 if (!recursive && !base::IsDirectoryEmpty(file_path)) { |
238 return File::FILE_ERROR_NOT_EMPTY; | 56 return File::FILE_ERROR_NOT_EMPTY; |
239 } | 57 } |
240 return File::FILE_ERROR_FAILED; | 58 return File::FILE_ERROR_FAILED; |
241 } | 59 } |
242 return File::FILE_OK; | 60 return File::FILE_OK; |
243 } | 61 } |
244 | 62 |
245 } // namespace | 63 } // namespace |
246 | 64 |
247 // static | |
248 bool FileUtilProxy::CreateOrOpen( | |
249 TaskRunner* task_runner, | |
250 const FilePath& file_path, int file_flags, | |
251 const CreateOrOpenCallback& callback) { | |
252 return RelayCreateOrOpen( | |
253 task_runner, | |
254 base::Bind(&CreateOrOpenAdapter, file_path, file_flags), | |
255 base::Bind(&CloseAdapter), | |
256 callback); | |
257 } | |
258 | |
259 // static | |
260 bool FileUtilProxy::CreateTemporary( | |
261 TaskRunner* task_runner, | |
262 int additional_file_flags, | |
263 const CreateTemporaryCallback& callback) { | |
264 CreateTemporaryHelper* helper = new CreateTemporaryHelper(task_runner); | |
265 return task_runner->PostTaskAndReply( | |
266 FROM_HERE, | |
267 Bind(&CreateTemporaryHelper::RunWork, Unretained(helper), | |
268 additional_file_flags), | |
269 Bind(&CreateTemporaryHelper::Reply, Owned(helper), callback)); | |
270 } | |
271 | |
272 // static | |
273 bool FileUtilProxy::Close( | |
274 TaskRunner* task_runner, | |
275 base::PlatformFile file_handle, | |
276 const StatusCallback& callback) { | |
277 return RelayClose( | |
278 task_runner, | |
279 base::Bind(&CloseAdapter), | |
280 file_handle, callback); | |
281 } | |
282 | |
283 // Retrieves the information about a file. It is invalid to pass NULL for the | 65 // Retrieves the information about a file. It is invalid to pass NULL for the |
284 // callback. | 66 // callback. |
285 bool FileUtilProxy::GetFileInfo( | 67 bool FileUtilProxy::GetFileInfo( |
286 TaskRunner* task_runner, | 68 TaskRunner* task_runner, |
287 const FilePath& file_path, | 69 const FilePath& file_path, |
288 const GetFileInfoCallback& callback) { | 70 const GetFileInfoCallback& callback) { |
289 GetFileInfoHelper* helper = new GetFileInfoHelper; | 71 GetFileInfoHelper* helper = new GetFileInfoHelper; |
290 return task_runner->PostTaskAndReply( | 72 return task_runner->PostTaskAndReply( |
291 FROM_HERE, | 73 FROM_HERE, |
292 Bind(&GetFileInfoHelper::RunWorkForFilePath, | 74 Bind(&GetFileInfoHelper::RunWorkForFilePath, |
293 Unretained(helper), file_path), | 75 Unretained(helper), file_path), |
294 Bind(&GetFileInfoHelper::Reply, Owned(helper), callback)); | 76 Bind(&GetFileInfoHelper::Reply, Owned(helper), callback)); |
295 } | 77 } |
296 | 78 |
297 // static | 79 // static |
298 bool FileUtilProxy::GetFileInfoFromPlatformFile( | |
299 TaskRunner* task_runner, | |
300 PlatformFile file, | |
301 const GetFileInfoCallback& callback) { | |
302 GetFileInfoHelper* helper = new GetFileInfoHelper; | |
303 return task_runner->PostTaskAndReply( | |
304 FROM_HERE, | |
305 Bind(&GetFileInfoHelper::RunWorkForPlatformFile, | |
306 Unretained(helper), file), | |
307 Bind(&GetFileInfoHelper::Reply, Owned(helper), callback)); | |
308 } | |
309 | |
310 // static | |
311 bool FileUtilProxy::DeleteFile(TaskRunner* task_runner, | 80 bool FileUtilProxy::DeleteFile(TaskRunner* task_runner, |
312 const FilePath& file_path, | 81 const FilePath& file_path, |
313 bool recursive, | 82 bool recursive, |
314 const StatusCallback& callback) { | 83 const StatusCallback& callback) { |
315 return base::PostTaskAndReplyWithResult( | 84 return base::PostTaskAndReplyWithResult( |
316 task_runner, FROM_HERE, | 85 task_runner, FROM_HERE, |
317 Bind(&DeleteAdapter, file_path, recursive), | 86 Bind(&DeleteAdapter, file_path, recursive), |
318 callback); | 87 callback); |
319 } | 88 } |
320 | 89 |
321 // static | 90 // static |
322 bool FileUtilProxy::Read( | |
323 TaskRunner* task_runner, | |
324 PlatformFile file, | |
325 int64 offset, | |
326 int bytes_to_read, | |
327 const ReadCallback& callback) { | |
328 if (bytes_to_read < 0) { | |
329 return false; | |
330 } | |
331 ReadHelper* helper = new ReadHelper(bytes_to_read); | |
332 return task_runner->PostTaskAndReply( | |
333 FROM_HERE, | |
334 Bind(&ReadHelper::RunWork, Unretained(helper), file, offset), | |
335 Bind(&ReadHelper::Reply, Owned(helper), callback)); | |
336 } | |
337 | |
338 // static | |
339 bool FileUtilProxy::Write( | |
340 TaskRunner* task_runner, | |
341 PlatformFile file, | |
342 int64 offset, | |
343 const char* buffer, | |
344 int bytes_to_write, | |
345 const WriteCallback& callback) { | |
346 if (bytes_to_write <= 0 || buffer == NULL) { | |
347 return false; | |
348 } | |
349 WriteHelper* helper = new WriteHelper(buffer, bytes_to_write); | |
350 return task_runner->PostTaskAndReply( | |
351 FROM_HERE, | |
352 Bind(&WriteHelper::RunWork, Unretained(helper), file, offset), | |
353 Bind(&WriteHelper::Reply, Owned(helper), callback)); | |
354 } | |
355 | |
356 // static | |
357 bool FileUtilProxy::Touch( | |
358 TaskRunner* task_runner, | |
359 PlatformFile file, | |
360 const Time& last_access_time, | |
361 const Time& last_modified_time, | |
362 const StatusCallback& callback) { | |
363 return base::PostTaskAndReplyWithResult( | |
364 task_runner, | |
365 FROM_HERE, | |
366 Bind(&TouchPlatformFile, file, | |
367 last_access_time, last_modified_time), | |
368 Bind(&CallWithTranslatedParameter, callback)); | |
369 } | |
370 | |
371 // static | |
372 bool FileUtilProxy::Touch( | 91 bool FileUtilProxy::Touch( |
373 TaskRunner* task_runner, | 92 TaskRunner* task_runner, |
374 const FilePath& file_path, | 93 const FilePath& file_path, |
375 const Time& last_access_time, | 94 const Time& last_access_time, |
376 const Time& last_modified_time, | 95 const Time& last_modified_time, |
377 const StatusCallback& callback) { | 96 const StatusCallback& callback) { |
378 return base::PostTaskAndReplyWithResult( | 97 return base::PostTaskAndReplyWithResult( |
379 task_runner, | 98 task_runner, |
380 FROM_HERE, | 99 FROM_HERE, |
381 Bind(&TouchFile, file_path, last_access_time, last_modified_time), | 100 Bind(&TouchFile, file_path, last_access_time, last_modified_time), |
382 Bind(&CallWithTranslatedParameter, callback)); | 101 Bind(&CallWithTranslatedParameter, callback)); |
383 } | 102 } |
384 | 103 |
385 // static | |
386 bool FileUtilProxy::Truncate( | |
387 TaskRunner* task_runner, | |
388 PlatformFile file, | |
389 int64 length, | |
390 const StatusCallback& callback) { | |
391 return base::PostTaskAndReplyWithResult( | |
392 task_runner, | |
393 FROM_HERE, | |
394 Bind(&TruncatePlatformFile, file, length), | |
395 Bind(&CallWithTranslatedParameter, callback)); | |
396 } | |
397 | |
398 // static | |
399 bool FileUtilProxy::Flush( | |
400 TaskRunner* task_runner, | |
401 PlatformFile file, | |
402 const StatusCallback& callback) { | |
403 return base::PostTaskAndReplyWithResult( | |
404 task_runner, | |
405 FROM_HERE, | |
406 Bind(&FlushPlatformFile, file), | |
407 Bind(&CallWithTranslatedParameter, callback)); | |
408 } | |
409 | |
410 // static | |
411 bool FileUtilProxy::RelayCreateOrOpen( | |
412 TaskRunner* task_runner, | |
413 const CreateOrOpenTask& open_task, | |
414 const CloseTask& close_task, | |
415 const CreateOrOpenCallback& callback) { | |
416 CreateOrOpenHelper* helper = new CreateOrOpenHelper( | |
417 task_runner, close_task); | |
418 return task_runner->PostTaskAndReply( | |
419 FROM_HERE, | |
420 Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), open_task), | |
421 Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback)); | |
422 } | |
423 | |
424 // static | |
425 bool FileUtilProxy::RelayClose( | |
426 TaskRunner* task_runner, | |
427 const CloseTask& close_task, | |
428 PlatformFile file_handle, | |
429 const StatusCallback& callback) { | |
430 return base::PostTaskAndReplyWithResult( | |
431 task_runner, FROM_HERE, Bind(close_task, file_handle), callback); | |
432 } | |
433 | |
434 } // namespace base | 104 } // namespace base |
OLD | NEW |