native_media_file_util.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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 "chrome/browser/media_galleries/fileapi/native_media_file_util.h" 6 7#include <string> 8 9#include "base/bind.h" 10#include "base/bind_helpers.h" 11#include "base/file_util.h" 12#include "base/files/file_enumerator.h" 13#include "base/strings/string_util.h" 14#include "base/task_runner_util.h" 15#include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h" 16#include "chrome/browser/media_galleries/fileapi/media_path_filter.h" 17#include "content/public/browser/browser_thread.h" 18#include "net/base/mime_sniffer.h" 19#include "url/gurl.h" 20#include "webkit/browser/fileapi/file_system_context.h" 21#include "webkit/browser/fileapi/file_system_operation_context.h" 22#include "webkit/browser/fileapi/file_system_task_runners.h" 23#include "webkit/browser/fileapi/native_file_util.h" 24#include "webkit/common/blob/shareable_file_reference.h" 25 26namespace chrome { 27 28namespace { 29 30// Modelled after ScopedFILEClose. 31struct ScopedPlatformFileClose { 32 void operator()(base::PlatformFile* file) { 33 if (file && *file != base::kInvalidPlatformFileValue) 34 base::ClosePlatformFile(*file); 35 } 36}; 37 38typedef scoped_ptr<base::PlatformFile, ScopedPlatformFileClose> 39 ScopedPlatformFile; 40 41// Used to skip the hidden folders and files. Returns true if the file specified 42// by |path| should be skipped. 43bool ShouldSkip(const base::FilePath& path) { 44 const base::FilePath::StringType base_name = path.BaseName().value(); 45 if (base_name.empty()) 46 return false; 47 48 // Dot files (aka hidden files) 49 if (base_name[0] == '.') 50 return true; 51 52 // Mac OS X file. 53 if (base_name == FILE_PATH_LITERAL("__MACOSX")) 54 return true; 55 56#if defined(OS_WIN) 57 DWORD file_attributes = ::GetFileAttributes(path.value().c_str()); 58 if ((file_attributes != INVALID_FILE_ATTRIBUTES) && 59 ((file_attributes & FILE_ATTRIBUTE_HIDDEN) != 0)) 60 return true; 61#else 62 // Windows always creates a recycle bin folder in the attached device to store 63 // all the deleted contents. On non-windows operating systems, there is no way 64 // to get the hidden attribute of windows recycle bin folders that are present 65 // on the attached device. Therefore, compare the file path name to the 66 // recycle bin name and exclude those folders. For more details, please refer 67 // to http://support.microsoft.com/kb/171694. 68 const char win_98_recycle_bin_name[] = "RECYCLED"; 69 const char win_xp_recycle_bin_name[] = "RECYCLER"; 70 const char win_vista_recycle_bin_name[] = "$Recycle.bin"; 71 if ((base::strncasecmp(base_name.c_str(), 72 win_98_recycle_bin_name, 73 strlen(win_98_recycle_bin_name)) == 0) || 74 (base::strncasecmp(base_name.c_str(), 75 win_xp_recycle_bin_name, 76 strlen(win_xp_recycle_bin_name)) == 0) || 77 (base::strncasecmp(base_name.c_str(), 78 win_vista_recycle_bin_name, 79 strlen(win_vista_recycle_bin_name)) == 0)) 80 return true; 81#endif 82 return false; 83} 84 85// Returns true if the current thread is capable of doing IO. 86bool IsOnTaskRunnerThread(fileapi::FileSystemOperationContext* context) { 87 return context->task_runner()->RunsTasksOnCurrentThread(); 88} 89 90MediaPathFilter* GetMediaPathFilter( 91 fileapi::FileSystemOperationContext* context) { 92 return context->GetUserValue<MediaPathFilter*>( 93 MediaFileSystemMountPointProvider::kMediaPathFilterKey); 94} 95 96} // namespace 97 98NativeMediaFileUtil::NativeMediaFileUtil() : weak_factory_(this) { 99} 100 101NativeMediaFileUtil::~NativeMediaFileUtil() { 102} 103 104// static 105base::PlatformFileError NativeMediaFileUtil::IsMediaFile( 106 const base::FilePath& path) { 107 base::PlatformFile file_handle; 108 const int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ; 109 base::PlatformFileError error = 110 fileapi::NativeFileUtil::CreateOrOpen(path, flags, &file_handle, NULL); 111 if (error != base::PLATFORM_FILE_OK) 112 return error; 113 114 ScopedPlatformFile scoped_platform_file(&file_handle); 115 char buffer[net::kMaxBytesToSniff]; 116 117 // Read as much as net::SniffMimeTypeFromLocalData() will bother looking at. 118 int64 len = 119 base::ReadPlatformFile(file_handle, 0, buffer, net::kMaxBytesToSniff); 120 if (len < 0) 121 return base::PLATFORM_FILE_ERROR_FAILED; 122 if (len == 0) 123 return base::PLATFORM_FILE_ERROR_SECURITY; 124 125 std::string mime_type; 126 if (!net::SniffMimeTypeFromLocalData(buffer, len, &mime_type)) 127 return base::PLATFORM_FILE_ERROR_SECURITY; 128 129 if (StartsWithASCII(mime_type, "image/", true) || 130 StartsWithASCII(mime_type, "audio/", true) || 131 StartsWithASCII(mime_type, "video/", true) || 132 mime_type == "application/x-shockwave-flash") { 133 return base::PLATFORM_FILE_OK; 134 } 135 return base::PLATFORM_FILE_ERROR_SECURITY; 136} 137 138bool NativeMediaFileUtil::CreateOrOpen( 139 scoped_ptr<fileapi::FileSystemOperationContext> context, 140 const fileapi::FileSystemURL& url, 141 int file_flags, 142 const CreateOrOpenCallback& callback) { 143 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 144 // Only called by NaCl, which should not have access to media file systems. 145 base::PlatformFile invalid_file(base::kInvalidPlatformFileValue); 146 if (!callback.is_null()) { 147 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, 148 base::PassPlatformFile(&invalid_file)); 149 } 150 return true; 151} 152 153bool NativeMediaFileUtil::EnsureFileExists( 154 scoped_ptr<fileapi::FileSystemOperationContext> context, 155 const fileapi::FileSystemURL& url, 156 const EnsureFileExistsCallback& callback) { 157 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 158 if (!callback.is_null()) 159 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, false); 160 return true; 161} 162 163bool NativeMediaFileUtil::CreateDirectory( 164 scoped_ptr<fileapi::FileSystemOperationContext> context, 165 const fileapi::FileSystemURL& url, 166 bool exclusive, 167 bool recursive, 168 const StatusCallback& callback) { 169 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 170 fileapi::FileSystemOperationContext* context_ptr = context.get(); 171 return context_ptr->task_runner()->PostTask( 172 FROM_HERE, 173 base::Bind(&NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread, 174 weak_factory_.GetWeakPtr(), base::Passed(&context), 175 url, exclusive, recursive, callback)); 176} 177 178bool NativeMediaFileUtil::GetFileInfo( 179 scoped_ptr<fileapi::FileSystemOperationContext> context, 180 const fileapi::FileSystemURL& url, 181 const GetFileInfoCallback& callback) { 182 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 183 fileapi::FileSystemOperationContext* context_ptr = context.get(); 184 return context_ptr->task_runner()->PostTask( 185 FROM_HERE, 186 base::Bind(&NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread, 187 weak_factory_.GetWeakPtr(), base::Passed(&context), 188 url, callback)); 189} 190 191bool NativeMediaFileUtil::ReadDirectory( 192 scoped_ptr<fileapi::FileSystemOperationContext> context, 193 const fileapi::FileSystemURL& url, 194 const ReadDirectoryCallback& callback) { 195 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 196 fileapi::FileSystemOperationContext* context_ptr = context.get(); 197 return context_ptr->task_runner()->PostTask( 198 FROM_HERE, 199 base::Bind(&NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread, 200 weak_factory_.GetWeakPtr(), base::Passed(&context), 201 url, callback)); 202} 203 204bool NativeMediaFileUtil::Touch( 205 scoped_ptr<fileapi::FileSystemOperationContext> context, 206 const fileapi::FileSystemURL& url, 207 const base::Time& last_access_time, 208 const base::Time& last_modified_time, 209 const StatusCallback& callback) { 210 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 211 if (!callback.is_null()) 212 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY); 213 return true; 214} 215 216bool NativeMediaFileUtil::Truncate( 217 scoped_ptr<fileapi::FileSystemOperationContext> context, 218 const fileapi::FileSystemURL& url, 219 int64 length, 220 const StatusCallback& callback) { 221 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 222 if (!callback.is_null()) 223 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY); 224 return true; 225} 226 227bool NativeMediaFileUtil::CopyFileLocal( 228 scoped_ptr<fileapi::FileSystemOperationContext> context, 229 const fileapi::FileSystemURL& src_url, 230 const fileapi::FileSystemURL& dest_url, 231 const StatusCallback& callback) { 232 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 233 fileapi::FileSystemOperationContext* context_ptr = context.get(); 234 return context_ptr->task_runner()->PostTask( 235 FROM_HERE, 236 base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread, 237 weak_factory_.GetWeakPtr(), base::Passed(&context), 238 src_url, dest_url, true /* copy */, callback)); 239} 240 241bool NativeMediaFileUtil::MoveFileLocal( 242 scoped_ptr<fileapi::FileSystemOperationContext> context, 243 const fileapi::FileSystemURL& src_url, 244 const fileapi::FileSystemURL& dest_url, 245 const StatusCallback& callback) { 246 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 247 fileapi::FileSystemOperationContext* context_ptr = context.get(); 248 return context_ptr->task_runner()->PostTask( 249 FROM_HERE, 250 base::Bind(&NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread, 251 weak_factory_.GetWeakPtr(), base::Passed(&context), 252 src_url, dest_url, false /* copy */, callback)); 253} 254 255bool NativeMediaFileUtil::CopyInForeignFile( 256 scoped_ptr<fileapi::FileSystemOperationContext> context, 257 const base::FilePath& src_file_path, 258 const fileapi::FileSystemURL& dest_url, 259 const StatusCallback& callback) { 260 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 261 fileapi::FileSystemOperationContext* context_ptr = context.get(); 262 return context_ptr->task_runner()->PostTask( 263 FROM_HERE, 264 base::Bind(&NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread, 265 weak_factory_.GetWeakPtr(), base::Passed(&context), 266 src_file_path, dest_url, callback)); 267} 268 269bool NativeMediaFileUtil::DeleteFile( 270 scoped_ptr<fileapi::FileSystemOperationContext> context, 271 const fileapi::FileSystemURL& url, 272 const StatusCallback& callback) { 273 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 274 if (!callback.is_null()) 275 callback.Run(base::PLATFORM_FILE_ERROR_SECURITY); 276 return true; 277} 278 279// This is needed to support Copy and Move. 280bool NativeMediaFileUtil::DeleteDirectory( 281 scoped_ptr<fileapi::FileSystemOperationContext> context, 282 const fileapi::FileSystemURL& url, 283 const StatusCallback& callback) { 284 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 285 fileapi::FileSystemOperationContext* context_ptr = context.get(); 286 return context_ptr->task_runner()->PostTask( 287 FROM_HERE, 288 base::Bind(&NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread, 289 weak_factory_.GetWeakPtr(), base::Passed(&context), 290 url, callback)); 291} 292 293bool NativeMediaFileUtil::DeleteRecursively( 294 scoped_ptr<fileapi::FileSystemOperationContext> context, 295 const fileapi::FileSystemURL& url, 296 const StatusCallback& callback) { 297 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 298 if (!callback.is_null()) 299 callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION); 300 return true; 301} 302 303bool NativeMediaFileUtil::CreateSnapshotFile( 304 scoped_ptr<fileapi::FileSystemOperationContext> context, 305 const fileapi::FileSystemURL& url, 306 const CreateSnapshotFileCallback& callback) { 307 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 308 fileapi::FileSystemOperationContext* context_ptr = context.get(); 309 return context_ptr->task_runner()->PostTask( 310 FROM_HERE, 311 base::Bind(&NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread, 312 weak_factory_.GetWeakPtr(), base::Passed(&context), 313 url, callback)); 314} 315 316void NativeMediaFileUtil::CreateDirectoryOnTaskRunnerThread( 317 scoped_ptr<fileapi::FileSystemOperationContext> context, 318 const fileapi::FileSystemURL& url, 319 bool exclusive, 320 bool recursive, 321 const StatusCallback& callback) { 322 DCHECK(IsOnTaskRunnerThread(context.get())); 323 base::PlatformFileError error = 324 CreateDirectorySync(context.get(), url, exclusive, recursive); 325 if (callback.is_null()) 326 return; 327 content::BrowserThread::PostTask( 328 content::BrowserThread::IO, 329 FROM_HERE, 330 base::Bind(callback, error)); 331} 332 333void NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread( 334 scoped_ptr<fileapi::FileSystemOperationContext> context, 335 const fileapi::FileSystemURL& url, 336 const GetFileInfoCallback& callback) { 337 DCHECK(IsOnTaskRunnerThread(context.get())); 338 base::PlatformFileInfo file_info; 339 // TODO(thestig): remove this. 340 base::FilePath platform_path; 341 base::PlatformFileError error = 342 GetFileInfoSync(context.get(), url, &file_info, &platform_path); 343 if (callback.is_null()) 344 return; 345 content::BrowserThread::PostTask( 346 content::BrowserThread::IO, 347 FROM_HERE, 348 base::Bind(callback, error, file_info)); 349} 350 351void NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread( 352 scoped_ptr<fileapi::FileSystemOperationContext> context, 353 const fileapi::FileSystemURL& url, 354 const ReadDirectoryCallback& callback) { 355 DCHECK(IsOnTaskRunnerThread(context.get())); 356 EntryList entry_list; 357 base::PlatformFileError error = 358 ReadDirectorySync(context.get(), url, &entry_list); 359 if (callback.is_null()) 360 return; 361 content::BrowserThread::PostTask( 362 content::BrowserThread::IO, 363 FROM_HERE, 364 base::Bind(callback, error, entry_list, false /* has_more */)); 365} 366 367void NativeMediaFileUtil::CopyOrMoveFileLocalOnTaskRunnerThread( 368 scoped_ptr<fileapi::FileSystemOperationContext> context, 369 const fileapi::FileSystemURL& src_url, 370 const fileapi::FileSystemURL& dest_url, 371 bool copy, 372 const StatusCallback& callback) { 373 DCHECK(IsOnTaskRunnerThread(context.get())); 374 base::PlatformFileError error = 375 CopyOrMoveFileSync(context.get(), src_url, dest_url, copy); 376 if (callback.is_null()) 377 return; 378 content::BrowserThread::PostTask( 379 content::BrowserThread::IO, 380 FROM_HERE, 381 base::Bind(callback, error)); 382} 383 384void NativeMediaFileUtil::CopyInForeignFileOnTaskRunnerThread( 385 scoped_ptr<fileapi::FileSystemOperationContext> context, 386 const base::FilePath& src_file_path, 387 const fileapi::FileSystemURL& dest_url, 388 const StatusCallback& callback) { 389 DCHECK(IsOnTaskRunnerThread(context.get())); 390 base::PlatformFileError error = 391 CopyInForeignFileSync(context.get(), src_file_path, dest_url); 392 if (callback.is_null()) 393 return; 394 content::BrowserThread::PostTask( 395 content::BrowserThread::IO, 396 FROM_HERE, 397 base::Bind(callback, error)); 398} 399 400void NativeMediaFileUtil::DeleteDirectoryOnTaskRunnerThread( 401 scoped_ptr<fileapi::FileSystemOperationContext> context, 402 const fileapi::FileSystemURL& url, 403 const StatusCallback& callback) { 404 DCHECK(IsOnTaskRunnerThread(context.get())); 405 base::PlatformFileError error = DeleteDirectorySync(context.get(), url); 406 if (callback.is_null()) 407 return; 408 content::BrowserThread::PostTask( 409 content::BrowserThread::IO, 410 FROM_HERE, 411 base::Bind(callback, error)); 412} 413 414void NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread( 415 scoped_ptr<fileapi::FileSystemOperationContext> context, 416 const fileapi::FileSystemURL& url, 417 const CreateSnapshotFileCallback& callback) { 418 DCHECK(IsOnTaskRunnerThread(context.get())); 419 base::PlatformFileInfo file_info; 420 base::FilePath platform_path; 421 scoped_refptr<webkit_blob::ShareableFileReference> file_ref; 422 base::PlatformFileError error = 423 CreateSnapshotFileSync(context.get(), url, &file_info, &platform_path, 424 &file_ref); 425 if (callback.is_null()) 426 return; 427 content::BrowserThread::PostTask( 428 content::BrowserThread::IO, 429 FROM_HERE, 430 base::Bind(callback, error, file_info, platform_path, file_ref)); 431} 432 433base::PlatformFileError NativeMediaFileUtil::CreateDirectorySync( 434 fileapi::FileSystemOperationContext* context, 435 const fileapi::FileSystemURL& url, 436 bool exclusive, 437 bool recursive) { 438 base::FilePath file_path; 439 base::PlatformFileError error = GetLocalFilePath(context, url, &file_path); 440 if (error != base::PLATFORM_FILE_OK) 441 return error; 442 return fileapi::NativeFileUtil::CreateDirectory(file_path, exclusive, 443 recursive); 444} 445 446base::PlatformFileError NativeMediaFileUtil::CopyOrMoveFileSync( 447 fileapi::FileSystemOperationContext* context, 448 const fileapi::FileSystemURL& src_url, 449 const fileapi::FileSystemURL& dest_url, 450 bool copy) { 451 DCHECK(IsOnTaskRunnerThread(context)); 452 base::FilePath src_file_path; 453 base::PlatformFileError error = 454 GetFilteredLocalFilePathForExistingFileOrDirectory( 455 context, src_url, 456 base::PLATFORM_FILE_ERROR_NOT_FOUND, 457 &src_file_path); 458 if (error != base::PLATFORM_FILE_OK) 459 return error; 460 if (fileapi::NativeFileUtil::DirectoryExists(src_file_path)) 461 return base::PLATFORM_FILE_ERROR_NOT_A_FILE; 462 463 base::FilePath dest_file_path; 464 error = GetLocalFilePath(context, dest_url, &dest_file_path); 465 if (error != base::PLATFORM_FILE_OK) 466 return error; 467 base::PlatformFileInfo file_info; 468 error = fileapi::NativeFileUtil::GetFileInfo(dest_file_path, &file_info); 469 if (error != base::PLATFORM_FILE_OK && 470 error != base::PLATFORM_FILE_ERROR_NOT_FOUND) 471 return error; 472 if (error == base::PLATFORM_FILE_OK && file_info.is_directory) 473 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; 474 if (!GetMediaPathFilter(context)->Match(dest_file_path)) 475 return base::PLATFORM_FILE_ERROR_SECURITY; 476 477 return fileapi::NativeFileUtil::CopyOrMoveFile(src_file_path, dest_file_path, 478 copy); 479} 480 481base::PlatformFileError NativeMediaFileUtil::CopyInForeignFileSync( 482 fileapi::FileSystemOperationContext* context, 483 const base::FilePath& src_file_path, 484 const fileapi::FileSystemURL& dest_url) { 485 DCHECK(IsOnTaskRunnerThread(context)); 486 if (src_file_path.empty()) 487 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; 488 489 base::FilePath dest_file_path; 490 base::PlatformFileError error = 491 GetFilteredLocalFilePath(context, dest_url, &dest_file_path); 492 if (error != base::PLATFORM_FILE_OK) 493 return error; 494 return fileapi::NativeFileUtil::CopyOrMoveFile(src_file_path, dest_file_path, 495 true); 496} 497 498base::PlatformFileError NativeMediaFileUtil::GetFileInfoSync( 499 fileapi::FileSystemOperationContext* context, 500 const fileapi::FileSystemURL& url, 501 base::PlatformFileInfo* file_info, 502 base::FilePath* platform_path) { 503 DCHECK(context); 504 DCHECK(IsOnTaskRunnerThread(context)); 505 DCHECK(file_info); 506 DCHECK(GetMediaPathFilter(context)); 507 508 base::FilePath file_path; 509 base::PlatformFileError error = GetLocalFilePath(context, url, &file_path); 510 if (error != base::PLATFORM_FILE_OK) 511 return error; 512 if (file_util::IsLink(file_path)) 513 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 514 error = fileapi::NativeFileUtil::GetFileInfo(file_path, file_info); 515 if (error != base::PLATFORM_FILE_OK) 516 return error; 517 518 if (platform_path) 519 *platform_path = file_path; 520 if (file_info->is_directory || 521 GetMediaPathFilter(context)->Match(file_path)) { 522 return base::PLATFORM_FILE_OK; 523 } 524 return base::PLATFORM_FILE_ERROR_NOT_FOUND; 525} 526 527base::PlatformFileError NativeMediaFileUtil::GetLocalFilePath( 528 fileapi::FileSystemOperationContext* context, 529 const fileapi::FileSystemURL& url, 530 base::FilePath* local_file_path) { 531 DCHECK(local_file_path); 532 DCHECK(url.is_valid()); 533 if (url.path().empty()) { 534 // Root direcory case, which should not be accessed. 535 return base::PLATFORM_FILE_ERROR_ACCESS_DENIED; 536 } 537 *local_file_path = url.path(); 538 return base::PLATFORM_FILE_OK; 539} 540 541base::PlatformFileError NativeMediaFileUtil::ReadDirectorySync( 542 fileapi::FileSystemOperationContext* context, 543 const fileapi::FileSystemURL& url, 544 EntryList* file_list) { 545 DCHECK(IsOnTaskRunnerThread(context)); 546 DCHECK(file_list); 547 DCHECK(file_list->empty()); 548 base::PlatformFileInfo file_info; 549 base::FilePath dir_path; 550 base::PlatformFileError error = 551 GetFileInfoSync(context, url, &file_info, &dir_path); 552 553 if (error != base::PLATFORM_FILE_OK) 554 return error; 555 556 if (!file_info.is_directory) 557 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; 558 559 base::FileEnumerator file_enum( 560 dir_path, 561 false /* recursive */, 562 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); 563 for (base::FilePath enum_path = file_enum.Next(); 564 !enum_path.empty(); 565 enum_path = file_enum.Next()) { 566 // Skip symlinks. 567 if (file_util::IsLink(enum_path)) 568 continue; 569 570 base::FileEnumerator::FileInfo info = file_enum.GetInfo(); 571 572 // NativeMediaFileUtil skip criteria. 573 if (ShouldSkip(enum_path)) 574 continue; 575 if (!info.IsDirectory() && !GetMediaPathFilter(context)->Match(enum_path)) 576 continue; 577 578 fileapi::DirectoryEntry entry; 579 entry.is_directory = info.IsDirectory(); 580 entry.name = enum_path.BaseName().value(); 581 entry.size = info.GetSize(); 582 entry.last_modified_time = info.GetLastModifiedTime(); 583 584 file_list->push_back(entry); 585 } 586 587 return base::PLATFORM_FILE_OK; 588} 589 590base::PlatformFileError NativeMediaFileUtil::DeleteDirectorySync( 591 fileapi::FileSystemOperationContext* context, 592 const fileapi::FileSystemURL& url) { 593 DCHECK(IsOnTaskRunnerThread(context)); 594 base::FilePath file_path; 595 base::PlatformFileError error = GetLocalFilePath(context, url, &file_path); 596 if (error != base::PLATFORM_FILE_OK) 597 return error; 598 return fileapi::NativeFileUtil::DeleteDirectory(file_path); 599} 600 601base::PlatformFileError NativeMediaFileUtil::CreateSnapshotFileSync( 602 fileapi::FileSystemOperationContext* context, 603 const fileapi::FileSystemURL& url, 604 base::PlatformFileInfo* file_info, 605 base::FilePath* platform_path, 606 scoped_refptr<webkit_blob::ShareableFileReference>* file_ref) { 607 DCHECK(IsOnTaskRunnerThread(context)); 608 base::PlatformFileError error = 609 GetFileInfoSync(context, url, file_info, platform_path); 610 if (error == base::PLATFORM_FILE_OK && file_info->is_directory) 611 error = base::PLATFORM_FILE_ERROR_NOT_A_FILE; 612 if (error == base::PLATFORM_FILE_OK) 613 error = NativeMediaFileUtil::IsMediaFile(*platform_path); 614 615 // We're just returning the local file information. 616 *file_ref = scoped_refptr<webkit_blob::ShareableFileReference>(); 617 618 return error; 619} 620 621base::PlatformFileError NativeMediaFileUtil::GetFilteredLocalFilePath( 622 fileapi::FileSystemOperationContext* context, 623 const fileapi::FileSystemURL& file_system_url, 624 base::FilePath* local_file_path) { 625 DCHECK(IsOnTaskRunnerThread(context)); 626 base::FilePath file_path; 627 base::PlatformFileError error = 628 GetLocalFilePath(context, file_system_url, &file_path); 629 if (error != base::PLATFORM_FILE_OK) 630 return error; 631 if (!GetMediaPathFilter(context)->Match(file_path)) 632 return base::PLATFORM_FILE_ERROR_SECURITY; 633 634 *local_file_path = file_path; 635 return base::PLATFORM_FILE_OK; 636} 637 638base::PlatformFileError 639NativeMediaFileUtil::GetFilteredLocalFilePathForExistingFileOrDirectory( 640 fileapi::FileSystemOperationContext* context, 641 const fileapi::FileSystemURL& file_system_url, 642 base::PlatformFileError failure_error, 643 base::FilePath* local_file_path) { 644 DCHECK(IsOnTaskRunnerThread(context)); 645 base::FilePath file_path; 646 base::PlatformFileError error = 647 GetLocalFilePath(context, file_system_url, &file_path); 648 if (error != base::PLATFORM_FILE_OK) 649 return error; 650 651 if (!file_util::PathExists(file_path)) 652 return failure_error; 653 base::PlatformFileInfo file_info; 654 if (!file_util::GetFileInfo(file_path, &file_info)) 655 return base::PLATFORM_FILE_ERROR_FAILED; 656 657 if (!file_info.is_directory && 658 !GetMediaPathFilter(context)->Match(file_path)) { 659 return failure_error; 660 } 661 662 *local_file_path = file_path; 663 return base::PLATFORM_FILE_OK; 664} 665 666} // namespace chrome 667