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