summaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/path3utl.cpp
blob: 999a99ac25457836a95711486b2336f80e156934 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.

#include "precomp.h"


// Exit macros
#define PathExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__)
#define PathExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__)
#define PathExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__)
#define PathExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__)
#define PathExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__)
#define PathExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_PATHUTIL, x, e, s, __VA_ARGS__)
#define PathExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_PATHUTIL, x, s, __VA_ARGS__)
#define PathExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_PATHUTIL, p, x, e, s, __VA_ARGS__)
#define PathExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_PATHUTIL, p, x, s, __VA_ARGS__)
#define PathExitOnNullDebugTrace(p, x, e, s, ...)  ExitOnNullDebugTraceSource(DUTIL_SOURCE_PATHUTIL, p, x, e, s, __VA_ARGS__)
#define PathExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_PATHUTIL, p, x, s, __VA_ARGS__)
#define PathExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_PATHUTIL, e, x, s, __VA_ARGS__)
#define PathExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_PATHUTIL, g, x, s, __VA_ARGS__)
#define PathExitOnPathFailure(x, b, s, ...) ExitOnPathFailureSource(DUTIL_SOURCE_PATHUTIL, x, b, s, __VA_ARGS__)

static HRESULT GetTempPathFromSystemEnvironmentVariable(
    __in HKEY hKey,
    __in_z LPCWSTR wzName,
    __out_z LPWSTR* psczPath
    );

DAPI_(HRESULT) PathGetSystemTempPaths(
    __inout_z LPWSTR** prgsczSystemTempPaths,
    __inout DWORD* pcSystemTempPaths
    )
{
    HRESULT hr = S_OK;
    HMODULE hModule = NULL;
    BOOL fSystem = FALSE;
    BOOL fExists = FALSE;
    HKEY hKey = NULL;
    LPWSTR sczTemp = NULL;

    // Follow documented precedence rules for SystemTemp/%TMP%/%TEMP% from ::GetTempPath2.
    hr = LoadSystemLibrary(L"kernel32.dll", &hModule);
    PathExitOnFailure(hr, "Failed to load kernel32.dll");

    // The SystemTemp folder was added at the same time as ::GetTempPath2.
    if (::GetProcAddress(hModule, "GetTempPath2W"))
    {
        hr = ProcSystem(::GetCurrentProcess(), &fSystem);
        PathExitOnFailure(hr, "Failed to check if running as system.");

        if (fSystem)
        {
            hr = PathSystemWindowsSubdirectory(L"SystemTemp", &sczTemp);
            PathExitOnFailure(hr, "Failed to get system Windows subdirectory path SystemTemp.");

            hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 4);
            PathExitOnFailure(hr, "Failed to ensure array size for Windows\\SystemTemp value.");

            (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
            sczTemp = NULL;
            *pcSystemTempPaths += 1;
        }
    }

    // There is no documented API to get system environment variables, so read them from the registry.
    hr = RegOpen(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Session Manager\\Environment", KEY_READ, &hKey);
    PathExitOnPathFailure(hr, fExists, "Failed to open system environment registry key.");

    if (fExists)
    {
        hr = GetTempPathFromSystemEnvironmentVariable(hKey, L"TMP", &sczTemp);
        PathExitOnFailure(hr, "Failed to get temp path from system TMP.");

        if (S_FALSE != hr)
        {
            hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 3);
            PathExitOnFailure(hr, "Failed to ensure array size for system TMP value.");

            (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
            sczTemp = NULL;
            *pcSystemTempPaths += 1;
        }

        hr = GetTempPathFromSystemEnvironmentVariable(hKey, L"TEMP", &sczTemp);
        PathExitOnFailure(hr, "Failed to get temp path from system TEMP.");

        if (S_FALSE != hr)
        {
            hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 2);
            PathExitOnFailure(hr, "Failed to ensure array size for system TEMP value.");

            (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
            sczTemp = NULL;
            *pcSystemTempPaths += 1;
        }
    }

    hr = PathSystemWindowsSubdirectory(L"TEMP", &sczTemp);
    PathExitOnFailure(hr, "Failed to get system Windows subdirectory path TEMP.");

    hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczSystemTempPaths), *pcSystemTempPaths, 1, sizeof(LPWSTR), 1);
    PathExitOnFailure(hr, "Failed to ensure array size for Windows\\TEMP value.");

    (*prgsczSystemTempPaths)[*pcSystemTempPaths] = sczTemp;
    sczTemp = NULL;
    *pcSystemTempPaths += 1;

LExit:
    ReleaseRegKey(hKey);
    ReleaseStr(sczTemp);

    return hr;
}

static HRESULT GetTempPathFromSystemEnvironmentVariable(
    __in HKEY hKey,
    __in_z LPCWSTR wzName,
    __out_z LPWSTR* psczPath
    )
{
    HRESULT hr = S_OK;
    LPWSTR sczValue = NULL;
    BOOL fNeedsExpansion = FALSE;
    BOOL fExists = FALSE;

    // Read the value unexpanded so that it can be expanded with system environment variables.
    hr = RegReadUnexpandedString(hKey, wzName, &fNeedsExpansion, &sczValue);
    PathExitOnPathFailure(hr, fExists, "Failed to get system '%ls' value.", wzName);

    if (!fExists)
    {
        ExitFunction1(hr = S_FALSE);
    }

    if (fNeedsExpansion)
    {
        hr = EnvExpandEnvironmentStringsForUser(NULL, sczValue, psczPath, NULL);
        PathExitOnFailure(hr, "Failed to expand environment variables for system in string: %ls", sczValue);
    }
    else
    {
        hr = StrAllocString(psczPath, sczValue, 0);
        PathExitOnFailure(hr, "Failed to copy environment variable: %ls", wzName);
    }

    hr = PathBackslashTerminate(psczPath);
    PathExitOnFailure(hr, "Failed to backslash terminate system '%ls' value.", wzName);

LExit:
    ReleaseStr(sczValue);

    return hr;
}