summaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/file2utl.cpp
blob: 3ab47f590371b80e8152bdcf98475ff9ea89e6a9 (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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// 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 FileExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_FILEUTIL, x, s, __VA_ARGS__)
#define FileExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_FILEUTIL, x, s, __VA_ARGS__)
#define FileExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_FILEUTIL, x, s, __VA_ARGS__)
#define FileExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_FILEUTIL, x, s, __VA_ARGS__)
#define FileExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_FILEUTIL, x, s, __VA_ARGS__)
#define FileExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_FILEUTIL, x, s, __VA_ARGS__)
#define FileExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_FILEUTIL, p, x, e, s, __VA_ARGS__)
#define FileExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_FILEUTIL, p, x, s, __VA_ARGS__)
#define FileExitOnNullDebugTrace(p, x, e, s, ...)  ExitOnNullDebugTraceSource(DUTIL_SOURCE_FILEUTIL, p, x, e, s, __VA_ARGS__)
#define FileExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_FILEUTIL, p, x, s, __VA_ARGS__)
#define FileExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_FILEUTIL, e, x, s, __VA_ARGS__)
#define FileExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_FILEUTIL, g, x, s, __VA_ARGS__)
#define FileExitOnPathFailure(x, b, s, ...) ExitOnPathFailureSource(DUTIL_SOURCE_FILEUTIL, x, b, s, __VA_ARGS__)

// constants

const LPCWSTR REGISTRY_PENDING_FILE_RENAME_KEY = L"SYSTEM\\CurrentControlSet\\Control\\Session Manager";
const LPCWSTR REGISTRY_PENDING_FILE_RENAME_VALUE = L"PendingFileRenameOperations";


/*******************************************************************
 FileExistsAfterRestart - checks that a file exists and will continue
                          to exist after restart.

********************************************************************/
extern "C" BOOL DAPI FileExistsAfterRestart(
    __in_z LPCWSTR wzPath,
    __out_opt DWORD *pdwAttributes
    )
{
    HRESULT hr = S_OK;
    BOOL fExists = FALSE;
    BOOL fRegExists = FALSE;
    HKEY hkPendingFileRename = NULL;
    LPWSTR* rgsczRenames = NULL;
    DWORD cRenames = 0;
    BOOL fPathEqual = FALSE;

    fExists = FileExistsEx(wzPath, pdwAttributes);
    if (fExists)
    {
        hr = RegOpen(HKEY_LOCAL_MACHINE, REGISTRY_PENDING_FILE_RENAME_KEY, KEY_QUERY_VALUE, &hkPendingFileRename);
        FileExitOnPathFailure(hr, fRegExists, "Failed to open pending file rename registry key.");

        if (!fRegExists)
        {
            ExitFunction();
        }

        hr = RegReadStringArray(hkPendingFileRename, REGISTRY_PENDING_FILE_RENAME_VALUE, &rgsczRenames, &cRenames);
        FileExitOnPathFailure(hr, fRegExists, "Failed to read pending file renames.");

        if (!fRegExists)
        {
            ExitFunction();
        }

        // The pending file renames array is pairs of source and target paths. We only care
        // about checking the source paths so skip the target paths (i += 2).
        for (DWORD i = 0; i < cRenames; i += 2)
        {
            LPWSTR wzRename = rgsczRenames[i];
            if (wzRename && *wzRename)
            {
                hr = PathCompareCanonicalized(wzPath, wzRename, &fPathEqual);
                FileExitOnFailure(hr, "Failed to compare path from pending file rename to check path.");

                if (fPathEqual)
                {
                    fExists = FALSE;
                    break;
                }
            }
        }
    }

LExit:
    ReleaseStrArray(rgsczRenames, cRenames);
    ReleaseRegKey(hkPendingFileRename);

    return fExists;
}


/*******************************************************************
 FileRemoveFromPendingRename - removes the file path from the pending
                               file rename list.

********************************************************************/
extern "C" HRESULT DAPI FileRemoveFromPendingRename(
    __in_z LPCWSTR wzPath
    )
{
    HRESULT hr = S_OK;
    HKEY hkPendingFileRename = NULL;
    BOOL fExists = FALSE;
    LPWSTR* rgsczRenames = NULL;
    DWORD cRenames = 0;
    BOOL fPathEqual = FALSE;
    BOOL fRemoved = FALSE;
    DWORD cNewRenames = 0;

    hr = RegOpen(HKEY_LOCAL_MACHINE, REGISTRY_PENDING_FILE_RENAME_KEY, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkPendingFileRename);
    FileExitOnPathFailure(hr, fExists, "Failed to open pending file rename registry key.");

    if (!fExists)
    {
        ExitFunction();
    }

    hr = RegReadStringArray(hkPendingFileRename, REGISTRY_PENDING_FILE_RENAME_VALUE, &rgsczRenames, &cRenames);
    FileExitOnPathFailure(hr, fExists, "Failed to read pending file renames.");

    if (!fExists)
    {
        ExitFunction();
    }

    // The pending file renames array is pairs of source and target paths. We only care
    // about checking the source paths so skip the target paths (i += 2).
    for (DWORD i = 0; i < cRenames; i += 2)
    {
        LPWSTR wzRename = rgsczRenames[i];
        if (wzRename && *wzRename)
        {
            hr = PathCompareCanonicalized(wzPath, wzRename, &fPathEqual);
            FileExitOnFailure(hr, "Failed to compare path from pending file rename to check path.");

            // If we find our path in the list, null out the source and target slot and
            // we'll compact the array next.
            if (fPathEqual)
            {
                ReleaseNullStr(rgsczRenames[i]);
                ReleaseNullStr(rgsczRenames[i + 1]);
                fRemoved = TRUE;
            }
        }
    }

    if (fRemoved)
    {
        // Compact the array by removing any nulls.
        for (DWORD i = 0; i < cRenames; ++i)
        {
            LPWSTR wzRename = rgsczRenames[i];
            if (wzRename)
            {
                rgsczRenames[cNewRenames] = wzRename;
                ++cNewRenames;
            }
        }

        cRenames = cNewRenames; // ignore the pointers on the end of the array since an early index points to them already.

        // Write the new array back to the pending file rename key.
        hr = RegWriteStringArray(hkPendingFileRename, REGISTRY_PENDING_FILE_RENAME_VALUE, rgsczRenames, cRenames);
        FileExitOnFailure(hr, "Failed to update pending file renames.");
    }

LExit:
    ReleaseStrArray(rgsczRenames, cRenames);
    ReleaseRegKey(hkPendingFileRename);

    return hr;
}