aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/metautil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/metautil.cpp')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/metautil.cpp378
1 files changed, 378 insertions, 0 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/metautil.cpp b/src/libs/dutil/WixToolset.DUtil/metautil.cpp
new file mode 100644
index 00000000..f313fc1c
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/metautil.cpp
@@ -0,0 +1,378 @@
1// 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.
2
3#include "precomp.h"
4
5// okay, this may look a little weird, but metautil.h cannot be in the
6// pre-compiled header because we need to #define these things so the
7// correct GUID's get pulled into this object file
8#include <initguid.h>
9#include "metautil.h"
10
11
12// Exit macros
13#define MetaExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_METAUTIL, x, s, __VA_ARGS__)
14#define MetaExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_METAUTIL, x, s, __VA_ARGS__)
15#define MetaExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_METAUTIL, x, s, __VA_ARGS__)
16#define MetaExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_METAUTIL, x, s, __VA_ARGS__)
17#define MetaExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_METAUTIL, x, s, __VA_ARGS__)
18#define MetaExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_METAUTIL, x, s, __VA_ARGS__)
19#define MetaExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_METAUTIL, p, x, e, s, __VA_ARGS__)
20#define MetaExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_METAUTIL, p, x, s, __VA_ARGS__)
21#define MetaExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_METAUTIL, p, x, e, s, __VA_ARGS__)
22#define MetaExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_METAUTIL, p, x, s, __VA_ARGS__)
23#define MetaExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_METAUTIL, e, x, s, __VA_ARGS__)
24#define MetaExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_METAUTIL, g, x, s, __VA_ARGS__)
25
26
27// prototypes
28static void Sort(
29 __in_ecount(cArray) DWORD dwArray[],
30 __in int cArray
31 );
32
33
34/********************************************************************
35 MetaFindWebBase - finds a metabase base string that matches IP, Port and Header
36
37********************************************************************/
38extern "C" HRESULT DAPI MetaFindWebBase(
39 __in IMSAdminBaseW* piMetabase,
40 __in_z LPCWSTR wzIP,
41 __in int iPort,
42 __in_z LPCWSTR wzHeader,
43 __in BOOL fSecure,
44 __out_ecount(cchWebBase) LPWSTR wzWebBase,
45 __in DWORD cchWebBase
46 )
47{
48 Assert(piMetabase && cchWebBase);
49
50 HRESULT hr = S_OK;
51
52 BOOL fFound = FALSE;
53
54 WCHAR wzKey[METADATA_MAX_NAME_LEN];
55 WCHAR wzSubkey[METADATA_MAX_NAME_LEN];
56 DWORD dwIndex = 0;
57
58 METADATA_RECORD mr;
59 METADATA_RECORD mrAddress;
60
61 LPWSTR pwzExists = NULL;
62 LPWSTR pwzIPExists = NULL;
63 LPWSTR pwzPortExists = NULL;
64 int iPortExists = 0;
65 LPCWSTR pwzHeaderExists = NULL;
66
67 memset(&mr, 0, sizeof(mr));
68 mr.dwMDIdentifier = MD_KEY_TYPE;
69 mr.dwMDAttributes = METADATA_INHERIT;
70 mr.dwMDUserType = IIS_MD_UT_SERVER;
71 mr.dwMDDataType = ALL_METADATA;
72
73 memset(&mrAddress, 0, sizeof(mrAddress));
74 mrAddress.dwMDIdentifier = (fSecure) ? MD_SECURE_BINDINGS : MD_SERVER_BINDINGS;
75 mrAddress.dwMDAttributes = METADATA_INHERIT;
76 mrAddress.dwMDUserType = IIS_MD_UT_SERVER;
77 mrAddress.dwMDDataType = ALL_METADATA;
78
79 // loop through the "web keys" looking for the "IIsWebServer" key that matches wzWeb
80 for (dwIndex = 0; SUCCEEDED(hr); ++dwIndex)
81 {
82 hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC", wzSubkey, dwIndex);
83 if (FAILED(hr))
84 break;
85
86 ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%s", wzSubkey);
87 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr);
88 if (MD_ERROR_DATA_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
89 {
90 hr = S_FALSE; // didn't find anything, try next one
91 continue;
92 }
93 MetaExitOnFailure(hr, "failed to get key from metabase while searching for web servers");
94
95 // if we have an IIsWebServer store the key
96 if (0 == lstrcmpW(L"IIsWebServer", (LPCWSTR)mr.pbMDData))
97 {
98 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mrAddress);
99 if (MD_ERROR_DATA_NOT_FOUND == hr)
100 hr = S_FALSE;
101 MetaExitOnFailure(hr, "failed to get address from metabase while searching for web servers");
102
103 // break down the first address into parts
104 pwzIPExists = reinterpret_cast<LPWSTR>(mrAddress.pbMDData);
105 pwzExists = wcsstr(pwzIPExists, L":");
106 if (NULL == pwzExists)
107 continue;
108
109 *pwzExists = L'\0';
110
111 pwzPortExists = pwzExists + 1;
112 pwzExists = wcsstr(pwzPortExists, L":");
113 if (NULL == pwzExists)
114 continue;
115
116 *pwzExists = L'\0';
117 iPortExists = wcstol(pwzPortExists, NULL, 10);
118
119 pwzHeaderExists = pwzExists + 1;
120
121 // compare the passed in address with the address listed for this web
122 if (S_OK == hr &&
123 (0 == lstrcmpW(wzIP, pwzIPExists) || 0 == lstrcmpW(wzIP, L"*")) &&
124 iPort == iPortExists &&
125 0 == lstrcmpW(wzHeader, pwzHeaderExists))
126 {
127 // if the passed in buffer wasn't big enough
128 hr = ::StringCchCopyW(wzWebBase, cchWebBase, wzKey);
129 MetaExitOnFailure(hr, "failed to copy in web base: %ls", wzKey);
130
131 fFound = TRUE;
132 break;
133 }
134 }
135 }
136
137 if (E_NOMOREITEMS == hr)
138 {
139 Assert(!fFound);
140 hr = S_FALSE;
141 }
142
143LExit:
144 MetaFreeValue(&mrAddress);
145 MetaFreeValue(&mr);
146
147 if (!fFound && SUCCEEDED(hr))
148 hr = S_FALSE;
149
150 return hr;
151}
152
153
154/********************************************************************
155 MetaFindFreeWebBase - finds the next metabase base string
156
157********************************************************************/
158extern "C" HRESULT DAPI MetaFindFreeWebBase(
159 __in IMSAdminBaseW* piMetabase,
160 __out_ecount(cchWebBase) LPWSTR wzWebBase,
161 __in DWORD cchWebBase
162 )
163{
164 Assert(piMetabase);
165
166 HRESULT hr = S_OK;
167
168 WCHAR wzKey[METADATA_MAX_NAME_LEN];
169 WCHAR wzSubkey[METADATA_MAX_NAME_LEN];
170 DWORD dwSubKeys[100];
171 int cSubKeys = 0;
172 DWORD dwIndex = 0;
173
174 int i;
175 DWORD dwKey;
176
177 METADATA_RECORD mr;
178
179 memset(&mr, 0, sizeof(mr));
180 mr.dwMDIdentifier = MD_KEY_TYPE;
181 mr.dwMDAttributes = 0;
182 mr.dwMDUserType = IIS_MD_UT_SERVER;
183 mr.dwMDDataType = STRING_METADATA;
184
185 // loop through the "web keys" looking for the "IIsWebServer" key that matches wzWeb
186 for (dwIndex = 0; SUCCEEDED(hr); ++dwIndex)
187 {
188 hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC", wzSubkey, dwIndex);
189 if (FAILED(hr))
190 break;
191
192 ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%s", wzSubkey);
193
194 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr);
195 if (MD_ERROR_DATA_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
196 {
197 hr = S_FALSE; // didn't find anything, try next one
198 continue;
199 }
200 MetaExitOnFailure(hr, "failed to get key from metabase while searching for free web root");
201
202 // if we have a IIsWebServer get the address information
203 if (0 == lstrcmpW(L"IIsWebServer", reinterpret_cast<LPCWSTR>(mr.pbMDData)))
204 {
205 if (cSubKeys >= countof(dwSubKeys))
206 {
207 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
208 MetaExitOnFailure(hr, "Insufficient buffer to track all sub-WebSites");
209 }
210
211 dwSubKeys[cSubKeys] = wcstol(wzSubkey, NULL, 10);
212 ++cSubKeys;
213 Sort(dwSubKeys, cSubKeys);
214 }
215 }
216
217 if (E_NOMOREITEMS == hr)
218 hr = S_OK;
219 MetaExitOnFailure(hr, "failed to find free web root");
220
221 // find the lowest free web root
222 dwKey = 1;
223 for (i = 0; i < cSubKeys; ++i)
224 {
225 if (dwKey < dwSubKeys[i])
226 break;
227
228 dwKey = dwSubKeys[i] + 1;
229 }
230
231 hr = ::StringCchPrintfW(wzWebBase, cchWebBase, L"/LM/W3SVC/%u", dwKey);
232LExit:
233 MetaFreeValue(&mr);
234 return hr;
235}
236
237
238/********************************************************************
239 MetaOpenKey - open key
240
241********************************************************************/
242extern "C" HRESULT DAPI MetaOpenKey(
243 __in IMSAdminBaseW* piMetabase,
244 __in METADATA_HANDLE mhKey,
245 __in_z LPCWSTR wzKey,
246 __in DWORD dwAccess,
247 __in DWORD cRetries,
248 __out METADATA_HANDLE* pmh
249 )
250{
251 Assert(piMetabase && pmh);
252
253 HRESULT hr = S_OK;
254
255 // loop while the key is busy
256 do
257 {
258 hr = piMetabase->OpenKey(mhKey, wzKey, dwAccess, 10, pmh);
259 if (HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr)
260 ::SleepEx(1000, TRUE);
261 } while (HRESULT_FROM_WIN32(ERROR_PATH_BUSY) == hr && 0 < cRetries--);
262
263 return hr;
264}
265
266
267/********************************************************************
268 MetaGetValue - finds the next metabase base string
269
270 NOTE: piMetabase is optional
271********************************************************************/
272extern "C" HRESULT DAPI MetaGetValue(
273 __in IMSAdminBaseW* piMetabase,
274 __in METADATA_HANDLE mhKey,
275 __in_z LPCWSTR wzKey,
276 __inout METADATA_RECORD* pmr
277 )
278{
279 Assert(pmr);
280
281 HRESULT hr = S_OK;
282 BOOL fInitialized = FALSE;
283 DWORD cbRequired = 0;
284
285 if (!piMetabase)
286 {
287 hr = ::CoInitialize(NULL);
288 MetaExitOnFailure(hr, "failed to initialize COM");
289 fInitialized = TRUE;
290
291 hr = ::CoCreateInstance(CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, reinterpret_cast<LPVOID*>(&piMetabase));
292 MetaExitOnFailure(hr, "failed to get IID_IMSAdminBaseW object");
293 }
294
295 if (!pmr->pbMDData)
296 {
297 pmr->dwMDDataLen = 256;
298 pmr->pbMDData = static_cast<BYTE*>(MemAlloc(pmr->dwMDDataLen, TRUE));
299 MetaExitOnNull(pmr->pbMDData, hr, E_OUTOFMEMORY, "failed to allocate memory for metabase value");
300 }
301 else // set the size of the data to the actual size of the memory
302 {
303 SIZE_T cb = MemSize(pmr->pbMDData);
304 if (cb > DWORD_MAX)
305 {
306 MetaExitOnRootFailure(hr = E_INVALIDSTATE, "metabase data is too large: %Iu", cb);
307 }
308 pmr->dwMDDataLen = (DWORD)cb;
309 }
310
311 hr = piMetabase->GetData(mhKey, wzKey, pmr, &cbRequired);
312 if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr)
313 {
314 pmr->dwMDDataLen = cbRequired;
315 BYTE* pb = static_cast<BYTE*>(MemReAlloc(pmr->pbMDData, pmr->dwMDDataLen, TRUE));
316 MetaExitOnNull(pb, hr, E_OUTOFMEMORY, "failed to reallocate memory for metabase value");
317
318 pmr->pbMDData = pb;
319 hr = piMetabase->GetData(mhKey, wzKey, pmr, &cbRequired);
320 }
321 MetaExitOnFailure(hr, "failed to get metabase data");
322
323LExit:
324 if (fInitialized)
325 {
326 ReleaseObject(piMetabase);
327 ::CoUninitialize();
328 }
329
330 return hr;
331}
332
333
334/********************************************************************
335 MetaFreeValue - frees data in METADATA_RECORD remove MetaGetValue()
336
337 NOTE: METADATA_RECORD must have been returned from MetaGetValue() above
338********************************************************************/
339extern "C" void DAPI MetaFreeValue(
340 __in METADATA_RECORD* pmr
341 )
342{
343 Assert(pmr);
344
345 ReleaseNullMem(pmr->pbMDData);
346}
347
348
349//
350// private
351//
352
353/********************************************************************
354 Sort - quick and dirty insertion sort
355
356********************************************************************/
357static void Sort(
358 __in_ecount(cArray) DWORD dwArray[],
359 __in int cArray
360 )
361{
362 int i, j;
363 DWORD dwData;
364
365 for (i = 1; i < cArray; ++i)
366 {
367 dwData = dwArray[i];
368
369 j = i - 1;
370 while (0 <= j && dwArray[j] > dwData)
371 {
372 dwArray[j + 1] = dwArray[j];
373 j--;
374 }
375
376 dwArray[j + 1] = dwData;
377 }
378}