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