diff options
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/pathutil.cpp')
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/pathutil.cpp | 404 |
1 files changed, 340 insertions, 64 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp index 0e2a5dec..dd5385fc 100644 --- a/src/libs/dutil/WixToolset.DUtil/pathutil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/pathutil.cpp | |||
@@ -20,6 +20,11 @@ | |||
20 | 20 | ||
21 | #define PATH_GOOD_ENOUGH 64 | 21 | #define PATH_GOOD_ENOUGH 64 |
22 | 22 | ||
23 | typedef DWORD(APIENTRY* PFN_GETTEMPPATH2W)( | ||
24 | __in DWORD BufferLength, | ||
25 | __out LPWSTR Buffer | ||
26 | ); | ||
27 | |||
23 | static BOOL IsPathSeparatorChar( | 28 | static BOOL IsPathSeparatorChar( |
24 | __in WCHAR wc | 29 | __in WCHAR wc |
25 | ); | 30 | ); |
@@ -527,28 +532,55 @@ DAPI_(HRESULT) PathForCurrentProcess( | |||
527 | ) | 532 | ) |
528 | { | 533 | { |
529 | HRESULT hr = S_OK; | 534 | HRESULT hr = S_OK; |
530 | DWORD cch = MAX_PATH; | 535 | WCHAR smallBuffer[1] = { }; |
536 | SIZE_T cchMax = 0; | ||
537 | DWORD cchBuffer = 0; | ||
538 | DWORD cch = 0; | ||
539 | DWORD dwMaxAttempts = 20; | ||
531 | 540 | ||
532 | do | 541 | // GetModuleFileNameW didn't originally set the last error when the buffer was too small. |
542 | ::SetLastError(ERROR_SUCCESS); | ||
543 | |||
544 | cch = ::GetModuleFileNameW(hModule, smallBuffer, countof(smallBuffer)); | ||
545 | PathExitOnNullWithLastError(cch, hr, "Failed to get size of path for executing process."); | ||
546 | |||
547 | if (*psczFullPath && ERROR_INSUFFICIENT_BUFFER == ::GetLastError()) | ||
533 | { | 548 | { |
534 | hr = StrAlloc(psczFullPath, cch); | 549 | hr = StrMaxLength(*psczFullPath, &cchMax); |
535 | PathExitOnFailure(hr, "Failed to allocate string for module path."); | 550 | PathExitOnFailure(hr, "Failed to get max length of input buffer."); |
551 | |||
552 | cchBuffer = (DWORD)min(DWORD_MAX, cchMax); | ||
553 | } | ||
554 | else | ||
555 | { | ||
556 | cchBuffer = MAX_PATH + 1; | ||
557 | |||
558 | hr = StrAlloc(psczFullPath, cchBuffer); | ||
559 | PathExitOnFailure(hr, "Failed to allocate space for module path."); | ||
560 | } | ||
561 | |||
562 | ::SetLastError(ERROR_SUCCESS); | ||
536 | 563 | ||
537 | DWORD cchRequired = ::GetModuleFileNameW(hModule, *psczFullPath, cch); | 564 | for (DWORD i = 0; i < dwMaxAttempts; ++i) |
538 | if (0 == cchRequired) | 565 | { |
566 | cch = ::GetModuleFileNameW(hModule, *psczFullPath, cchBuffer); | ||
567 | PathExitOnNullWithLastError(cch, hr, "Failed to get path for executing process."); | ||
568 | |||
569 | if (ERROR_INSUFFICIENT_BUFFER != ::GetLastError()) | ||
539 | { | 570 | { |
540 | PathExitWithLastError(hr, "Failed to get path for executing process."); | 571 | break; |
541 | } | 572 | } |
542 | else if (cchRequired == cch) | 573 | |
574 | if ((dwMaxAttempts - 1) == i) | ||
543 | { | 575 | { |
544 | cch = cchRequired + 1; | 576 | PathExitWithRootFailure(hr, E_FAIL, "Unexpected failure getting path for executing process."); |
545 | hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); | ||
546 | } | 577 | } |
547 | else | 578 | |
548 | { | 579 | cchBuffer *= 2; |
549 | hr = S_OK; | 580 | |
550 | } | 581 | hr = StrAlloc(psczFullPath, cchBuffer); |
551 | } while (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr); | 582 | PathExitOnFailure(hr, "Failed to re-allocate more space for module path."); |
583 | } | ||
552 | 584 | ||
553 | LExit: | 585 | LExit: |
554 | return hr; | 586 | return hr; |
@@ -582,17 +614,18 @@ DAPI_(HRESULT) PathCreateTempFile( | |||
582 | __in_opt LPCWSTR wzDirectory, | 614 | __in_opt LPCWSTR wzDirectory, |
583 | __in_opt __format_string LPCWSTR wzFileNameTemplate, | 615 | __in_opt __format_string LPCWSTR wzFileNameTemplate, |
584 | __in DWORD dwUniqueCount, | 616 | __in DWORD dwUniqueCount, |
617 | __in_z LPCWSTR wzPrefix, | ||
585 | __in DWORD dwFileAttributes, | 618 | __in DWORD dwFileAttributes, |
586 | __out_opt LPWSTR* psczTempFile, | 619 | __out_opt LPWSTR* psczTempFile, |
587 | __out_opt HANDLE* phTempFile | 620 | __out_opt HANDLE* phTempFile |
588 | ) | 621 | ) |
589 | { | 622 | { |
590 | AssertSz(0 < dwUniqueCount, "Must specify a non-zero unique count."); | 623 | Assert(wzPrefix); |
624 | AssertSz(!wzFileNameTemplate || !*wzFileNameTemplate || 0 < dwUniqueCount, "Must specify a non-zero unique count."); | ||
591 | 625 | ||
592 | HRESULT hr = S_OK; | 626 | HRESULT hr = S_OK; |
593 | 627 | ||
594 | LPWSTR sczTempPath = NULL; | 628 | LPWSTR sczTempPath = NULL; |
595 | DWORD cchTempPath = MAX_PATH; | ||
596 | 629 | ||
597 | HANDLE hTempFile = INVALID_HANDLE_VALUE; | 630 | HANDLE hTempFile = INVALID_HANDLE_VALUE; |
598 | LPWSTR scz = NULL; | 631 | LPWSTR scz = NULL; |
@@ -605,13 +638,8 @@ DAPI_(HRESULT) PathCreateTempFile( | |||
605 | } | 638 | } |
606 | else | 639 | else |
607 | { | 640 | { |
608 | hr = StrAlloc(&sczTempPath, cchTempPath); | 641 | hr = PathGetTempPath(&sczTempPath, NULL); |
609 | PathExitOnFailure(hr, "Failed to allocate memory for the temp path."); | 642 | PathExitOnFailure(hr, "Failed to get temp path."); |
610 | |||
611 | if (!::GetTempPathW(cchTempPath, sczTempPath)) | ||
612 | { | ||
613 | PathExitWithLastError(hr, "Failed to get temp path."); | ||
614 | } | ||
615 | } | 643 | } |
616 | 644 | ||
617 | if (wzFileNameTemplate && *wzFileNameTemplate) | 645 | if (wzFileNameTemplate && *wzFileNameTemplate) |
@@ -621,7 +649,7 @@ DAPI_(HRESULT) PathCreateTempFile( | |||
621 | hr = StrAllocFormatted(&scz, wzFileNameTemplate, i); | 649 | hr = StrAllocFormatted(&scz, wzFileNameTemplate, i); |
622 | PathExitOnFailure(hr, "Failed to allocate memory for file template."); | 650 | PathExitOnFailure(hr, "Failed to allocate memory for file template."); |
623 | 651 | ||
624 | hr = StrAllocFormatted(&sczTempFile, L"%s%s", sczTempPath, scz); | 652 | hr = StrAllocFormatted(&sczTempFile, L"%ls%ls", sczTempPath, scz); |
625 | PathExitOnFailure(hr, "Failed to allocate temp file name."); | 653 | PathExitOnFailure(hr, "Failed to allocate temp file name."); |
626 | 654 | ||
627 | hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_NEW, dwFileAttributes, NULL); | 655 | hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_NEW, dwFileAttributes, NULL); |
@@ -642,13 +670,8 @@ DAPI_(HRESULT) PathCreateTempFile( | |||
642 | // the system to provide us a temp file using its built-in mechanism. | 670 | // the system to provide us a temp file using its built-in mechanism. |
643 | if (INVALID_HANDLE_VALUE == hTempFile) | 671 | if (INVALID_HANDLE_VALUE == hTempFile) |
644 | { | 672 | { |
645 | hr = StrAlloc(&sczTempFile, MAX_PATH); | 673 | hr = PathGetTempFileName(sczTempPath, wzPrefix, 0, &sczTempFile); |
646 | PathExitOnFailure(hr, "Failed to allocate memory for the temp path"); | 674 | PathExitOnFailure(hr, "Failed to create new temp file name."); |
647 | |||
648 | if (!::GetTempFileNameW(sczTempPath, L"TMP", 0, sczTempFile)) | ||
649 | { | ||
650 | PathExitWithLastError(hr, "Failed to create new temp file name."); | ||
651 | } | ||
652 | 675 | ||
653 | hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, dwFileAttributes, NULL); | 676 | hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, dwFileAttributes, NULL); |
654 | if (INVALID_HANDLE_VALUE == hTempFile) | 677 | if (INVALID_HANDLE_VALUE == hTempFile) |
@@ -684,6 +707,82 @@ LExit: | |||
684 | } | 707 | } |
685 | 708 | ||
686 | 709 | ||
710 | DAPI_(HRESULT) PathGetTempFileName( | ||
711 | __in LPCWSTR wzPathName, | ||
712 | __in LPCWSTR wzPrefixString, | ||
713 | __in UINT uUnique, | ||
714 | __out LPWSTR* psczTempFileName | ||
715 | ) | ||
716 | { | ||
717 | HRESULT hr = S_OK; | ||
718 | size_t cchFullPath = 0; | ||
719 | WORD wValue = (WORD)(0xffff & uUnique); | ||
720 | LPWSTR scz = NULL; | ||
721 | LPWSTR sczTempFile = NULL; | ||
722 | HANDLE hTempFile = INVALID_HANDLE_VALUE; | ||
723 | |||
724 | hr = ::StringCchLengthW(wzPathName, STRSAFE_MAX_CCH, &cchFullPath); | ||
725 | PathExitOnFailure(hr, "Failed to get length of path to prefix."); | ||
726 | |||
727 | if (MAX_PATH - 14 >= cchFullPath) | ||
728 | { | ||
729 | hr = StrAlloc(psczTempFileName, MAX_PATH); | ||
730 | PathExitOnFailure(hr, "Failed to allocate buffer for GetTempFileNameW."); | ||
731 | |||
732 | if (!::GetTempFileNameW(wzPathName, wzPrefixString, uUnique, *psczTempFileName)) | ||
733 | { | ||
734 | PathExitWithLastError(hr, "Failed to create new temp file name."); | ||
735 | } | ||
736 | |||
737 | ExitFunction(); | ||
738 | } | ||
739 | |||
740 | // TODO: when uUnique is 0, consider not always starting at 0 to avoid collisions if this is called repeatedly. | ||
741 | // Purposely let it wrap around. | ||
742 | for (WORD w = 0; w < WORD_MAX && INVALID_HANDLE_VALUE == hTempFile; ++wValue) | ||
743 | { | ||
744 | hr = StrAllocFormatted(&scz, L"%ls%x.TMP", wzPrefixString, w); | ||
745 | PathExitOnFailure(hr, "Failed to allocate memory for file template."); | ||
746 | |||
747 | hr = PathConcat(wzPathName, scz, &sczTempFile); | ||
748 | PathExitOnFailure(hr, "Failed to allocate temp file name."); | ||
749 | |||
750 | hTempFile = ::CreateFileW(sczTempFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_NEW, 0, NULL); | ||
751 | if (INVALID_HANDLE_VALUE == hTempFile) | ||
752 | { | ||
753 | // if the file already exists, try next one. | ||
754 | hr = HRESULT_FROM_WIN32(::GetLastError()); | ||
755 | if (HRESULT_FROM_WIN32(ERROR_FILE_EXISTS) == hr) | ||
756 | { | ||
757 | hr = S_OK; | ||
758 | } | ||
759 | PathExitOnFailure(hr, "Failed to create file: %ls", sczTempFile); | ||
760 | } | ||
761 | |||
762 | ++w; | ||
763 | } | ||
764 | |||
765 | if (INVALID_HANDLE_VALUE == hTempFile) | ||
766 | { | ||
767 | PathExitWithRootFailure(hr, HRESULT_FROM_WIN32(ERROR_FILE_EXISTS), "Failed to create temp file."); | ||
768 | } | ||
769 | |||
770 | hr = StrAllocString(psczTempFileName, sczTempFile, 0); | ||
771 | PathExitOnFailure(hr, "Failed to copy temp file string."); | ||
772 | |||
773 | LExit: | ||
774 | if (INVALID_HANDLE_VALUE != hTempFile) | ||
775 | { | ||
776 | ::CloseHandle(hTempFile); | ||
777 | } | ||
778 | |||
779 | ReleaseStr(scz); | ||
780 | ReleaseStr(sczTempFile); | ||
781 | |||
782 | return hr; | ||
783 | } | ||
784 | |||
785 | |||
687 | DAPI_(HRESULT) PathCreateTimeBasedTempFile( | 786 | DAPI_(HRESULT) PathCreateTimeBasedTempFile( |
688 | __in_z_opt LPCWSTR wzDirectory, | 787 | __in_z_opt LPCWSTR wzDirectory, |
689 | __in_z LPCWSTR wzPrefix, | 788 | __in_z LPCWSTR wzPrefix, |
@@ -695,7 +794,7 @@ DAPI_(HRESULT) PathCreateTimeBasedTempFile( | |||
695 | { | 794 | { |
696 | HRESULT hr = S_OK; | 795 | HRESULT hr = S_OK; |
697 | BOOL fRetry = FALSE; | 796 | BOOL fRetry = FALSE; |
698 | WCHAR wzTempPath[MAX_PATH] = { }; | 797 | LPWSTR sczTempParentPath = NULL; |
699 | LPWSTR sczPrefix = NULL; | 798 | LPWSTR sczPrefix = NULL; |
700 | LPWSTR sczPrefixFolder = NULL; | 799 | LPWSTR sczPrefixFolder = NULL; |
701 | SYSTEMTIME time = { }; | 800 | SYSTEMTIME time = { }; |
@@ -711,12 +810,10 @@ DAPI_(HRESULT) PathCreateTimeBasedTempFile( | |||
711 | } | 810 | } |
712 | else | 811 | else |
713 | { | 812 | { |
714 | if (!::GetTempPathW(countof(wzTempPath), wzTempPath)) | 813 | hr = PathGetTempPath(&sczTempParentPath, NULL); |
715 | { | 814 | PathExitOnFailure(hr, "Failed to get temp folder."); |
716 | PathExitWithLastError(hr, "Failed to get temp folder."); | ||
717 | } | ||
718 | 815 | ||
719 | hr = PathConcat(wzTempPath, wzPrefix, &sczPrefix); | 816 | hr = PathConcat(sczTempParentPath, wzPrefix, &sczPrefix); |
720 | PathExitOnFailure(hr, "Failed to concatenate the temp folder and log prefix."); | 817 | PathExitOnFailure(hr, "Failed to concatenate the temp folder and log prefix."); |
721 | } | 818 | } |
722 | 819 | ||
@@ -778,6 +875,7 @@ DAPI_(HRESULT) PathCreateTimeBasedTempFile( | |||
778 | 875 | ||
779 | LExit: | 876 | LExit: |
780 | ReleaseFile(hTempFile); | 877 | ReleaseFile(hTempFile); |
878 | ReleaseStr(sczTempParentPath); | ||
781 | ReleaseStr(sczTempPath); | 879 | ReleaseStr(sczTempPath); |
782 | ReleaseStr(sczPrefixFolder); | 880 | ReleaseStr(sczPrefixFolder); |
783 | ReleaseStr(sczPrefix); | 881 | ReleaseStr(sczPrefix); |
@@ -799,7 +897,6 @@ DAPI_(HRESULT) PathCreateTempDirectory( | |||
799 | HRESULT hr = S_OK; | 897 | HRESULT hr = S_OK; |
800 | 898 | ||
801 | LPWSTR sczTempPath = NULL; | 899 | LPWSTR sczTempPath = NULL; |
802 | DWORD cchTempPath = MAX_PATH; | ||
803 | 900 | ||
804 | LPWSTR scz = NULL; | 901 | LPWSTR scz = NULL; |
805 | 902 | ||
@@ -813,13 +910,8 @@ DAPI_(HRESULT) PathCreateTempDirectory( | |||
813 | } | 910 | } |
814 | else | 911 | else |
815 | { | 912 | { |
816 | hr = StrAlloc(&sczTempPath, cchTempPath); | 913 | hr = PathGetTempPath(&sczTempPath, NULL); |
817 | PathExitOnFailure(hr, "Failed to allocate memory for the temp path."); | 914 | PathExitOnFailure(hr, "Failed to get temp path."); |
818 | |||
819 | if (!::GetTempPathW(cchTempPath, sczTempPath)) | ||
820 | { | ||
821 | PathExitWithLastError(hr, "Failed to get temp path."); | ||
822 | } | ||
823 | } | 915 | } |
824 | 916 | ||
825 | for (DWORD i = 1; i <= dwUniqueCount; ++i) | 917 | for (DWORD i = 1; i <= dwUniqueCount; ++i) |
@@ -869,46 +961,230 @@ LExit: | |||
869 | 961 | ||
870 | 962 | ||
871 | DAPI_(HRESULT) PathGetTempPath( | 963 | DAPI_(HRESULT) PathGetTempPath( |
872 | __out_z LPWSTR* psczTempPath | 964 | __out_z LPWSTR* psczTempPath, |
965 | __out_opt SIZE_T* pcch | ||
966 | ) | ||
967 | { | ||
968 | |||
969 | HRESULT hr = S_OK; | ||
970 | SIZE_T cchMax = 0; | ||
971 | DWORD cchBuffer = 0; | ||
972 | DWORD cch = 0; | ||
973 | DWORD dwAttempts = 0; | ||
974 | HMODULE hModule = NULL; | ||
975 | PFN_GETTEMPPATH2W pfnGetTempPath = NULL; | ||
976 | const DWORD dwMaxAttempts = 10; | ||
977 | |||
978 | if (*psczTempPath) | ||
979 | { | ||
980 | hr = StrMaxLength(*psczTempPath, &cchMax); | ||
981 | PathExitOnFailure(hr, "Failed to get max length of input buffer."); | ||
982 | |||
983 | cchBuffer = (DWORD)min(DWORD_MAX, cchMax); | ||
984 | } | ||
985 | else | ||
986 | { | ||
987 | cchBuffer = MAX_PATH + 1; | ||
988 | |||
989 | hr = StrAlloc(psczTempPath, cchBuffer); | ||
990 | PathExitOnFailure(hr, "Failed to allocate space for temp path."); | ||
991 | } | ||
992 | |||
993 | hr = LoadSystemLibrary(L"kernel32.dll", &hModule); | ||
994 | PathExitOnFailure(hr, "Failed to load kernel32.dll"); | ||
995 | |||
996 | pfnGetTempPath = reinterpret_cast<PFN_GETTEMPPATH2W>(::GetProcAddress(hModule, "GetTempPath2W")); | ||
997 | if (!pfnGetTempPath) | ||
998 | { | ||
999 | pfnGetTempPath = ::GetTempPathW; | ||
1000 | } | ||
1001 | |||
1002 | for (; dwAttempts < dwMaxAttempts; ++dwAttempts) | ||
1003 | { | ||
1004 | cch = pfnGetTempPath(cchBuffer, *psczTempPath); | ||
1005 | PathExitOnNullWithLastError(cch, hr, "Failed to get temp path."); | ||
1006 | |||
1007 | cch += 1; // add one for null terminator. | ||
1008 | |||
1009 | if (cch <= cchBuffer) | ||
1010 | { | ||
1011 | break; | ||
1012 | } | ||
1013 | |||
1014 | hr = StrAlloc(psczTempPath, cch); | ||
1015 | PathExitOnFailure(hr, "Failed to reallocate space for temp path."); | ||
1016 | |||
1017 | cchBuffer = cch; | ||
1018 | } | ||
1019 | |||
1020 | if (dwMaxAttempts == dwAttempts) | ||
1021 | { | ||
1022 | PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "GetTempPathW results never converged."); | ||
1023 | } | ||
1024 | |||
1025 | if (pcch) | ||
1026 | { | ||
1027 | *pcch = cch - 1; // remove one for null terminator. | ||
1028 | } | ||
1029 | |||
1030 | LExit: | ||
1031 | return hr; | ||
1032 | } | ||
1033 | |||
1034 | |||
1035 | DAPI_(HRESULT) PathGetSystemDirectory( | ||
1036 | __out_z LPWSTR* psczSystemPath | ||
1037 | ) | ||
1038 | { | ||
1039 | HRESULT hr = S_OK; | ||
1040 | SIZE_T cchMax = 0; | ||
1041 | DWORD cchBuffer = 0; | ||
1042 | DWORD cch = 0; | ||
1043 | |||
1044 | if (*psczSystemPath) | ||
1045 | { | ||
1046 | hr = StrMaxLength(*psczSystemPath, &cchMax); | ||
1047 | PathExitOnFailure(hr, "Failed to get max length of input buffer."); | ||
1048 | |||
1049 | cchBuffer = (DWORD)min(DWORD_MAX, cchMax); | ||
1050 | } | ||
1051 | else | ||
1052 | { | ||
1053 | cchBuffer = MAX_PATH + 1; | ||
1054 | |||
1055 | hr = StrAlloc(psczSystemPath, cchBuffer); | ||
1056 | PathExitOnFailure(hr, "Failed to allocate space for system directory."); | ||
1057 | } | ||
1058 | |||
1059 | cch = ::GetSystemDirectoryW(*psczSystemPath, cchBuffer); | ||
1060 | PathExitOnNullWithLastError(cch, hr, "Failed to get system directory path with default size."); | ||
1061 | |||
1062 | if (cch > cchBuffer) | ||
1063 | { | ||
1064 | hr = StrAlloc(psczSystemPath, cch); | ||
1065 | PathExitOnFailure(hr, "Failed to realloc system directory path."); | ||
1066 | |||
1067 | cchBuffer = cch; | ||
1068 | |||
1069 | cch = ::GetSystemDirectoryW(*psczSystemPath, cchBuffer); | ||
1070 | PathExitOnNullWithLastError(cch, hr, "Failed to get system directory path with returned size."); | ||
1071 | |||
1072 | if (cch > cchBuffer) | ||
1073 | { | ||
1074 | PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Failed to get system directory path with returned size."); | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | hr = PathBackslashTerminate(psczSystemPath); | ||
1079 | PathExitOnFailure(hr, "Failed to terminate system directory path with backslash."); | ||
1080 | |||
1081 | LExit: | ||
1082 | return hr; | ||
1083 | } | ||
1084 | |||
1085 | |||
1086 | DAPI_(HRESULT) PathGetSystemWow64Directory( | ||
1087 | __out_z LPWSTR* psczSystemPath | ||
873 | ) | 1088 | ) |
874 | { | 1089 | { |
875 | HRESULT hr = S_OK; | 1090 | HRESULT hr = S_OK; |
876 | WCHAR wzTempPath[MAX_PATH + 1] = { }; | 1091 | SIZE_T cchMax = 0; |
1092 | DWORD cchBuffer = 0; | ||
877 | DWORD cch = 0; | 1093 | DWORD cch = 0; |
878 | 1094 | ||
879 | cch = ::GetTempPathW(countof(wzTempPath), wzTempPath); | 1095 | if (*psczSystemPath) |
880 | if (!cch) | ||
881 | { | 1096 | { |
882 | PathExitWithLastError(hr, "Failed to GetTempPath."); | 1097 | hr = StrMaxLength(*psczSystemPath, &cchMax); |
1098 | PathExitOnFailure(hr, "Failed to get max length of input buffer."); | ||
1099 | |||
1100 | cchBuffer = (DWORD)min(DWORD_MAX, cchMax); | ||
883 | } | 1101 | } |
884 | else if (cch >= countof(wzTempPath)) | 1102 | else |
885 | { | 1103 | { |
886 | PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "TEMP directory path too long."); | 1104 | cchBuffer = MAX_PATH + 1; |
1105 | |||
1106 | hr = StrAlloc(psczSystemPath, cchBuffer); | ||
1107 | PathExitOnFailure(hr, "Failed to allocate space for system wow64 directory."); | ||
887 | } | 1108 | } |
888 | 1109 | ||
889 | hr = StrAllocString(psczTempPath, wzTempPath, cch); | 1110 | cch = ::GetSystemWow64DirectoryW(*psczSystemPath, cchBuffer); |
890 | PathExitOnFailure(hr, "Failed to copy TEMP directory path."); | 1111 | PathExitOnNullWithLastError(cch, hr, "Failed to get system wow64 directory path with default size."); |
1112 | |||
1113 | cch += 1; // add one for the null terminator. | ||
1114 | |||
1115 | if (cch > cchBuffer) | ||
1116 | { | ||
1117 | hr = StrAlloc(psczSystemPath, cch); | ||
1118 | PathExitOnFailure(hr, "Failed to realloc system wow64 directory path."); | ||
1119 | |||
1120 | cchBuffer = cch; | ||
1121 | |||
1122 | cch = ::GetSystemWow64DirectoryW(*psczSystemPath, cchBuffer); | ||
1123 | PathExitOnNullWithLastError(cch, hr, "Failed to get system wow64 directory path with returned size."); | ||
1124 | |||
1125 | cch += 1; // add one for the null terminator. | ||
1126 | |||
1127 | if (cch > cchBuffer) | ||
1128 | { | ||
1129 | PathExitWithRootFailure(hr, E_INSUFFICIENT_BUFFER, "Failed to get system wow64 directory path with returned size."); | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | hr = PathBackslashTerminate(psczSystemPath); | ||
1134 | PathExitOnFailure(hr, "Failed to terminate system wow64 directory path with backslash."); | ||
891 | 1135 | ||
892 | LExit: | 1136 | LExit: |
893 | return hr; | 1137 | return hr; |
894 | } | 1138 | } |
895 | 1139 | ||
896 | 1140 | ||
897 | DAPI_(HRESULT) PathGetKnownFolder( | 1141 | DAPI_(HRESULT) PathGetVolumePathName( |
898 | __in int csidl, | 1142 | __in_z LPCWSTR wzFileName, |
899 | __out LPWSTR* psczKnownFolder | 1143 | __out_z LPWSTR* psczVolumePathName |
900 | ) | 1144 | ) |
901 | { | 1145 | { |
902 | HRESULT hr = S_OK; | 1146 | HRESULT hr = S_OK; |
1147 | DWORD cchBuffer = 0; | ||
1148 | SIZE_T cchMax = 0; | ||
1149 | const DWORD dwMaxAttempts = 20; | ||
903 | 1150 | ||
904 | hr = StrAlloc(psczKnownFolder, MAX_PATH); | 1151 | if (*psczVolumePathName) |
905 | PathExitOnFailure(hr, "Failed to allocate memory for known folder."); | 1152 | { |
1153 | hr = StrMaxLength(*psczVolumePathName, &cchMax); | ||
1154 | PathExitOnFailure(hr, "Failed to get max length of input buffer."); | ||
906 | 1155 | ||
907 | hr = ::SHGetFolderPathW(NULL, csidl, NULL, SHGFP_TYPE_CURRENT, *psczKnownFolder); | 1156 | cchBuffer = (DWORD)min(DWORD_MAX, cchMax); |
908 | PathExitOnFailure(hr, "Failed to get known folder path."); | 1157 | } |
1158 | else | ||
1159 | { | ||
1160 | cchBuffer = MAX_PATH + 1; | ||
1161 | |||
1162 | hr = StrAlloc(psczVolumePathName, cchBuffer); | ||
1163 | PathExitOnFailure(hr, "Failed to allocate space for volume path name."); | ||
1164 | } | ||
1165 | |||
1166 | for (DWORD i = 0; i < dwMaxAttempts; ++i) | ||
1167 | { | ||
1168 | if (::GetVolumePathNameW(wzFileName, *psczVolumePathName, cchBuffer)) | ||
1169 | { | ||
1170 | break; | ||
1171 | } | ||
1172 | |||
1173 | hr = HRESULT_FROM_WIN32(::GetLastError()); | ||
1174 | if (HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) != hr && E_INSUFFICIENT_BUFFER != hr || | ||
1175 | (dwMaxAttempts - 1) == i) | ||
1176 | { | ||
1177 | PathExitWithRootFailure(hr, hr, "Failed to get volume path name of: %ls", wzFileName); | ||
1178 | } | ||
1179 | |||
1180 | cchBuffer *= 2; | ||
1181 | |||
1182 | hr = StrAlloc(psczVolumePathName, cchBuffer); | ||
1183 | PathExitOnFailure(hr, "Failed to re-allocate more space for volume path name."); | ||
1184 | } | ||
909 | 1185 | ||
910 | hr = PathBackslashTerminate(psczKnownFolder); | 1186 | hr = PathBackslashTerminate(psczVolumePathName); |
911 | PathExitOnFailure(hr, "Failed to ensure known folder path is backslash terminated."); | 1187 | PathExitOnFailure(hr, "Failed to terminate volume path name with backslash."); |
912 | 1188 | ||
913 | LExit: | 1189 | LExit: |
914 | return hr; | 1190 | return hr; |