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 |