| 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/file_util.h" | 5 #include "base/file_util.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <psapi.h> | 8 #include <psapi.h> |
| 9 #include <shellapi.h> | 9 #include <shellapi.h> |
| 10 #include <shlobj.h> | 10 #include <shlobj.h> |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 bool DeleteFile(const FilePath& path, bool recursive) { | 85 bool DeleteFile(const FilePath& path, bool recursive) { |
| 86 ThreadRestrictions::AssertIOAllowed(); | 86 ThreadRestrictions::AssertIOAllowed(); |
| 87 | 87 |
| 88 if (path.value().length() >= MAX_PATH) | 88 if (path.value().length() >= MAX_PATH) |
| 89 return false; | 89 return false; |
| 90 | 90 |
| 91 if (!recursive) { | 91 if (!recursive) { |
| 92 // If not recursing, then first check to see if |path| is a directory. | 92 // If not recursing, then first check to see if |path| is a directory. |
| 93 // If it is, then remove it with RemoveDirectory. | 93 // If it is, then remove it with RemoveDirectory. |
| 94 PlatformFileInfo file_info; | 94 PlatformFileInfo file_info; |
| 95 if (file_util::GetFileInfo(path, &file_info) && file_info.is_directory) | 95 if (GetFileInfo(path, &file_info) && file_info.is_directory) |
| 96 return RemoveDirectory(path.value().c_str()) != 0; | 96 return RemoveDirectory(path.value().c_str()) != 0; |
| 97 | 97 |
| 98 // Otherwise, it's a file, wildcard or non-existant. Try DeleteFile first | 98 // Otherwise, it's a file, wildcard or non-existant. Try DeleteFile first |
| 99 // because it should be faster. If DeleteFile fails, then we fall through | 99 // because it should be faster. If DeleteFile fails, then we fall through |
| 100 // to SHFileOperation, which will do the right thing. | 100 // to SHFileOperation, which will do the right thing. |
| 101 if (::DeleteFile(path.value().c_str()) != 0) | 101 if (::DeleteFile(path.value().c_str()) != 0) |
| 102 return true; | 102 return true; |
| 103 } | 103 } |
| 104 | 104 |
| 105 // SHFILEOPSTRUCT wants the path to be terminated with two NULLs, | 105 // SHFILEOPSTRUCT wants the path to be terminated with two NULLs, |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 return false; | 386 return false; |
| 387 } | 387 } |
| 388 } else { | 388 } else { |
| 389 return true; | 389 return true; |
| 390 } | 390 } |
| 391 } | 391 } |
| 392 | 392 |
| 393 bool NormalizeFilePath(const FilePath& path, FilePath* real_path) { | 393 bool NormalizeFilePath(const FilePath& path, FilePath* real_path) { |
| 394 ThreadRestrictions::AssertIOAllowed(); | 394 ThreadRestrictions::AssertIOAllowed(); |
| 395 FilePath mapped_file; | 395 FilePath mapped_file; |
| 396 if (!file_util::NormalizeToNativeFilePath(path, &mapped_file)) | 396 if (!NormalizeToNativeFilePath(path, &mapped_file)) |
| 397 return false; | 397 return false; |
| 398 // NormalizeToNativeFilePath() will return a path that starts with | 398 // NormalizeToNativeFilePath() will return a path that starts with |
| 399 // "\Device\Harddisk...". Helper DevicePathToDriveLetterPath() | 399 // "\Device\Harddisk...". Helper DevicePathToDriveLetterPath() |
| 400 // will find a drive letter which maps to the path's device, so | 400 // will find a drive letter which maps to the path's device, so |
| 401 // that we return a path starting with a drive letter. | 401 // that we return a path starting with a drive letter. |
| 402 return file_util::DevicePathToDriveLetterPath(mapped_file, real_path); | 402 return DevicePathToDriveLetterPath(mapped_file, real_path); |
| 403 } | 403 } |
| 404 | 404 |
| 405 } // namespace base | 405 bool DevicePathToDriveLetterPath(const FilePath& nt_device_path, |
| 406 FilePath* out_drive_letter_path) { |
| 407 ThreadRestrictions::AssertIOAllowed(); |
| 406 | 408 |
| 407 // ----------------------------------------------------------------------------- | 409 // Get the mapping of drive letters to device paths. |
| 410 const int kDriveMappingSize = 1024; |
| 411 wchar_t drive_mapping[kDriveMappingSize] = {'\0'}; |
| 412 if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping)) { |
| 413 DLOG(ERROR) << "Failed to get drive mapping."; |
| 414 return false; |
| 415 } |
| 408 | 416 |
| 409 namespace file_util { | 417 // The drive mapping is a sequence of null terminated strings. |
| 418 // The last string is empty. |
| 419 wchar_t* drive_map_ptr = drive_mapping; |
| 420 wchar_t device_path_as_string[MAX_PATH]; |
| 421 wchar_t drive[] = L" :"; |
| 410 | 422 |
| 411 using base::DirectoryExists; | 423 // For each string in the drive mapping, get the junction that links |
| 412 using base::FilePath; | 424 // to it. If that junction is a prefix of |device_path|, then we |
| 413 using base::kFileShareAll; | 425 // know that |drive| is the real path prefix. |
| 426 while (*drive_map_ptr) { |
| 427 drive[0] = drive_map_ptr[0]; // Copy the drive letter. |
| 428 |
| 429 if (QueryDosDevice(drive, device_path_as_string, MAX_PATH)) { |
| 430 FilePath device_path(device_path_as_string); |
| 431 if (device_path == nt_device_path || |
| 432 device_path.IsParent(nt_device_path)) { |
| 433 *out_drive_letter_path = FilePath(drive + |
| 434 nt_device_path.value().substr(wcslen(device_path_as_string))); |
| 435 return true; |
| 436 } |
| 437 } |
| 438 // Move to the next drive letter string, which starts one |
| 439 // increment after the '\0' that terminates the current string. |
| 440 while (*drive_map_ptr++); |
| 441 } |
| 442 |
| 443 // No drive matched. The path does not start with a device junction |
| 444 // that is mounted as a drive letter. This means there is no drive |
| 445 // letter path to the volume that holds |device_path|, so fail. |
| 446 return false; |
| 447 } |
| 448 |
| 449 bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) { |
| 450 ThreadRestrictions::AssertIOAllowed(); |
| 451 // In Vista, GetFinalPathNameByHandle() would give us the real path |
| 452 // from a file handle. If we ever deprecate XP, consider changing the |
| 453 // code below to a call to GetFinalPathNameByHandle(). The method this |
| 454 // function uses is explained in the following msdn article: |
| 455 // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx |
| 456 base::win::ScopedHandle file_handle( |
| 457 ::CreateFile(path.value().c_str(), |
| 458 GENERIC_READ, |
| 459 kFileShareAll, |
| 460 NULL, |
| 461 OPEN_EXISTING, |
| 462 FILE_ATTRIBUTE_NORMAL, |
| 463 NULL)); |
| 464 if (!file_handle) |
| 465 return false; |
| 466 |
| 467 // Create a file mapping object. Can't easily use MemoryMappedFile, because |
| 468 // we only map the first byte, and need direct access to the handle. You can |
| 469 // not map an empty file, this call fails in that case. |
| 470 base::win::ScopedHandle file_map_handle( |
| 471 ::CreateFileMapping(file_handle.Get(), |
| 472 NULL, |
| 473 PAGE_READONLY, |
| 474 0, |
| 475 1, // Just one byte. No need to look at the data. |
| 476 NULL)); |
| 477 if (!file_map_handle) |
| 478 return false; |
| 479 |
| 480 // Use a view of the file to get the path to the file. |
| 481 void* file_view = MapViewOfFile(file_map_handle.Get(), |
| 482 FILE_MAP_READ, 0, 0, 1); |
| 483 if (!file_view) |
| 484 return false; |
| 485 |
| 486 // The expansion of |path| into a full path may make it longer. |
| 487 // GetMappedFileName() will fail if the result is longer than MAX_PATH. |
| 488 // Pad a bit to be safe. If kMaxPathLength is ever changed to be less |
| 489 // than MAX_PATH, it would be nessisary to test that GetMappedFileName() |
| 490 // not return kMaxPathLength. This would mean that only part of the |
| 491 // path fit in |mapped_file_path|. |
| 492 const int kMaxPathLength = MAX_PATH + 10; |
| 493 wchar_t mapped_file_path[kMaxPathLength]; |
| 494 bool success = false; |
| 495 HANDLE cp = GetCurrentProcess(); |
| 496 if (::GetMappedFileNameW(cp, file_view, mapped_file_path, kMaxPathLength)) { |
| 497 *nt_path = FilePath(mapped_file_path); |
| 498 success = true; |
| 499 } |
| 500 ::UnmapViewOfFile(file_view); |
| 501 return success; |
| 502 } |
| 414 | 503 |
| 415 // TODO(rkc): Work out if we want to handle NTFS junctions here or not, handle | 504 // TODO(rkc): Work out if we want to handle NTFS junctions here or not, handle |
| 416 // them if we do decide to. | 505 // them if we do decide to. |
| 417 bool IsLink(const FilePath& file_path) { | 506 bool IsLink(const FilePath& file_path) { |
| 418 return false; | 507 return false; |
| 419 } | 508 } |
| 420 | 509 |
| 421 bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) { | 510 bool GetFileInfo(const FilePath& file_path, PlatformFileInfo* results) { |
| 422 base::ThreadRestrictions::AssertIOAllowed(); | 511 ThreadRestrictions::AssertIOAllowed(); |
| 423 | 512 |
| 424 WIN32_FILE_ATTRIBUTE_DATA attr; | 513 WIN32_FILE_ATTRIBUTE_DATA attr; |
| 425 if (!GetFileAttributesEx(file_path.value().c_str(), | 514 if (!GetFileAttributesEx(file_path.value().c_str(), |
| 426 GetFileExInfoStandard, &attr)) { | 515 GetFileExInfoStandard, &attr)) { |
| 427 return false; | 516 return false; |
| 428 } | 517 } |
| 429 | 518 |
| 430 ULARGE_INTEGER size; | 519 ULARGE_INTEGER size; |
| 431 size.HighPart = attr.nFileSizeHigh; | 520 size.HighPart = attr.nFileSizeHigh; |
| 432 size.LowPart = attr.nFileSizeLow; | 521 size.LowPart = attr.nFileSizeLow; |
| 433 results->size = size.QuadPart; | 522 results->size = size.QuadPart; |
| 434 | 523 |
| 435 results->is_directory = | 524 results->is_directory = |
| 436 (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; | 525 (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; |
| 437 results->last_modified = base::Time::FromFileTime(attr.ftLastWriteTime); | 526 results->last_modified = Time::FromFileTime(attr.ftLastWriteTime); |
| 438 results->last_accessed = base::Time::FromFileTime(attr.ftLastAccessTime); | 527 results->last_accessed = Time::FromFileTime(attr.ftLastAccessTime); |
| 439 results->creation_time = base::Time::FromFileTime(attr.ftCreationTime); | 528 results->creation_time = Time::FromFileTime(attr.ftCreationTime); |
| 440 | 529 |
| 441 return true; | 530 return true; |
| 442 } | 531 } |
| 443 | 532 |
| 533 } // namespace base |
| 534 |
| 535 // ----------------------------------------------------------------------------- |
| 536 |
| 537 namespace file_util { |
| 538 |
| 539 using base::DirectoryExists; |
| 540 using base::FilePath; |
| 541 using base::kFileShareAll; |
| 542 |
| 444 FILE* OpenFile(const FilePath& filename, const char* mode) { | 543 FILE* OpenFile(const FilePath& filename, const char* mode) { |
| 445 base::ThreadRestrictions::AssertIOAllowed(); | 544 base::ThreadRestrictions::AssertIOAllowed(); |
| 446 std::wstring w_mode = ASCIIToWide(std::string(mode)); | 545 std::wstring w_mode = ASCIIToWide(std::string(mode)); |
| 447 return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO); | 546 return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO); |
| 448 } | 547 } |
| 449 | 548 |
| 450 FILE* OpenFile(const std::string& filename, const char* mode) { | 549 FILE* OpenFile(const std::string& filename, const char* mode) { |
| 451 base::ThreadRestrictions::AssertIOAllowed(); | 550 base::ThreadRestrictions::AssertIOAllowed(); |
| 452 return _fsopen(filename.c_str(), mode, _SH_DENYNO); | 551 return _fsopen(filename.c_str(), mode, _SH_DENYNO); |
| 453 } | 552 } |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 return true; | 651 return true; |
| 553 } | 652 } |
| 554 | 653 |
| 555 // Sets the current working directory for the process. | 654 // Sets the current working directory for the process. |
| 556 bool SetCurrentDirectory(const FilePath& directory) { | 655 bool SetCurrentDirectory(const FilePath& directory) { |
| 557 base::ThreadRestrictions::AssertIOAllowed(); | 656 base::ThreadRestrictions::AssertIOAllowed(); |
| 558 BOOL ret = ::SetCurrentDirectory(directory.value().c_str()); | 657 BOOL ret = ::SetCurrentDirectory(directory.value().c_str()); |
| 559 return ret != 0; | 658 return ret != 0; |
| 560 } | 659 } |
| 561 | 660 |
| 562 bool DevicePathToDriveLetterPath(const FilePath& nt_device_path, | |
| 563 FilePath* out_drive_letter_path) { | |
| 564 base::ThreadRestrictions::AssertIOAllowed(); | |
| 565 | |
| 566 // Get the mapping of drive letters to device paths. | |
| 567 const int kDriveMappingSize = 1024; | |
| 568 wchar_t drive_mapping[kDriveMappingSize] = {'\0'}; | |
| 569 if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping)) { | |
| 570 DLOG(ERROR) << "Failed to get drive mapping."; | |
| 571 return false; | |
| 572 } | |
| 573 | |
| 574 // The drive mapping is a sequence of null terminated strings. | |
| 575 // The last string is empty. | |
| 576 wchar_t* drive_map_ptr = drive_mapping; | |
| 577 wchar_t device_path_as_string[MAX_PATH]; | |
| 578 wchar_t drive[] = L" :"; | |
| 579 | |
| 580 // For each string in the drive mapping, get the junction that links | |
| 581 // to it. If that junction is a prefix of |device_path|, then we | |
| 582 // know that |drive| is the real path prefix. | |
| 583 while (*drive_map_ptr) { | |
| 584 drive[0] = drive_map_ptr[0]; // Copy the drive letter. | |
| 585 | |
| 586 if (QueryDosDevice(drive, device_path_as_string, MAX_PATH)) { | |
| 587 FilePath device_path(device_path_as_string); | |
| 588 if (device_path == nt_device_path || | |
| 589 device_path.IsParent(nt_device_path)) { | |
| 590 *out_drive_letter_path = FilePath(drive + | |
| 591 nt_device_path.value().substr(wcslen(device_path_as_string))); | |
| 592 return true; | |
| 593 } | |
| 594 } | |
| 595 // Move to the next drive letter string, which starts one | |
| 596 // increment after the '\0' that terminates the current string. | |
| 597 while (*drive_map_ptr++); | |
| 598 } | |
| 599 | |
| 600 // No drive matched. The path does not start with a device junction | |
| 601 // that is mounted as a drive letter. This means there is no drive | |
| 602 // letter path to the volume that holds |device_path|, so fail. | |
| 603 return false; | |
| 604 } | |
| 605 | |
| 606 bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) { | |
| 607 base::ThreadRestrictions::AssertIOAllowed(); | |
| 608 // In Vista, GetFinalPathNameByHandle() would give us the real path | |
| 609 // from a file handle. If we ever deprecate XP, consider changing the | |
| 610 // code below to a call to GetFinalPathNameByHandle(). The method this | |
| 611 // function uses is explained in the following msdn article: | |
| 612 // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx | |
| 613 base::win::ScopedHandle file_handle( | |
| 614 ::CreateFile(path.value().c_str(), | |
| 615 GENERIC_READ, | |
| 616 kFileShareAll, | |
| 617 NULL, | |
| 618 OPEN_EXISTING, | |
| 619 FILE_ATTRIBUTE_NORMAL, | |
| 620 NULL)); | |
| 621 if (!file_handle) | |
| 622 return false; | |
| 623 | |
| 624 // Create a file mapping object. Can't easily use MemoryMappedFile, because | |
| 625 // we only map the first byte, and need direct access to the handle. You can | |
| 626 // not map an empty file, this call fails in that case. | |
| 627 base::win::ScopedHandle file_map_handle( | |
| 628 ::CreateFileMapping(file_handle.Get(), | |
| 629 NULL, | |
| 630 PAGE_READONLY, | |
| 631 0, | |
| 632 1, // Just one byte. No need to look at the data. | |
| 633 NULL)); | |
| 634 if (!file_map_handle) | |
| 635 return false; | |
| 636 | |
| 637 // Use a view of the file to get the path to the file. | |
| 638 void* file_view = MapViewOfFile(file_map_handle.Get(), | |
| 639 FILE_MAP_READ, 0, 0, 1); | |
| 640 if (!file_view) | |
| 641 return false; | |
| 642 | |
| 643 // The expansion of |path| into a full path may make it longer. | |
| 644 // GetMappedFileName() will fail if the result is longer than MAX_PATH. | |
| 645 // Pad a bit to be safe. If kMaxPathLength is ever changed to be less | |
| 646 // than MAX_PATH, it would be nessisary to test that GetMappedFileName() | |
| 647 // not return kMaxPathLength. This would mean that only part of the | |
| 648 // path fit in |mapped_file_path|. | |
| 649 const int kMaxPathLength = MAX_PATH + 10; | |
| 650 wchar_t mapped_file_path[kMaxPathLength]; | |
| 651 bool success = false; | |
| 652 HANDLE cp = GetCurrentProcess(); | |
| 653 if (::GetMappedFileNameW(cp, file_view, mapped_file_path, kMaxPathLength)) { | |
| 654 *nt_path = FilePath(mapped_file_path); | |
| 655 success = true; | |
| 656 } | |
| 657 ::UnmapViewOfFile(file_view); | |
| 658 return success; | |
| 659 } | |
| 660 | |
| 661 int GetMaximumPathComponentLength(const FilePath& path) { | 661 int GetMaximumPathComponentLength(const FilePath& path) { |
| 662 base::ThreadRestrictions::AssertIOAllowed(); | 662 base::ThreadRestrictions::AssertIOAllowed(); |
| 663 | 663 |
| 664 wchar_t volume_path[MAX_PATH]; | 664 wchar_t volume_path[MAX_PATH]; |
| 665 if (!GetVolumePathNameW(path.NormalizePathSeparators().value().c_str(), | 665 if (!GetVolumePathNameW(path.NormalizePathSeparators().value().c_str(), |
| 666 volume_path, | 666 volume_path, |
| 667 arraysize(volume_path))) { | 667 arraysize(volume_path))) { |
| 668 return -1; | 668 return -1; |
| 669 } | 669 } |
| 670 | 670 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 744 // Like Move, this function is not transactional, so we just | 744 // Like Move, this function is not transactional, so we just |
| 745 // leave the copied bits behind if deleting from_path fails. | 745 // leave the copied bits behind if deleting from_path fails. |
| 746 // If to_path exists previously then we have already overwritten | 746 // If to_path exists previously then we have already overwritten |
| 747 // it by now, we don't get better off by deleting the new bits. | 747 // it by now, we don't get better off by deleting the new bits. |
| 748 } | 748 } |
| 749 return false; | 749 return false; |
| 750 } | 750 } |
| 751 | 751 |
| 752 } // namespace internal | 752 } // namespace internal |
| 753 } // namespace base | 753 } // namespace base |
| OLD | NEW |