| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 "webkit/fileapi/file_system_file_util.h" | |
| 6 | |
| 7 #include <stack> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/file_util_proxy.h" | |
| 11 #include "base/memory/scoped_ptr.h" | |
| 12 #include "webkit/fileapi/file_system_operation_context.h" | |
| 13 | |
| 14 namespace fileapi { | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 // This assumes that the root exists. | |
| 19 bool ParentExists(FileSystemOperationContext* context, | |
| 20 FileSystemFileUtil* file_util, const FilePath& file_path) { | |
| 21 // If file_path is in the root, file_path.DirName() will be ".", | |
| 22 // since we use paths with no leading '/'. | |
| 23 FilePath parent = file_path.DirName(); | |
| 24 if (parent == FilePath(FILE_PATH_LITERAL("."))) | |
| 25 return true; | |
| 26 return file_util->DirectoryExists(context, parent); | |
| 27 } | |
| 28 | |
| 29 } // namespace | |
| 30 | |
| 31 PlatformFileError FileSystemFileUtil::CreateOrOpen( | |
| 32 FileSystemOperationContext* unused, | |
| 33 const FilePath& file_path, int file_flags, | |
| 34 PlatformFile* file_handle, bool* created) { | |
| 35 if (!file_util::DirectoryExists(file_path.DirName())) { | |
| 36 // If its parent does not exist, should return NOT_FOUND error. | |
| 37 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 38 } | |
| 39 PlatformFileError error_code = base::PLATFORM_FILE_OK; | |
| 40 *file_handle = base::CreatePlatformFile(file_path, file_flags, | |
| 41 created, &error_code); | |
| 42 return error_code; | |
| 43 } | |
| 44 | |
| 45 PlatformFileError FileSystemFileUtil::Close( | |
| 46 FileSystemOperationContext* unused, | |
| 47 PlatformFile file_handle) { | |
| 48 if (!base::ClosePlatformFile(file_handle)) | |
| 49 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 50 return base::PLATFORM_FILE_OK; | |
| 51 } | |
| 52 | |
| 53 PlatformFileError FileSystemFileUtil::EnsureFileExists( | |
| 54 FileSystemOperationContext* unused, | |
| 55 const FilePath& file_path, | |
| 56 bool* created) { | |
| 57 if (!file_util::DirectoryExists(file_path.DirName())) | |
| 58 // If its parent does not exist, should return NOT_FOUND error. | |
| 59 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 60 PlatformFileError error_code = base::PLATFORM_FILE_OK; | |
| 61 // Tries to create the |file_path| exclusively. This should fail | |
| 62 // with base::PLATFORM_FILE_ERROR_EXISTS if the path already exists. | |
| 63 PlatformFile handle = base::CreatePlatformFile( | |
| 64 file_path, | |
| 65 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ, | |
| 66 created, &error_code); | |
| 67 if (error_code == base::PLATFORM_FILE_ERROR_EXISTS) { | |
| 68 // Make sure created_ is false. | |
| 69 if (created) | |
| 70 *created = false; | |
| 71 error_code = base::PLATFORM_FILE_OK; | |
| 72 } | |
| 73 if (handle != base::kInvalidPlatformFileValue) | |
| 74 base::ClosePlatformFile(handle); | |
| 75 return error_code; | |
| 76 } | |
| 77 | |
| 78 PlatformFileError FileSystemFileUtil::GetLocalFilePath( | |
| 79 FileSystemOperationContext* context, | |
| 80 const FilePath& virtual_path, | |
| 81 FilePath* local_path) { | |
| 82 *local_path = virtual_path; | |
| 83 return base::PLATFORM_FILE_OK; | |
| 84 } | |
| 85 | |
| 86 PlatformFileError FileSystemFileUtil::GetFileInfo( | |
| 87 FileSystemOperationContext* unused, | |
| 88 const FilePath& file_path, | |
| 89 base::PlatformFileInfo* file_info, | |
| 90 FilePath* platform_file_path) { | |
| 91 if (!file_util::PathExists(file_path)) | |
| 92 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 93 // TODO(rkc): Fix this hack once we have refactored file_util to handle | |
| 94 // symlinks correctly. | |
| 95 // http://code.google.com/p/chromium-os/issues/detail?id=15948 | |
| 96 if (file_util::IsLink(file_path)) | |
| 97 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 98 if (!file_util::GetFileInfo(file_path, file_info)) | |
| 99 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 100 *platform_file_path = file_path; | |
| 101 return base::PLATFORM_FILE_OK; | |
| 102 } | |
| 103 | |
| 104 PlatformFileError FileSystemFileUtil::ReadDirectory( | |
| 105 FileSystemOperationContext* unused, | |
| 106 const FilePath& file_path, | |
| 107 std::vector<base::FileUtilProxy::Entry>* entries) { | |
| 108 // TODO(kkanetkar): Implement directory read in multiple chunks. | |
| 109 if (!file_util::DirectoryExists(file_path)) | |
| 110 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 111 | |
| 112 file_util::FileEnumerator file_enum( | |
| 113 file_path, false, static_cast<file_util::FileEnumerator::FILE_TYPE>( | |
| 114 file_util::FileEnumerator::FILES | | |
| 115 file_util::FileEnumerator::DIRECTORIES)); | |
| 116 FilePath current; | |
| 117 while (!(current = file_enum.Next()).empty()) { | |
| 118 base::FileUtilProxy::Entry entry; | |
| 119 file_util::FileEnumerator::FindInfo info; | |
| 120 file_enum.GetFindInfo(&info); | |
| 121 entry.is_directory = file_enum.IsDirectory(info); | |
| 122 // This will just give the entry's name instead of entire path | |
| 123 // if we use current.value(). | |
| 124 entry.name = file_util::FileEnumerator::GetFilename(info).value(); | |
| 125 entry.size = file_util::FileEnumerator::GetFilesize(info); | |
| 126 entry.last_modified_time = | |
| 127 file_util::FileEnumerator::GetLastModifiedTime(info); | |
| 128 // TODO(rkc): Fix this also once we've refactored file_util | |
| 129 // http://code.google.com/p/chromium-os/issues/detail?id=15948 | |
| 130 // This currently just prevents a file from showing up at all | |
| 131 // if it's a link, hence preventing arbitary 'read' exploits. | |
| 132 if (!file_util::IsLink(file_path.Append(entry.name))) | |
| 133 entries->push_back(entry); | |
| 134 } | |
| 135 return base::PLATFORM_FILE_OK; | |
| 136 } | |
| 137 | |
| 138 PlatformFileError FileSystemFileUtil::CreateDirectory( | |
| 139 FileSystemOperationContext* fs_context, | |
| 140 const FilePath& file_path, | |
| 141 bool exclusive, | |
| 142 bool recursive) { | |
| 143 if (fs_context->do_not_write_actually()) | |
| 144 return base::PLATFORM_FILE_OK; | |
| 145 | |
| 146 // If parent dir of file doesn't exist. | |
| 147 if (!recursive && !file_util::PathExists(file_path.DirName())) | |
| 148 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 149 | |
| 150 bool path_exists = file_util::PathExists(file_path); | |
| 151 if (exclusive && path_exists) | |
| 152 return base::PLATFORM_FILE_ERROR_EXISTS; | |
| 153 | |
| 154 // If file exists at the path. | |
| 155 if (path_exists && !file_util::DirectoryExists(file_path)) | |
| 156 return base::PLATFORM_FILE_ERROR_EXISTS; | |
| 157 | |
| 158 if (!file_util::CreateDirectory(file_path)) | |
| 159 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 160 return base::PLATFORM_FILE_OK; | |
| 161 } | |
| 162 | |
| 163 PlatformFileError FileSystemFileUtil::Copy( | |
| 164 FileSystemOperationContext* context, | |
| 165 const FilePath& src_file_path, | |
| 166 const FilePath& dest_file_path) { | |
| 167 PlatformFileError error_code; | |
| 168 error_code = | |
| 169 PerformCommonCheckAndPreparationForMoveAndCopy( | |
| 170 context, src_file_path, dest_file_path); | |
| 171 if (error_code != base::PLATFORM_FILE_OK) | |
| 172 return error_code; | |
| 173 | |
| 174 if (DirectoryExists(context, src_file_path)) | |
| 175 return CopyOrMoveDirectory(context, src_file_path, dest_file_path, | |
| 176 true /* copy */); | |
| 177 return CopyOrMoveFileHelper(context, src_file_path, dest_file_path, | |
| 178 true /* copy */); | |
| 179 } | |
| 180 | |
| 181 PlatformFileError FileSystemFileUtil::Move( | |
| 182 FileSystemOperationContext* context, | |
| 183 const FilePath& src_file_path, | |
| 184 const FilePath& dest_file_path) { | |
| 185 PlatformFileError error_code; | |
| 186 error_code = | |
| 187 PerformCommonCheckAndPreparationForMoveAndCopy( | |
| 188 context, src_file_path, dest_file_path); | |
| 189 if (error_code != base::PLATFORM_FILE_OK) | |
| 190 return error_code; | |
| 191 | |
| 192 // TODO(dmikurube): ReplaceFile if in the same domain and filesystem type. | |
| 193 if (DirectoryExists(context, src_file_path)) | |
| 194 return CopyOrMoveDirectory(context, src_file_path, dest_file_path, | |
| 195 false /* copy */); | |
| 196 return CopyOrMoveFileHelper(context, src_file_path, dest_file_path, | |
| 197 false /* copy */); | |
| 198 } | |
| 199 | |
| 200 PlatformFileError FileSystemFileUtil::Delete( | |
| 201 FileSystemOperationContext* context, | |
| 202 const FilePath& file_path, | |
| 203 bool recursive) { | |
| 204 if (DirectoryExists(context, file_path)) { | |
| 205 if (!recursive) | |
| 206 return DeleteSingleDirectory(context, file_path); | |
| 207 else | |
| 208 return DeleteDirectoryRecursive(context, file_path); | |
| 209 } else { | |
| 210 return DeleteFile(context, file_path); | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 PlatformFileError FileSystemFileUtil::Touch( | |
| 215 FileSystemOperationContext* unused, | |
| 216 const FilePath& file_path, | |
| 217 const base::Time& last_access_time, | |
| 218 const base::Time& last_modified_time) { | |
| 219 if (!file_util::TouchFile( | |
| 220 file_path, last_access_time, last_modified_time)) | |
| 221 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 222 return base::PLATFORM_FILE_OK; | |
| 223 } | |
| 224 | |
| 225 PlatformFileError FileSystemFileUtil::Truncate( | |
| 226 FileSystemOperationContext* unused, | |
| 227 const FilePath& file_path, | |
| 228 int64 length) { | |
| 229 PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED); | |
| 230 PlatformFile file = | |
| 231 base::CreatePlatformFile( | |
| 232 file_path, | |
| 233 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, | |
| 234 NULL, | |
| 235 &error_code); | |
| 236 if (error_code != base::PLATFORM_FILE_OK) { | |
| 237 return error_code; | |
| 238 } | |
| 239 DCHECK_NE(base::kInvalidPlatformFileValue, file); | |
| 240 if (!base::TruncatePlatformFile(file, length)) | |
| 241 error_code = base::PLATFORM_FILE_ERROR_FAILED; | |
| 242 base::ClosePlatformFile(file); | |
| 243 return error_code; | |
| 244 } | |
| 245 | |
| 246 PlatformFileError | |
| 247 FileSystemFileUtil::PerformCommonCheckAndPreparationForMoveAndCopy( | |
| 248 FileSystemOperationContext* context, | |
| 249 const FilePath& src_file_path, | |
| 250 const FilePath& dest_file_path) { | |
| 251 bool same_file_system = | |
| 252 (context->src_origin_url() == context->dest_origin_url()) && | |
| 253 (context->src_type() == context->dest_type()); | |
| 254 FileSystemFileUtil* dest_util = context->dest_file_system_file_util(); | |
| 255 DCHECK(dest_util); | |
| 256 if (same_file_system) | |
| 257 DCHECK(context->src_file_system_file_util() == | |
| 258 context->dest_file_system_file_util()); | |
| 259 // All the single-path virtual FSFU methods expect the context information | |
| 260 // to be in the src_* variables, not the dest_* variables, so we have to | |
| 261 // make a new context if we want to call them on the dest_file_path. | |
| 262 scoped_ptr<FileSystemOperationContext> dest_context( | |
| 263 context->CreateInheritedContextForDest()); | |
| 264 | |
| 265 // Exits earlier if the source path does not exist. | |
| 266 if (!PathExists(context, src_file_path)) | |
| 267 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 268 | |
| 269 // The parent of the |dest_file_path| does not exist. | |
| 270 if (!ParentExists(dest_context.get(), dest_util, dest_file_path)) | |
| 271 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 272 | |
| 273 // It is an error to try to copy/move an entry into its child. | |
| 274 if (same_file_system && src_file_path.IsParent(dest_file_path)) | |
| 275 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | |
| 276 | |
| 277 // Now it is ok to return if the |dest_file_path| does not exist. | |
| 278 if (!dest_util->PathExists(dest_context.get(), dest_file_path)) | |
| 279 return base::PLATFORM_FILE_OK; | |
| 280 | |
| 281 // |src_file_path| exists and is a directory. | |
| 282 // |dest_file_path| exists and is a file. | |
| 283 bool src_is_directory = DirectoryExists(context, src_file_path); | |
| 284 bool dest_is_directory = | |
| 285 dest_util->DirectoryExists(dest_context.get(), dest_file_path); | |
| 286 if (src_is_directory && !dest_is_directory) | |
| 287 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | |
| 288 | |
| 289 // |src_file_path| exists and is a file. | |
| 290 // |dest_file_path| exists and is a directory. | |
| 291 if (!src_is_directory && dest_is_directory) | |
| 292 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; | |
| 293 | |
| 294 // It is an error to copy/move an entry into the same path. | |
| 295 if (same_file_system && (src_file_path.value() == dest_file_path.value())) | |
| 296 return base::PLATFORM_FILE_ERROR_EXISTS; | |
| 297 | |
| 298 if (dest_is_directory) { | |
| 299 // It is an error to copy/move an entry to a non-empty directory. | |
| 300 // Otherwise the copy/move attempt must overwrite the destination, but | |
| 301 // the file_util's Copy or Move method doesn't perform overwrite | |
| 302 // on all platforms, so we delete the destination directory here. | |
| 303 // TODO(kinuko): may be better to change the file_util::{Copy,Move}. | |
| 304 PlatformFileError error = dest_util->Delete( | |
| 305 dest_context.get(), dest_file_path, false /* recursive */); | |
| 306 context->ImportAllowedBytesGrowth(*dest_context); | |
| 307 if (base::PLATFORM_FILE_OK != error) { | |
| 308 if (!dest_util->IsDirectoryEmpty(dest_context.get(), dest_file_path)) | |
| 309 return base::PLATFORM_FILE_ERROR_NOT_EMPTY; | |
| 310 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 311 } | |
| 312 } | |
| 313 return base::PLATFORM_FILE_OK; | |
| 314 } | |
| 315 | |
| 316 PlatformFileError FileSystemFileUtil::CopyOrMoveFile( | |
| 317 FileSystemOperationContext* unused, | |
| 318 const FilePath& src_file_path, | |
| 319 const FilePath& dest_file_path, | |
| 320 bool copy) { | |
| 321 if (copy) { | |
| 322 if (file_util::CopyFile(src_file_path, dest_file_path)) | |
| 323 return base::PLATFORM_FILE_OK; | |
| 324 } else { | |
| 325 DCHECK(!file_util::DirectoryExists(src_file_path)); | |
| 326 if (file_util::Move(src_file_path, dest_file_path)) | |
| 327 return base::PLATFORM_FILE_OK; | |
| 328 } | |
| 329 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 330 } | |
| 331 | |
| 332 PlatformFileError FileSystemFileUtil::CopyInForeignFile( | |
| 333 FileSystemOperationContext* context, | |
| 334 const FilePath& src_file_path, | |
| 335 const FilePath& dest_file_path) { | |
| 336 return CopyOrMoveFile(context, src_file_path, dest_file_path, true); | |
| 337 } | |
| 338 | |
| 339 PlatformFileError FileSystemFileUtil::CopyOrMoveDirectory( | |
| 340 FileSystemOperationContext* context, | |
| 341 const FilePath& src_file_path, | |
| 342 const FilePath& dest_file_path, | |
| 343 bool copy) { | |
| 344 FileSystemFileUtil* dest_util = context->dest_file_system_file_util(); | |
| 345 scoped_ptr<FileSystemOperationContext> dest_context( | |
| 346 context->CreateInheritedContextForDest()); | |
| 347 | |
| 348 // Re-check PerformCommonCheckAndPreparationForMoveAndCopy() by DCHECK. | |
| 349 DCHECK(DirectoryExists(context, src_file_path)); | |
| 350 DCHECK(ParentExists(dest_context.get(), dest_util, dest_file_path)); | |
| 351 DCHECK(!dest_util->PathExists(dest_context.get(), dest_file_path)); | |
| 352 if ((context->src_origin_url() == context->dest_origin_url()) && | |
| 353 (context->src_type() == context->dest_type())) | |
| 354 DCHECK(!src_file_path.IsParent(dest_file_path)); | |
| 355 | |
| 356 if (!dest_util->DirectoryExists(dest_context.get(), dest_file_path)) { | |
| 357 PlatformFileError error = dest_util->CreateDirectory(dest_context.get(), | |
| 358 dest_file_path, false, false); | |
| 359 context->ImportAllowedBytesGrowth(*dest_context); | |
| 360 if (error != base::PLATFORM_FILE_OK) | |
| 361 return error; | |
| 362 } | |
| 363 | |
| 364 scoped_ptr<AbstractFileEnumerator> file_enum( | |
| 365 CreateFileEnumerator(context, src_file_path)); | |
| 366 FilePath src_file_path_each; | |
| 367 while (!(src_file_path_each = file_enum->Next()).empty()) { | |
| 368 FilePath dest_file_path_each(dest_file_path); | |
| 369 src_file_path.AppendRelativePath(src_file_path_each, &dest_file_path_each); | |
| 370 | |
| 371 if (file_enum->IsDirectory()) { | |
| 372 scoped_ptr<FileSystemOperationContext> new_directory_context( | |
| 373 dest_context->CreateInheritedContextWithNewVirtualPaths( | |
| 374 dest_file_path_each, FilePath())); | |
| 375 PlatformFileError error = dest_util->CreateDirectory( | |
| 376 new_directory_context.get(), dest_file_path_each, false, false); | |
| 377 context->ImportAllowedBytesGrowth(*new_directory_context); | |
| 378 if (error != base::PLATFORM_FILE_OK) | |
| 379 return error; | |
| 380 } else { | |
| 381 scoped_ptr<FileSystemOperationContext> copy_context( | |
| 382 context->CreateInheritedContextWithNewVirtualPaths( | |
| 383 src_file_path_each, dest_file_path_each)); | |
| 384 PlatformFileError error = CopyOrMoveFileHelper( | |
| 385 copy_context.get(), src_file_path_each, dest_file_path_each, copy); | |
| 386 context->ImportAllowedBytesGrowth(*copy_context); | |
| 387 if (error != base::PLATFORM_FILE_OK) | |
| 388 return error; | |
| 389 } | |
| 390 } | |
| 391 | |
| 392 if (!copy) { | |
| 393 PlatformFileError error = Delete(context, src_file_path, true); | |
| 394 if (error != base::PLATFORM_FILE_OK) | |
| 395 return error; | |
| 396 } | |
| 397 return base::PLATFORM_FILE_OK; | |
| 398 } | |
| 399 | |
| 400 PlatformFileError FileSystemFileUtil::CopyOrMoveFileHelper( | |
| 401 FileSystemOperationContext* context, | |
| 402 const FilePath& src_file_path, | |
| 403 const FilePath& dest_file_path, | |
| 404 bool copy) { | |
| 405 // CopyOrMoveFile here is the virtual overridden member function. | |
| 406 if ((context->src_origin_url() == context->dest_origin_url()) && | |
| 407 (context->src_type() == context->dest_type())) { | |
| 408 DCHECK(context->src_file_system_file_util() == | |
| 409 context->dest_file_system_file_util()); | |
| 410 return CopyOrMoveFile(context, src_file_path, dest_file_path, copy); | |
| 411 } | |
| 412 base::PlatformFileInfo file_info; | |
| 413 FilePath platform_file_path; | |
| 414 PlatformFileError error_code; | |
| 415 error_code = | |
| 416 GetFileInfo(context, src_file_path, &file_info, &platform_file_path); | |
| 417 if (error_code != base::PLATFORM_FILE_OK) | |
| 418 return error_code; | |
| 419 | |
| 420 DCHECK(context->dest_file_system_file_util()); | |
| 421 error_code = context->dest_file_system_file_util()->CopyInForeignFile( | |
| 422 context, platform_file_path, dest_file_path); | |
| 423 if (copy || error_code != base::PLATFORM_FILE_OK) | |
| 424 return error_code; | |
| 425 return DeleteFile(context, src_file_path); | |
| 426 } | |
| 427 | |
| 428 | |
| 429 PlatformFileError FileSystemFileUtil::DeleteFile( | |
| 430 FileSystemOperationContext* unused, | |
| 431 const FilePath& file_path) { | |
| 432 if (!file_util::PathExists(file_path)) | |
| 433 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 434 if (file_util::DirectoryExists(file_path)) | |
| 435 return base::PLATFORM_FILE_ERROR_NOT_A_FILE; | |
| 436 if (!file_util::Delete(file_path, false)) | |
| 437 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 438 return base::PLATFORM_FILE_OK; | |
| 439 } | |
| 440 | |
| 441 PlatformFileError FileSystemFileUtil::DeleteSingleDirectory( | |
| 442 FileSystemOperationContext* unused, | |
| 443 const FilePath& file_path) { | |
| 444 if (!file_util::PathExists(file_path)) | |
| 445 return base::PLATFORM_FILE_ERROR_NOT_FOUND; | |
| 446 if (!file_util::DirectoryExists(file_path)) { | |
| 447 // TODO(dmikurube): Check if this error code is appropriate. | |
| 448 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; | |
| 449 } | |
| 450 if (!file_util::IsDirectoryEmpty(file_path)) { | |
| 451 // TODO(dmikurube): Check if this error code is appropriate. | |
| 452 return base::PLATFORM_FILE_ERROR_NOT_EMPTY; | |
| 453 } | |
| 454 if (!file_util::Delete(file_path, false)) | |
| 455 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 456 return base::PLATFORM_FILE_OK; | |
| 457 } | |
| 458 | |
| 459 PlatformFileError FileSystemFileUtil::DeleteDirectoryRecursive( | |
| 460 FileSystemOperationContext* context, | |
| 461 const FilePath& file_path) { | |
| 462 scoped_ptr<AbstractFileEnumerator> file_enum( | |
| 463 CreateFileEnumerator(context, file_path)); | |
| 464 FilePath file_path_each; | |
| 465 | |
| 466 std::stack<FilePath> directories; | |
| 467 while (!(file_path_each = file_enum->Next()).empty()) { | |
| 468 if (file_enum->IsDirectory()) { | |
| 469 directories.push(file_path_each); | |
| 470 } else { | |
| 471 // DeleteFile here is the virtual overridden member function. | |
| 472 scoped_ptr<FileSystemOperationContext> inherited_context( | |
| 473 context->CreateInheritedContextWithNewVirtualPaths( | |
| 474 file_path_each, FilePath())); | |
| 475 PlatformFileError error = | |
| 476 DeleteFile(inherited_context.get(), file_path_each); | |
| 477 context->ImportAllowedBytesGrowth(*inherited_context); | |
| 478 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) | |
| 479 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 480 else if (error != base::PLATFORM_FILE_OK) | |
| 481 return error; | |
| 482 } | |
| 483 } | |
| 484 | |
| 485 while (!directories.empty()) { | |
| 486 scoped_ptr<FileSystemOperationContext> inherited_context( | |
| 487 context->CreateInheritedContextWithNewVirtualPaths( | |
| 488 directories.top(), FilePath())); | |
| 489 PlatformFileError error = | |
| 490 DeleteSingleDirectory(inherited_context.get(), directories.top()); | |
| 491 context->ImportAllowedBytesGrowth(*inherited_context); | |
| 492 if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND) | |
| 493 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 494 else if (error != base::PLATFORM_FILE_OK) | |
| 495 return error; | |
| 496 directories.pop(); | |
| 497 } | |
| 498 return DeleteSingleDirectory(context, file_path); | |
| 499 } | |
| 500 | |
| 501 bool FileSystemFileUtil::PathExists( | |
| 502 FileSystemOperationContext* unused, | |
| 503 const FilePath& file_path) { | |
| 504 return file_util::PathExists(file_path); | |
| 505 } | |
| 506 | |
| 507 bool FileSystemFileUtil::DirectoryExists( | |
| 508 FileSystemOperationContext* unused, | |
| 509 const FilePath& file_path) { | |
| 510 return file_util::DirectoryExists(file_path); | |
| 511 } | |
| 512 | |
| 513 bool FileSystemFileUtil::IsDirectoryEmpty( | |
| 514 FileSystemOperationContext* unused, | |
| 515 const FilePath& file_path) { | |
| 516 return file_util::IsDirectoryEmpty(file_path); | |
| 517 } | |
| 518 | |
| 519 class FileSystemFileEnumerator | |
| 520 : public FileSystemFileUtil::AbstractFileEnumerator { | |
| 521 public: | |
| 522 FileSystemFileEnumerator(const FilePath& root_path, | |
| 523 bool recursive, | |
| 524 file_util::FileEnumerator::FILE_TYPE file_type) | |
| 525 : file_enum_(root_path, recursive, file_type) { | |
| 526 } | |
| 527 | |
| 528 ~FileSystemFileEnumerator() {} | |
| 529 | |
| 530 virtual FilePath Next(); | |
| 531 virtual bool IsDirectory(); | |
| 532 | |
| 533 private: | |
| 534 file_util::FileEnumerator file_enum_; | |
| 535 }; | |
| 536 | |
| 537 FilePath FileSystemFileEnumerator::Next() { | |
| 538 return file_enum_.Next(); | |
| 539 } | |
| 540 | |
| 541 bool FileSystemFileEnumerator::IsDirectory() { | |
| 542 file_util::FileEnumerator::FindInfo file_util_info; | |
| 543 file_enum_.GetFindInfo(&file_util_info); | |
| 544 return file_util::FileEnumerator::IsDirectory(file_util_info); | |
| 545 } | |
| 546 | |
| 547 FileSystemFileUtil::AbstractFileEnumerator* | |
| 548 FileSystemFileUtil::CreateFileEnumerator( | |
| 549 FileSystemOperationContext* unused, | |
| 550 const FilePath& root_path) { | |
| 551 return new FileSystemFileEnumerator( | |
| 552 root_path, true, static_cast<file_util::FileEnumerator::FILE_TYPE>( | |
| 553 file_util::FileEnumerator::FILES | | |
| 554 file_util::FileEnumerator::DIRECTORIES)); | |
| 555 } | |
| 556 | |
| 557 } // namespace fileapi | |
| OLD | NEW |