aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Iis/ca/scaweb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Iis/ca/scaweb.cpp')
-rw-r--r--src/ext/Iis/ca/scaweb.cpp1187
1 files changed, 1187 insertions, 0 deletions
diff --git a/src/ext/Iis/ca/scaweb.cpp b/src/ext/Iis/ca/scaweb.cpp
new file mode 100644
index 00000000..0452fb0b
--- /dev/null
+++ b/src/ext/Iis/ca/scaweb.cpp
@@ -0,0 +1,1187 @@
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//Adding this because delivery doesn't have the updated specstrings.h that windows build does
6#ifndef __in_xcount
7#define __in_xcount(size)
8#endif
9
10// sql queries
11
12enum eWebBaseQuery { wbqWeb = 1, wbqId, wbqIP, wbqPort, wbqHeader, wbqSecure, wbqDescription };
13
14
15// prototypes for private helper functions
16static SCA_WEB* NewWeb();
17static void FreeWeb(SCA_WEB *pswDelete);
18static SCA_WEB* AddWebToList(
19 __in SCA_WEB* pswList,
20 __in SCA_WEB* psw
21 );
22static HRESULT ScaWebFindBase(
23 __in IMSAdminBase* piMetabase,
24 __in SCA_WEB* pswList,
25 __in_z LPCWSTR wzWeb,
26 __in int iSiteId,
27 __in_z LPCWSTR wzIP,
28 __in int iPort,
29 __in_z LPCWSTR wzHeader,
30 __in BOOL fSecure,
31 __in_z LPCWSTR wzDescription,
32 __out_ecount(cchWebBase) LPWSTR wzWebBase,
33 __in DWORD cchWebBase
34 );
35static HRESULT ScaWebFindFreeBase(
36 __in IMSAdminBase* piMetabase,
37 __in_xcount(unknown) SCA_WEB* pswList,
38 __in int iSiteId,
39 __in_z LPCWSTR wzDescription,
40 __out_ecount(cchWebBase) LPWSTR wzWebBase,
41 __in DWORD cchWebBase
42 );
43static HRESULT ScaWebWrite(
44 __in IMSAdminBase* piMetabase,
45 __in SCA_WEB* psw,
46 __in SCA_APPPOOL * psapList
47 );
48static HRESULT ScaWebRemove(
49 __in IMSAdminBase* piMetabase,
50 __in const SCA_WEB* psw);
51static DWORD SiteIdFromDescription(
52 __in_z LPCWSTR wzDescription
53 );
54static void Sort(
55 __in_ecount(cArray) DWORD dwArray[],
56 __in int cArray
57 );
58
59
60HRESULT ScaWebsRead(
61 __in IMSAdminBase* piMetabase,
62 __in SCA_MIMEMAP** ppsmmList,
63 __in SCA_WEB** ppswList,
64 __in SCA_HTTP_HEADER** ppshhList,
65 __in SCA_WEB_ERROR** ppsweList,
66 __in WCA_WRAPQUERY_HANDLE hUserQuery,
67 __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery,
68 __in WCA_WRAPQUERY_HANDLE hSslCertQuery,
69 __in WCA_WRAPQUERY_HANDLE hWebLogQuery,
70 __in WCA_WRAPQUERY_HANDLE hWebAppQuery,
71 __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery,
72 __inout LPWSTR *ppwzCustomActionData
73 )
74{
75 Assert(piMetabase && ppswList);
76
77 HRESULT hr = S_OK;
78
79 MSIHANDLE hRec;
80 MSIHANDLE hRecAddresses;
81
82 SCA_WEB* psw = NULL;
83 LPWSTR pwzData = NULL;
84 int iSiteId;
85
86 DWORD dwLen = 0;
87 WCA_WRAPQUERY_HANDLE hQueryWebSite = NULL;
88 WCA_WRAPQUERY_HANDLE hQueryWebAddress = NULL;
89
90 hr = WcaBeginUnwrapQuery(&hQueryWebSite, ppwzCustomActionData);
91 ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead");
92
93 hr = WcaBeginUnwrapQuery(&hQueryWebAddress, ppwzCustomActionData);
94 ExitOnFailure(hr, "Failed to unwrap query for ScaWebsRead");
95
96 if (0 == WcaGetQueryRecords(hQueryWebSite))
97 {
98 WcaLog(LOGMSG_VERBOSE, "Required tables not present");
99 ExitFunction1(hr = S_FALSE);
100 }
101
102 // loop through all the webs
103 while (S_OK == (hr = WcaFetchWrappedRecord(hQueryWebSite, &hRec)))
104 {
105 psw = NewWeb();
106 ExitOnNull(psw, hr, E_OUTOFMEMORY, "Failed to allocate memory for web object in memory");
107
108 // get the darwin information
109 hr = WcaGetRecordString(hRec, wqWeb, &pwzData);
110 ExitOnFailure(hr, "Failed to get Web");
111 hr = ::StringCchCopyW(psw->wzKey, countof(psw->wzKey), pwzData);
112 ExitOnFailure(hr, "Failed to copy key string to web object");
113
114 if (*pwzData && *ppsmmList)
115 {
116 hr = ScaGetMimeMap(mmptWeb, pwzData, ppsmmList, &psw->psmm);
117 ExitOnFailure(hr, "Failed to get mimemap for VirtualDir");
118 }
119
120 // get component install state
121 hr = WcaGetRecordString(hRec, wqComponent, &pwzData);
122 ExitOnFailure(hr, "Failed to get Component for Web");
123 hr = ::StringCchCopyW(psw->wzComponent, countof(psw->wzComponent), pwzData);
124 ExitOnFailure(hr, "Failed to copy component string to web object");
125 if (*(psw->wzComponent))
126 {
127 psw->fHasComponent = TRUE;
128
129 hr = WcaGetRecordInteger(hRec, wqInstalled, (int *)&psw->isInstalled);
130 ExitOnFailure(hr, "Failed to get web Component's installed state");
131
132 WcaGetRecordInteger(hRec, wqAction, (int *)&psw->isAction);
133 ExitOnFailure(hr, "Failed to get web Component's action state");
134
135 if (!WcaIsInstalling(psw->isInstalled, psw->isAction) && !WcaIsUninstalling(psw->isInstalled, psw->isAction)
136 && !WcaIsReInstalling(psw->isInstalled, psw->isAction))
137 {
138 FreeWeb(psw);
139 psw = NULL;
140
141 continue; // If we aren't acting on this component, skip it
142 }
143 }
144
145 hr = WcaGetRecordInteger(hRec, wqId, &iSiteId);
146 ExitOnFailure(hr, "Failed to get SiteId for Web");
147
148 // Get the web's key address.
149 hr = WcaGetRecordString(hRec, wqAddress, &pwzData);
150 ExitOnFailure(hr, "Failed to get Address for Web");
151 hr = ::StringCchCopyW(psw->swaKey.wzKey, countof(psw->swaKey.wzKey), pwzData);
152 ExitOnFailure(hr, "Failed to copy key string to web object");
153
154 hr = WcaGetRecordString(hRec, wqIP, &pwzData);
155 ExitOnFailure(hr, "Failed to get IP for Web");
156 hr = ::StringCchCopyW(psw->swaKey.wzIP, countof(psw->swaKey.wzIP), pwzData);
157 ExitOnFailure(hr, "Failed to copy IP string to web object");
158
159 hr = WcaGetRecordString(hRec, wqPort, &pwzData);
160 ExitOnFailure(hr, "Failed to get Web Address port");
161 psw->swaKey.iPort = wcstol(pwzData, NULL, 10);
162
163 hr = WcaGetRecordString(hRec, wqHeader, &pwzData);
164 ExitOnFailure(hr, "Failed to get Header for Web");
165 hr = ::StringCchCopyW(psw->swaKey.wzHeader, countof(psw->swaKey.wzHeader), pwzData);
166 ExitOnFailure(hr, "Failed to copy header string to web object");
167
168 hr = WcaGetRecordInteger(hRec, wqSecure, &psw->swaKey.fSecure);
169 ExitOnFailure(hr, "Failed to get if Web is secure");
170 if (S_FALSE == hr)
171 {
172 psw->swaKey.fSecure = FALSE;
173 }
174
175 // Get the web's description.
176 hr = WcaGetRecordString(hRec, wqDescription, &pwzData);
177 ExitOnFailure(hr, "Failed to get Description for Web");
178 hr = ::StringCchCopyW(psw->wzDescription, countof(psw->wzDescription), pwzData);
179 ExitOnFailure(hr, "Failed to copy description string to web object");
180
181 // Try to find the web root in case it already exists.
182 dwLen = METADATA_MAX_NAME_LEN;
183 hr = ScaWebFindBase(piMetabase, *ppswList,
184 psw->wzKey,
185 iSiteId,
186 psw->swaKey.wzIP,
187 psw->swaKey.iPort,
188 psw->swaKey.wzHeader,
189 psw->swaKey.fSecure,
190 psw->wzDescription,
191 psw->wzWebBase, dwLen);
192 if (S_OK == hr)
193 {
194 psw->fBaseExists = TRUE;
195 }
196 else if (S_FALSE == hr) // didn't find the web site.
197 {
198 psw->fBaseExists = FALSE;
199
200 // If we're actually configuring the web site.
201 if (psw->fHasComponent)
202 {
203 if (WcaIsInstalling(psw->isInstalled, psw->isAction))
204 {
205 hr = ScaWebFindFreeBase(piMetabase, *ppswList, iSiteId, psw->wzDescription, psw->wzWebBase, countof(psw->wzWebBase));
206 ExitOnFailure(hr, "Failed to find free web root.");
207 }
208 else if (WcaIsUninstalling(psw->isInstalled, psw->isAction))
209 {
210 WcaLog(LOGMSG_VERBOSE, "Web site: '%ls' was already removed, skipping.", psw->wzKey);
211
212 hr = S_OK;
213 continue;
214 }
215 }
216 }
217 ExitOnFailure(hr, "Failed to find web root");
218
219 // get any extra web addresses
220 WcaFetchWrappedReset(hQueryWebAddress);
221 while (S_OK == (hr = WcaFetchWrappedRecordWhereString(hQueryWebAddress, 2, psw->wzKey, &hRecAddresses)))
222 {
223 if (MAX_ADDRESSES_PER_WEB <= psw->cExtraAddresses)
224 {
225 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
226 ExitOnFailure(hr, "Failure to get more extra web addresses, max exceeded.");
227 }
228
229 hr = WcaGetRecordString(hRecAddresses, waqAddress, &pwzData);
230 ExitOnFailure(hr, "Failed to get extra web Address");
231
232 // if this isn't the key address add it
233 if (0 != lstrcmpW(pwzData, psw->swaKey.wzKey))
234 {
235 hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzKey), pwzData);
236 ExitOnFailure(hr, "Failed to copy extra addresses key string to web object");
237
238 hr = WcaGetRecordString(hRecAddresses, waqIP, &pwzData);
239 ExitOnFailure(hr, "Failed to get extra web IP");
240 hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzIP), pwzData);
241 ExitOnFailure(hr, "Failed to copy extra addresses IP string to web object");
242
243 hr = WcaGetRecordString(hRecAddresses, waqPort, &pwzData);
244 ExitOnFailure(hr, "Failed to get port for extra web IP");
245 psw->swaExtraAddresses[psw->cExtraAddresses].iPort= wcstol(pwzData, NULL, 10);
246
247 hr = WcaGetRecordString(hRecAddresses, waqHeader, &pwzData);
248 ExitOnFailure(hr, "Failed to get header for extra web IP");
249 hr = ::StringCchCopyW(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader, countof(psw->swaExtraAddresses[psw->cExtraAddresses].wzHeader), pwzData);
250 ExitOnFailure(hr, "Failed to copy extra addresses header string to web object");
251
252 hr = WcaGetRecordInteger(hRecAddresses, waqSecure, &psw->swaExtraAddresses[psw->cExtraAddresses].fSecure);
253 ExitOnFailure(hr, "Failed to get if secure extra web IP");
254 if (S_FALSE == hr)
255 psw->swaExtraAddresses[psw->cExtraAddresses].fSecure = FALSE;
256
257 ++psw->cExtraAddresses;
258 }
259 }
260
261 if (E_NOMOREITEMS == hr)
262 hr = S_OK;
263 ExitOnFailure(hr, "Failure occured while getting extra web addresses");
264
265 hr = WcaGetRecordInteger(hRec, wqConnectionTimeout, &psw->iConnectionTimeout);
266 ExitOnFailure(hr, "Failed to get connection timeout for Web");
267
268 if (psw->fHasComponent) // If we're installing it, it needs a dir
269 {
270 // get the web's directory
271 if (INSTALLSTATE_SOURCE == psw->isAction)
272 {
273 hr = WcaGetRecordString(hRec, wqSourcePath, &pwzData);
274 }
275 else
276 {
277 hr = WcaGetRecordString(hRec, wqTargetPath, &pwzData);
278 }
279 ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory");
280
281 // remove trailing backslashes
282 while (lstrlenW(pwzData) > 0 && pwzData[lstrlenW(pwzData)-1] == L'\\')
283 {
284 pwzData[lstrlenW(pwzData)-1] = 0;
285 }
286 hr = ::StringCchCopyW(psw->wzDirectory, countof(psw->wzDirectory), pwzData);
287 ExitOnFailure(hr, "Failed to copy directory string to web object");
288 }
289
290 hr = WcaGetRecordInteger(hRec, wqState, &psw->iState);
291 ExitOnFailure(hr, "Failed to get state for Web");
292
293 hr = WcaGetRecordInteger(hRec, wqAttributes, &psw->iAttributes);
294 ExitOnFailure(hr, "Failed to get attributes for Web");
295
296 // get the dir properties for this web
297 hr = WcaGetRecordString(hRec, wqProperties, &pwzData);
298 ExitOnFailure(hr, "Failed to get directory property record for Web");
299 if (*pwzData)
300 {
301 hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &psw->swp);
302 ExitOnFailure(hr, "Failed to get directory properties for Web");
303
304 psw->fHasProperties = TRUE;
305 }
306
307 // get the application information for this web
308 hr = WcaGetRecordString(hRec, wqApplication, &pwzData);
309 ExitOnFailure(hr, "Failed to get application identifier for Web");
310 if (*pwzData)
311 {
312 hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &psw->swapp);
313 ExitOnFailure(hr, "Failed to get application for Web");
314
315 psw->fHasApplication = TRUE;
316 }
317
318 // get the SSL certificates
319 hr = ScaSslCertificateRead(psw->wzKey, hSslCertQuery, &(psw->pswscList));
320 ExitOnFailure(hr, "Failed to get SSL Certificates.");
321
322 // get the custom headers
323 if (*ppshhList)
324 {
325 hr = ScaGetHttpHeader(hhptWeb, psw->wzKey, ppshhList, &(psw->pshhList));
326 ExitOnFailure(hr, "Failed to get Custom HTTP Headers");
327 }
328
329 // get the errors
330 if (*ppsweList)
331 {
332 hr = ScaGetWebError(weptWeb, psw->wzKey, ppsweList, &(psw->psweList));
333 ExitOnFailure(hr, "Failed to get Custom Errors");
334 }
335
336 // get the log information for this web
337 hr = WcaGetRecordString(hRec, wqLog, &pwzData);
338 ExitOnFailure(hr, "Failed to get log identifier for Web");
339 if (*pwzData)
340 {
341 hr = ScaGetWebLog(piMetabase, pwzData, hWebLogQuery, &psw->swl);
342 ExitOnFailure(hr, "Failed to get Log for Web.");
343
344 psw->fHasLog = TRUE;
345 }
346
347 *ppswList = AddWebToList(*ppswList, psw);
348 psw = NULL; // set the web NULL so it doesn't accidentally get freed below
349 }
350
351 if (E_NOMOREITEMS == hr)
352 {
353 hr = S_OK;
354 }
355
356LExit:
357 // if anything was left over after an error clean it all up
358 WcaFinishUnwrapQuery(hQueryWebSite);
359 WcaFinishUnwrapQuery(hQueryWebAddress);
360
361 if (psw)
362 {
363 ScaWebsFreeList(psw);
364 }
365
366 ReleaseStr(pwzData);
367
368 return hr;
369}
370
371
372HRESULT ScaWebsGetBase(
373 __in IMSAdminBase* piMetabase,
374 __in SCA_WEB* pswList,
375 __in LPCWSTR wzWeb,
376 __out_ecount(cchWebBase) LPWSTR wzWebBase,
377 __in DWORD cchWebBase,
378 __in WCA_WRAPQUERY_HANDLE hWrapQuery
379 )
380{
381 HRESULT hr = S_OK;
382 MSIHANDLE hRec;
383
384 int iSiteId;
385 WCHAR wzIP[MAX_PATH];
386 int iPort = -1;
387 WCHAR wzHeader[MAX_PATH];
388 BOOL fSecure = FALSE;
389
390 LPWSTR pwzData = NULL;
391
392 // get the web information
393 WcaFetchWrappedReset(hWrapQuery);
394
395 hr = WcaFetchWrappedRecordWhereString(hWrapQuery, 1, wzWeb, &hRec);
396 if (S_OK == hr)
397 {
398 // get the data to search for
399 hr = WcaGetRecordInteger(hRec, wbqId, &iSiteId);
400 ExitOnFailure(hr, "Failed to get SiteId for Web for VirtualDir");
401
402 hr = WcaGetRecordString(hRec, wbqIP, &pwzData);
403 ExitOnFailure(hr, "Failed to get IP for Web for VirtualDir");
404 hr = ::StringCchCopyW(wzIP, countof(wzIP), pwzData);
405 ExitOnFailure(hr, "Failed to copy IP for Web for VirtualDir");
406
407 hr = WcaGetRecordString(hRec, wbqPort, &pwzData);
408 ExitOnFailure(hr, "Failed to get port for extra web IP");
409 iPort = wcstol(pwzData, NULL, 10);
410
411 hr = WcaGetRecordString(hRec, wbqHeader, &pwzData);
412 ExitOnFailure(hr, "Failed to get Header for Web for VirtualDir");
413 hr = ::StringCchCopyW(wzHeader, countof(wzHeader), pwzData);
414 ExitOnFailure(hr, "Failed to copy Header for Web for VirtualDir");
415
416 hr = WcaGetRecordInteger(hRec, wbqSecure, &fSecure);
417 if (S_FALSE == hr)
418 fSecure = FALSE;
419
420 hr = WcaGetRecordString(hRec, wbqDescription, &pwzData);
421 ExitOnFailure(hr, "Failed to get Description for Web");
422
423 // find the web or find the next free web location
424 hr = ScaWebFindBase(piMetabase, pswList, wzWeb, iSiteId, wzIP, iPort, wzHeader, fSecure, pwzData, wzWebBase, cchWebBase);
425 if (S_FALSE == hr)
426 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
427 ExitOnFailure(hr, "Failed to find Web base");
428 }
429 else if (S_FALSE == hr)
430 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
431
432 // Let's check that there isn't more than one record found - if there is, throw an assert like WcaFetchSingleRecord() would
433 HRESULT hrTemp = WcaFetchWrappedRecordWhereString(hWrapQuery, 1, wzWeb, &hRec);
434 if (SUCCEEDED(hrTemp))
435 {
436 AssertSz(E_NOMOREITEMS == hrTemp, "ScaWebsGetBase found more than one record");
437 }
438
439LExit:
440 ReleaseStr(pwzData);
441
442 return hr;
443}
444
445
446HRESULT ScaWebsInstall(
447 __in IMSAdminBase* piMetabase,
448 __in SCA_WEB* pswList,
449 __in SCA_APPPOOL * psapList
450 )
451{
452 HRESULT hr = S_OK;
453 SCA_WEB* psw = pswList;
454
455 while (psw)
456 {
457 // if we are installing the web site
458 if (psw->fHasComponent && WcaIsInstalling(psw->isInstalled, psw->isAction))
459 {
460 hr = ScaWebWrite(piMetabase, psw, psapList);
461 ExitOnFailure(hr, "failed to write web '%ls' to metabase", psw->wzKey);
462 }
463
464 psw = psw->pswNext;
465 }
466
467LExit:
468 return hr;
469}
470
471
472HRESULT ScaWebsUninstall(
473 __in IMSAdminBase* piMetabase,
474 __in SCA_WEB* pswList
475 )
476{
477 HRESULT hr = S_OK;
478 SCA_WEB* psw = pswList;
479
480 while (psw)
481 {
482 // if we are uninstalling the web site
483 if (psw->fHasComponent && WcaIsUninstalling(psw->isInstalled, psw->isAction))
484 {
485 hr = ScaWebRemove(piMetabase, psw);
486 ExitOnFailure(hr, "Failed to remove web '%ls' from metabase", psw->wzKey);
487 }
488
489 psw = psw->pswNext;
490 }
491
492LExit:
493 return hr;
494}
495
496
497void ScaWebsFreeList(
498 __in SCA_WEB* pswList
499 )
500{
501 SCA_WEB* pswDelete = pswList;
502 while (pswList)
503 {
504 pswDelete = pswList;
505 pswList = pswList->pswNext;
506
507 // Free the SSL, headers and errors list first
508 FreeWeb(pswDelete);
509 }
510}
511
512
513// private helper functions
514
515static void FreeWeb(SCA_WEB *pswDelete)
516{
517 ScaSslCertificateFreeList(pswDelete->pswscList);
518 ScaHttpHeaderFreeList(pswDelete->pshhList);
519 ScaWebErrorFreeList(pswDelete->psweList);
520 MemFree(pswDelete);
521}
522
523static SCA_WEB* NewWeb()
524{
525 SCA_WEB* psw = static_cast<SCA_WEB*>(MemAlloc(sizeof(SCA_WEB), TRUE));
526 Assert(psw);
527 return psw;
528}
529
530
531static SCA_WEB* AddWebToList(
532 __in SCA_WEB* pswList,
533 __in SCA_WEB* psw
534 )
535{
536 if (pswList)
537 {
538 SCA_WEB* pswTemp = pswList;
539 while (pswTemp->pswNext)
540 {
541 pswTemp = pswTemp->pswNext;
542 }
543
544 pswTemp->pswNext = psw;
545 }
546 else
547 {
548 pswList = psw;
549 }
550
551 return pswList;
552}
553
554
555static HRESULT ScaWebFindBase(
556 __in IMSAdminBase* piMetabase,
557 __in SCA_WEB* pswList,
558 __in_z LPCWSTR wzWeb,
559 __in int iSiteId,
560 __in_z LPCWSTR wzIP,
561 __in int iPort,
562 __in_z LPCWSTR wzHeader,
563 __in BOOL fSecure,
564 __in_z LPCWSTR wzDescription,
565 __out_ecount(cchWebBase) LPWSTR wzWebBase,
566 __in DWORD cchWebBase
567 )
568{
569 Assert(piMetabase);
570
571 HRESULT hr = S_OK;
572
573 WCHAR wzKey[METADATA_MAX_NAME_LEN];
574 WCHAR wzSubkey[METADATA_MAX_NAME_LEN];
575 LPWSTR wzFoundKey = NULL;
576
577 METADATA_RECORD mr;
578 ::ZeroMemory(&mr, sizeof(mr));
579
580 METADATA_RECORD mrCompare;
581 ::ZeroMemory(&mrCompare, sizeof(mrCompare));
582
583 // try to find the web in memory first
584 for (SCA_WEB* psw = pswList; psw; psw = psw->pswNext)
585 {
586 if (0 == lstrcmpW(wzWeb, psw->wzKey))
587 {
588 if ((0 == lstrcmpW(wzIP, psw->swaKey.wzIP) || 0 == lstrcmpW(wzIP, L"*") || 0 == lstrcmpW(psw->swaKey.wzIP, L"*")) &&
589 iPort == psw->swaKey.iPort &&
590 0 == lstrcmpW(wzHeader, psw->swaKey.wzHeader) &&
591 fSecure == psw->swaKey.fSecure)
592 {
593 if (0 == lstrlenW(psw->wzWebBase))
594 {
595 WcaLog(LOGMSG_STANDARD, "A matching web object in memory was found, but the web object in memory has no associated base");
596 ExitFunction1(hr = S_FALSE);
597 }
598
599 hr = ::StringCchCopyW(wzKey, countof(wzKey), psw->wzWebBase);
600 ExitOnFailure(hr, "Failed to copy web base into key.");
601
602 wzFoundKey = wzKey;
603 break;
604 }
605 else
606 {
607 WcaLog(LOGMSG_STANDARD, "Found web `%ls` but data did not match.", wzWeb);
608 hr = E_UNEXPECTED;
609 break;
610 }
611 }
612 }
613 ExitOnFailure(hr, "Failure occured while searching for web in memory");
614
615 // If we didn't find a web in memory matching look in the metabase.
616 if (!wzFoundKey)
617 {
618 mr.dwMDIdentifier = MD_KEY_TYPE;
619 mr.dwMDAttributes = METADATA_INHERIT;
620 mr.dwMDUserType = IIS_MD_UT_SERVER;
621 mr.dwMDDataType = ALL_METADATA;
622 mr.dwMDDataLen = 0;
623 mr.pbMDData = NULL;
624
625 // If we're looking based on the old WebAddress detection (NULL) or the new
626 // Web description detection (-1)
627 if (MSI_NULL_INTEGER == iSiteId || -1 == iSiteId)
628 {
629 if (MSI_NULL_INTEGER == iSiteId)
630 {
631 mrCompare.dwMDIdentifier = (fSecure) ? MD_SECURE_BINDINGS : MD_SERVER_BINDINGS;
632 }
633 else
634 {
635 mrCompare.dwMDIdentifier = MD_SERVER_COMMENT;
636 }
637 mrCompare.dwMDAttributes = METADATA_INHERIT;
638 mrCompare.dwMDUserType = IIS_MD_UT_SERVER;
639 mrCompare.dwMDDataType = ALL_METADATA;
640 mrCompare.dwMDDataLen = 0;
641 mrCompare.pbMDData = NULL;
642
643 // Loop through the "web keys" looking for the "IIsWebServer" key that matches our search criteria.
644 for (DWORD dwIndex = 0; SUCCEEDED(hr); ++dwIndex)
645 {
646 hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC", wzSubkey, dwIndex);
647 if (SUCCEEDED(hr))
648 {
649 hr = ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%s", wzSubkey);
650 ExitOnFailure(hr, "Failed to copy web subkey.");
651
652 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr);
653 if (MD_ERROR_DATA_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
654 {
655 hr = S_FALSE; // didn't find anything, try next one
656 continue;
657 }
658 ExitOnFailure(hr, "Failed to get key from metabase while searching for web servers");
659
660 // If we have an IIsWebServer check to see if this is the site we are searching for.
661 if (0 == lstrcmpW(L"IIsWebServer", (LPCWSTR)mr.pbMDData))
662 {
663 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mrCompare);
664 if (MD_ERROR_DATA_NOT_FOUND == hr || NULL == mrCompare.pbMDData)
665 {
666 hr = S_FALSE;
667 continue;
668 }
669 ExitOnFailure(hr, "Failed to get address/description from metabase while searching for web servers");
670
671 LPWSTR pwzExists = (LPWSTR)mrCompare.pbMDData;
672 if (MSI_NULL_INTEGER == iSiteId)
673 {
674 // Break down the address into its constituent parts (IP:Port:Header).
675 while (S_OK == hr && *pwzExists)
676 {
677 LPCWSTR pwzIPExists = pwzExists;
678 pwzExists = const_cast<LPWSTR>(wcsstr(pwzIPExists, L":"));
679 ExitOnNull(pwzExists, hr, E_INVALIDARG, "Invalid web address. IP was not separated by a colon.");
680 *pwzExists = L'\0';
681
682 LPCWSTR pwzPortExists = pwzExists + 1;
683 pwzExists = const_cast<LPWSTR>(wcsstr(pwzPortExists, L":"));
684 ExitOnNull(pwzExists, hr, E_INVALIDARG, "Invalid web address. Port was not separated by a colon.");
685 *pwzExists = L'\0';
686 int iPortExists = wcstol(pwzPortExists, NULL, 10);
687
688 LPCWSTR pwzHeaderExists = pwzExists + 1;
689
690 // compare the passed in address with the address listed for this web
691 if ((0 == lstrcmpW(wzIP, pwzIPExists) || 0 == lstrcmpW(wzIP, L"*")) &&
692 iPort == iPortExists &&
693 0 == lstrcmpW(wzHeader, pwzHeaderExists))
694 {
695 wzFoundKey = wzKey;
696 break;
697 }
698
699 // move to the next block of data, this may move beyond the available
700 // data and exit the while loop above.
701 pwzExists = const_cast<LPWSTR>(pwzHeaderExists + lstrlenW(pwzHeaderExists) + 1);
702 }
703 }
704 else
705 {
706 if (0 == lstrcmpW(wzDescription, pwzExists))
707 {
708 wzFoundKey = wzKey;
709 }
710 }
711
712 // If we found the key we were looking for, no point in continuing to search.
713 if (wzFoundKey)
714 {
715 break;
716 }
717 }
718 }
719 }
720
721 if (E_NOMOREITEMS == hr)
722 {
723 Assert(!wzFoundKey);
724 hr = S_FALSE;
725 }
726 }
727 else // we're looking a specific SiteId
728 {
729 hr = ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%d", iSiteId);
730 ExitOnFailure(hr, "Failed to allocate metabase key string.");
731
732 // if we have an IIsWebServer store the key
733 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr);
734
735 if (SUCCEEDED(hr) && NULL != mr.pbMDData && 0 == lstrcmpW(L"IIsWebServer", (LPCWSTR)mr.pbMDData))
736 {
737 wzFoundKey = wzKey;
738 }
739 else if (MD_ERROR_DATA_NOT_FOUND == hr || NULL == mrCompare.pbMDData || NULL == mr.pbMDData)
740 {
741 hr = S_FALSE;
742 }
743 }
744 }
745
746 if (wzFoundKey)
747 {
748 Assert(S_OK == hr);
749
750 hr = ::StringCchCopyW(wzWebBase, cchWebBase, wzFoundKey);
751 ExitOnFailure(hr, "Buffer not larger enough for found base key.");
752 }
753
754LExit:
755 MetaFreeValue(&mr);
756 MetaFreeValue(&mrCompare);
757
758 if (!wzFoundKey && SUCCEEDED(hr))
759 {
760 hr = S_FALSE;
761 }
762
763 return hr;
764}
765
766
767static HRESULT ScaWebFindFreeBase(
768 __in IMSAdminBase* piMetabase,
769 __in_xcount(unknown) SCA_WEB* pswList,
770 __in int iSiteId,
771 __in_z LPCWSTR wzDescription,
772 __out_ecount(cchWebBase) LPWSTR wzWebBase,
773 __in DWORD cchWebBase
774 )
775{
776 Assert(piMetabase);
777
778 HRESULT hr = S_OK;
779
780 WCHAR wzKey[METADATA_MAX_NAME_LEN];
781 WCHAR wzSubkey[METADATA_MAX_NAME_LEN];
782 DWORD* prgdwSubKeys = NULL;
783 DWORD cSubKeys = 128;
784 DWORD cSubKeysFilled = 0;
785
786 DWORD dwKey;
787
788 METADATA_RECORD mr;
789 ::ZeroMemory(&mr, sizeof(METADATA_RECORD));
790 mr.dwMDIdentifier = MD_KEY_TYPE;
791 mr.dwMDAttributes = 0;
792 mr.dwMDUserType = IIS_MD_UT_SERVER;
793 mr.dwMDDataType = STRING_METADATA;
794 mr.dwMDDataLen = 0;
795 mr.pbMDData = NULL;
796
797 if (MSI_NULL_INTEGER == iSiteId || -1 == iSiteId)
798 {
799 prgdwSubKeys = static_cast<DWORD*>(MemAlloc(cSubKeys * sizeof(DWORD), TRUE));
800 ExitOnNull(prgdwSubKeys, hr, E_OUTOFMEMORY, "failed to allocate space for web site keys");
801
802 // loop through the "web keys" looking for the "IIsWebServer" key that matches wzWeb
803 for (DWORD dwIndex = 0; SUCCEEDED(hr); ++dwIndex)
804 {
805 hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC", wzSubkey, dwIndex);
806 if (SUCCEEDED(hr))
807 {
808 hr = ::StringCchPrintfW(wzKey, countof(wzKey), L"/LM/W3SVC/%s", wzSubkey);
809 ExitOnFailure(hr, "Failed remember key.");
810
811 hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzKey, &mr);
812 if (MD_ERROR_DATA_NOT_FOUND == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
813 {
814 hr = S_FALSE; // didn't find anything, try next one
815 continue;
816 }
817 ExitOnFailure(hr, "Failed to get key from metabase while searching for free web root");
818
819 // if we have a IIsWebServer get the address information
820 if (0 == lstrcmpW(L"IIsWebServer", (LPCWSTR)mr.pbMDData))
821 {
822 if (cSubKeysFilled >= cSubKeys)
823 {
824 cSubKeys = cSubKeys * 2;
825 prgdwSubKeys = static_cast<DWORD*>(MemReAlloc(prgdwSubKeys, cSubKeys * sizeof(DWORD), FALSE));
826 ExitOnNull(prgdwSubKeys, hr, E_OUTOFMEMORY, "failed to allocate space for web site keys");
827 }
828
829 prgdwSubKeys[cSubKeysFilled] = wcstol(wzSubkey, NULL, 10);
830 ++cSubKeysFilled;
831 Sort(prgdwSubKeys, cSubKeysFilled);
832 }
833 }
834 }
835
836 if (E_NOMOREITEMS == hr)
837 {
838 hr = S_OK;
839 }
840 ExitOnFailure(hr, "Failed to find free web root");
841
842 // Add all the webs created in memory.
843 CONST WCHAR *pcchSlash;
844 for (SCA_WEB* psw = pswList; psw; psw = psw->pswNext)
845 {
846 // Don't process webs that don't have a base
847 if (!*psw->wzWebBase)
848 {
849 continue;
850 }
851
852 // find the last slash in the web root because the root # is after it
853 pcchSlash = NULL;
854 for (CONST WCHAR *pcch = psw->wzWebBase; pcch && *pcch; ++pcch)
855 {
856 if (L'/' == *pcch)
857 {
858 pcchSlash = pcch;
859 }
860 }
861 // In case we don't find a slash, error out
862 ExitOnNull(pcchSlash, hr, E_INVALIDARG, "Failed to find a slash in the web root: %ls", psw->wzWebBase);
863
864 prgdwSubKeys[cSubKeysFilled] = wcstol(pcchSlash + 1, NULL, 10);
865 ++cSubKeysFilled;
866 Sort(prgdwSubKeys, cSubKeysFilled);
867
868 if (cSubKeysFilled >= cSubKeys)
869 {
870 cSubKeys = cSubKeys * 2;
871 prgdwSubKeys = static_cast<DWORD*>(MemReAlloc(prgdwSubKeys, cSubKeys * sizeof(DWORD), FALSE));
872 ExitOnNull(prgdwSubKeys, hr, E_OUTOFMEMORY, "failed to allocate space for web site keys");
873 }
874 }
875
876 // Find the lowest free web root.
877 dwKey = (-1 == iSiteId) ? SiteIdFromDescription(wzDescription) : 1;
878 for (DWORD i = 0; i < cSubKeysFilled; ++i)
879 {
880 if (dwKey == prgdwSubKeys[i])
881 {
882 ++dwKey;
883 }
884 else if (dwKey < prgdwSubKeys[i])
885 {
886 break;
887 }
888 }
889 }
890 else
891 {
892 dwKey = iSiteId;
893 }
894
895 hr = ::StringCchPrintfW(wzWebBase, cchWebBase, L"/LM/W3SVC/%u", dwKey);
896 ExitOnFailure(hr, "failed to format web base with key: %u", dwKey);
897
898LExit:
899 MetaFreeValue(&mr);
900
901 if (prgdwSubKeys)
902 {
903 MemFree(prgdwSubKeys);
904 }
905
906 return hr;
907}
908
909
910static HRESULT ScaWebWrite(
911 __in IMSAdminBase* piMetabase,
912 __in SCA_WEB* psw,
913 __in SCA_APPPOOL * psapList)
914{
915 HRESULT hr = S_OK;
916
917 UINT ui = 0;
918 WCHAR wzIP[64];
919 WCHAR wzBindings[1024];
920 WCHAR wzSecureBindings[1024];
921 WCHAR* pcchNext; // used to properly create the MULTI_SZ
922 DWORD cchPcchNext;
923 WCHAR* pcchSecureNext ; // used to properly create the MULTI_SZ
924 DWORD cchPcchSecureNext;
925
926 // if the web root doesn't exist create it
927 if (!psw->fBaseExists)
928 {
929 hr = ScaCreateWeb(piMetabase, psw->wzKey, psw->wzWebBase);
930 ExitOnFailure(hr, "Failed to create web");
931 }
932 else if (psw->iAttributes & SWATTRIB_NOCONFIGUREIFEXISTS) // if we're not supposed to configure existing webs, bail
933 {
934 Assert(psw->fBaseExists);
935
936 hr = S_FALSE;
937 WcaLog(LOGMSG_VERBOSE, "Skipping configuration of existing web: %ls", psw->wzKey);
938 ExitFunction();
939 }
940
941 // put the secure and non-secure bindings together as MULTI_SZs
942 ::ZeroMemory(wzBindings, sizeof(wzBindings));
943 pcchNext = wzBindings;
944 cchPcchNext = countof(wzBindings);
945 ::ZeroMemory(wzSecureBindings, sizeof(wzSecureBindings));
946 pcchSecureNext = wzSecureBindings;
947 cchPcchSecureNext = countof(wzSecureBindings);
948
949 // set the IP address appropriately
950 if (0 == lstrcmpW(psw->swaKey.wzIP, L"*"))
951 {
952 ::ZeroMemory(wzIP, sizeof(wzIP));
953 }
954 else
955 {
956 hr = ::StringCchCopyW(wzIP, countof(wzIP), psw->swaKey.wzIP);
957 ExitOnFailure(hr, "Failed to copy IP string");
958 }
959
960 WCHAR wzBinding[256];
961 hr = ::StringCchPrintfW(wzBinding, countof(wzBinding), L"%s:%d:%s", wzIP, psw->swaKey.iPort, psw->swaKey.wzHeader);
962 ExitOnFailure(hr, "Failed to format IP:Port:Header binding string");
963 if (psw->swaKey.fSecure)
964 {
965 hr = ::StringCchCopyW(pcchSecureNext, cchPcchSecureNext, wzBinding);
966 ExitOnFailure(hr, "Failed to copy binding string to securenext string");
967 pcchSecureNext += lstrlenW(wzBinding) + 1;
968 cchPcchSecureNext -= lstrlenW(wzBinding) + 1;
969 }
970 else
971 {
972 hr = ::StringCchCopyW(pcchNext, cchPcchNext, wzBinding);
973 ExitOnFailure(hr, "Failed to copy binding string to next string");
974 pcchNext += lstrlenW(wzBinding) + 1;
975 cchPcchNext -= lstrlenW(wzBinding) + 1;
976 }
977
978 for (ui = 0; ui < psw->cExtraAddresses; ++ui)
979 {
980 // set the IP address appropriately
981 if (0 == lstrcmpW(psw->swaExtraAddresses[ui].wzIP, L"*"))
982 {
983 ::ZeroMemory(wzIP, sizeof(wzIP));
984 }
985 else
986 {
987 hr = ::StringCchCopyW(wzIP, countof(wzIP), psw->swaExtraAddresses[ui].wzIP);
988 ExitOnFailure(hr, "Failed to copy extra addresses IP to IP string");
989 }
990
991 hr = ::StringCchPrintfW(wzBinding, countof(wzBinding), L"%s:%d:%s", wzIP, psw->swaExtraAddresses[ui].iPort, psw->swaExtraAddresses[ui].wzHeader);
992 ExitOnFailure(hr, "Failed to format IP:Port:Header binding string for extra address");
993 if (psw->swaExtraAddresses[ui].fSecure)
994 {
995 hr = ::StringCchCopyW(pcchSecureNext, cchPcchSecureNext, wzBinding);
996 ExitOnFailure(hr, "Failed to copy binding string to securenext string for extra address");
997 pcchSecureNext += lstrlenW(wzBinding) + 1;
998 cchPcchSecureNext -= lstrlenW(wzBinding) + 1;
999 }
1000 else
1001 {
1002 hr = ::StringCchCopyW(pcchNext, cchPcchNext, wzBinding);
1003 ExitOnFailure(hr, "Failed to copy binding string to next string for extra address");
1004 pcchNext += lstrlenW(wzBinding) + 1;
1005 cchPcchNext -= lstrlenW(wzBinding) + 1;
1006 }
1007 }
1008
1009 // Delete the existing secure bindings metabase value, as having one while SSLCertHash and SSLStoreName aren't both set correctly can result in
1010 // 0x80070520 (ERROR_NO_SUCH_LOGON_SESSION) errors in some situations on IIS7. Clearing this value first and then setting it after the install has completed
1011 // allows the two aforementioned properties to exist in an intermediate state without errors
1012 hr = ScaDeleteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SECURE_BINDINGS, MULTISZ_METADATA);
1013 ExitOnFailure(hr, "Failed to temporarily delete secure bindings for Web");
1014
1015 // now write the bindings to the metabase
1016 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, wzBindings);
1017 ExitOnFailure(hr, "Failed to write server bindings for Web");
1018
1019 // write the target path for the web's directory to the metabase
1020 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"/Root", MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, psw->wzDirectory);
1021 ExitOnFailure(hr, "Failed to write virtual root path for Web");
1022
1023 // write the description for the web to the metabase
1024 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_COMMENT, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, psw->wzDescription);
1025 ExitOnFailure(hr, "Failed to write description for Web");
1026
1027 ui = psw->iConnectionTimeout;
1028 if (MSI_NULL_INTEGER != ui)
1029 {
1030 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_CONNECTION_TIMEOUT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui));
1031 ExitOnFailure(hr, "Failed to write connection timeout for Web");
1032 }
1033
1034 ui = psw->iState;
1035 if (MSI_NULL_INTEGER != ui)
1036 {
1037 if (2 == ui)
1038 {
1039 ui = 1;
1040 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_AUTOSTART, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui));
1041 ExitOnFailure(hr, "Failed to write auto start flag for Web");
1042 ui = 2;
1043 }
1044
1045 if (1 == ui || 2 == ui)
1046 {
1047 ui = 1; // start command
1048 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_COMMAND, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui));
1049 ExitOnFailure(hr, "Failed to start Web");
1050 }
1051 else if (0 == ui)
1052 {
1053 ui = 2; // stop command
1054 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SERVER_COMMAND, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)ui));
1055 ExitOnFailure(hr, "Failed to stop Web");
1056 }
1057 else
1058 {
1059 hr = E_UNEXPECTED;
1060 ExitOnFailure(hr, "Unexpected value for Web State");
1061 }
1062 }
1063
1064 WCHAR wzRootOfWeb[METADATA_MAX_NAME_LEN];
1065 hr = ::StringCchPrintfW(wzRootOfWeb, countof(wzRootOfWeb), L"%s/Root", psw->wzWebBase);
1066 ExitOnFailure(hr, "Failed to allocate WebBase/Root string for root of web");
1067
1068 // write the web dirproperties information
1069 if (psw->fHasProperties)
1070 {
1071 hr = ScaWriteWebDirProperties(piMetabase, wzRootOfWeb, &psw->swp);
1072 ExitOnFailure(hr, "Failed to write web security information to metabase");
1073 }
1074
1075 // write the application information
1076 if (psw->fHasApplication)
1077 {
1078 // On reinstall, we have to uninstall the old application, otherwise a duplicate will be created
1079 if (WcaIsReInstalling(psw->isInstalled, psw->isAction))
1080 {
1081 hr = ScaDeleteApp(piMetabase, wzRootOfWeb);
1082 ExitOnFailure(hr, "Failed to remove application for WebDir as part of a reinstall");
1083 }
1084
1085 hr = ScaWriteWebApplication(piMetabase, wzRootOfWeb, &psw->swapp, psapList);
1086 ExitOnFailure(hr, "Failed to write web application information to metabase");
1087 }
1088
1089 // write the SSL certificate information
1090 if (psw->pswscList)
1091 {
1092 hr = ScaSslCertificateWriteMetabase(piMetabase, psw->wzWebBase, psw->pswscList);
1093 ExitOnFailure(hr, "Failed to write SSL certificates for Web site: %ls", psw->wzKey);
1094 }
1095
1096 hr = ScaWriteMetabaseValue(piMetabase, psw->wzWebBase, L"", MD_SECURE_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, wzSecureBindings);
1097 ExitOnFailure(hr, "Failed to write secure bindings for Web");
1098
1099 // write the headers
1100 if (psw->pshhList)
1101 {
1102 hr = ScaWriteHttpHeader(piMetabase, wzRootOfWeb, psw->pshhList);
1103 ExitOnFailure(hr, "Failed to write custom HTTP headers for Web site: %ls", psw->wzKey);
1104 }
1105
1106 // write the errors
1107 if (psw->psweList)
1108 {
1109 hr = ScaWriteWebError(piMetabase, weptWeb, psw->wzWebBase, psw->psweList);
1110 ExitOnFailure(hr, "Failed to write custom web errors for Web site: %ls", psw->wzKey);
1111 }
1112
1113 // write the mimetypes
1114 if (psw->psmm)
1115 {
1116 hr = ScaWriteMimeMap(piMetabase, wzRootOfWeb, psw->psmm);
1117 ExitOnFailure(hr, "Failed to write mimemap for Web site: %ls", psw->wzKey);
1118 }
1119
1120 // write the log information to the metabase
1121 if (psw->fHasLog)
1122 {
1123 hr = ScaWriteWebLog(piMetabase, psw->wzWebBase, &psw->swl);
1124 ExitOnFailure(hr, "Failed to write web log information to metabase");
1125 }
1126
1127LExit:
1128 return hr;
1129}
1130
1131
1132static HRESULT ScaWebRemove(
1133 __in IMSAdminBase* piMetabase,
1134 __in const SCA_WEB* psw
1135 )
1136{
1137 HRESULT hr = S_OK;
1138
1139 // simply remove the root key and everything else is pulled at the same time
1140 hr = ScaDeleteMetabaseKey(piMetabase, psw->wzWebBase, L"");
1141 ExitOnFailure(hr, "Failed to remove web '%ls' from metabase", psw->wzKey);
1142
1143LExit:
1144 return hr;
1145}
1146
1147
1148static DWORD SiteIdFromDescription(
1149 __in_z LPCWSTR wzDescription
1150 )
1151{
1152 LPCWSTR pwz = wzDescription;
1153 DWORD dwSiteId = 0;
1154 while (pwz && *pwz)
1155 {
1156 WCHAR ch = *pwz & 0xdf;
1157 dwSiteId = (dwSiteId * 101) + ch;
1158 ++pwz;
1159 }
1160
1161 return (dwSiteId % INT_MAX) + 1;
1162}
1163
1164
1165// insertion sort
1166static void Sort(
1167 __in_ecount(cArray) DWORD dwArray[],
1168 __in int cArray
1169 )
1170{
1171 int i, j;
1172 DWORD dwData;
1173
1174 for (i = 1; i < cArray; ++i)
1175 {
1176 dwData = dwArray[i];
1177
1178 j = i - 1;
1179 while (0 <= j && dwArray[j] > dwData)
1180 {
1181 dwArray[j + 1] = dwArray[j];
1182 j--;
1183 }
1184
1185 dwArray[j + 1] = dwData;
1186 }
1187}