| 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 | // prototypes |
| 6 | static HRESULT AddVirtualDirToList( |
| 7 | __in SCA_VDIR** psvdList |
| 8 | ); |
| 9 | |
| 10 | |
| 11 | HRESULT __stdcall ScaVirtualDirsRead( |
| 12 | __in IMSAdminBase* piMetabase, |
| 13 | __in SCA_WEB* pswList, |
| 14 | __in SCA_VDIR** ppsvdList, |
| 15 | __in SCA_MIMEMAP** ppsmmList, |
| 16 | __in SCA_HTTP_HEADER** ppshhList, |
| 17 | __in SCA_WEB_ERROR** ppsweList, |
| 18 | __in WCA_WRAPQUERY_HANDLE hUserQuery, |
| 19 | __in WCA_WRAPQUERY_HANDLE hWebBaseQuery, |
| 20 | __in WCA_WRAPQUERY_HANDLE hWebDirPropQuery, |
| 21 | __in WCA_WRAPQUERY_HANDLE hWebAppQuery, |
| 22 | __in WCA_WRAPQUERY_HANDLE hWebAppExtQuery, |
| 23 | __inout LPWSTR *ppwzCustomActionData |
| 24 | ) |
| 25 | { |
| 26 | Assert(piMetabase && ppsvdList); |
| 27 | |
| 28 | HRESULT hr = S_OK; |
| 29 | MSIHANDLE hRec; |
| 30 | INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; |
| 31 | INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; |
| 32 | |
| 33 | SCA_VDIR* pvdir = NULL; |
| 34 | LPWSTR pwzData = NULL; |
| 35 | |
| 36 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; |
| 37 | |
| 38 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); |
| 39 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); |
| 40 | |
| 41 | if (0 == WcaGetQueryRecords(hWrapQuery)) |
| 42 | { |
| 43 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaVirtualDirsRead() because IIsWebVirtualDir table not present"); |
| 44 | ExitFunction1(hr = S_FALSE); |
| 45 | } |
| 46 | |
| 47 | // loop through all the vdirs |
| 48 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) |
| 49 | { |
| 50 | // Get the Component first. If there is a Component and it is not being modified during |
| 51 | // this transaction, skip processing this whole record. |
| 52 | hr = WcaGetRecordString(hRec, vdqComponent, &pwzData); |
| 53 | ExitOnFailure(hr, "failed to get IIsWebVirtualDir.Component"); |
| 54 | |
| 55 | hr = WcaGetRecordInteger(hRec, vdqInstalled, (int *)&isInstalled); |
| 56 | ExitOnFailure(hr, "Failed to get Component installed state for virtual dir"); |
| 57 | |
| 58 | hr = WcaGetRecordInteger(hRec, vdqAction, (int *)&isAction); |
| 59 | ExitOnFailure(hr, "Failed to get Component action state for virtual dir"); |
| 60 | |
| 61 | if (!WcaIsInstalling(isInstalled, isAction) && |
| 62 | !WcaIsReInstalling(isInstalled, isAction) && |
| 63 | !WcaIsUninstalling(isInstalled, isAction)) |
| 64 | { |
| 65 | continue; // skip this record. |
| 66 | } |
| 67 | |
| 68 | hr = AddVirtualDirToList(ppsvdList); |
| 69 | ExitOnFailure(hr, "failed to add virtual dir to list"); |
| 70 | |
| 71 | pvdir = *ppsvdList; |
| 72 | |
| 73 | hr = ::StringCchCopyW(pvdir->wzComponent, countof(pvdir->wzComponent), pwzData); |
| 74 | ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); |
| 75 | |
| 76 | pvdir->isInstalled = isInstalled; |
| 77 | pvdir->isAction = isAction; |
| 78 | |
| 79 | // get the web key |
| 80 | hr = WcaGetRecordString(hRec, vdqWeb, &pwzData); |
| 81 | ExitOnFailure(hr, "Failed to get Web for VirtualDir"); |
| 82 | |
| 83 | hr = ScaWebsGetBase(piMetabase, pswList, pwzData, pvdir->wzWebBase, countof(pvdir->wzWebBase), hWebBaseQuery); |
| 84 | if (WcaIsUninstalling(isInstalled, isAction)) |
| 85 | { |
| 86 | // If we're uninstalling, ignore any failure to find the existing web |
| 87 | hr = S_OK; |
| 88 | } |
| 89 | ExitOnFailure(hr, "Failed to get base of web: %ls for VirtualDir", pwzData); |
| 90 | |
| 91 | hr = WcaGetRecordString(hRec, vdqAlias, &pwzData); |
| 92 | ExitOnFailure(hr, "Failed to get Alias for VirtualDir"); |
| 93 | |
| 94 | if (0 != lstrlenW(pvdir->wzWebBase)) |
| 95 | { |
| 96 | hr = ::StringCchPrintfW(pvdir->wzVDirRoot, countof(pvdir->wzVDirRoot), L"%s/Root/%s", pvdir->wzWebBase, pwzData); |
| 97 | ExitOnFailure(hr, "Failed to set VDirRoot for VirtualDir"); |
| 98 | } |
| 99 | |
| 100 | // get the vdir's directory |
| 101 | hr = WcaGetRecordString(hRec, vdqDirectory, &pwzData); |
| 102 | ExitOnFailure(hr, "Failed to get Directory for VirtualDir"); |
| 103 | |
| 104 | // get the web's directory |
| 105 | if (INSTALLSTATE_SOURCE == pvdir->isAction) |
| 106 | { |
| 107 | hr = WcaGetRecordString(hRec, vdqSourcePath, &pwzData); |
| 108 | } |
| 109 | else |
| 110 | { |
| 111 | hr = WcaGetRecordString(hRec, vdqTargetPath, &pwzData); |
| 112 | } |
| 113 | ExitOnFailure(hr, "Failed to get Source/TargetPath for Directory"); |
| 114 | |
| 115 | // remove trailing backslash(es) |
| 116 | while (lstrlenW(pwzData) > 0 && pwzData[lstrlenW(pwzData)-1] == L'\\') |
| 117 | { |
| 118 | pwzData[lstrlenW(pwzData)-1] = 0; |
| 119 | } |
| 120 | hr = ::StringCchCopyW(pvdir->wzDirectory, countof(pvdir->wzDirectory), pwzData); |
| 121 | ExitOnFailure(hr, "Failed to copy directory string to vdir object"); |
| 122 | |
| 123 | // get the security information for this web |
| 124 | hr = WcaGetRecordString(hRec, vdqProperties, &pwzData); |
| 125 | ExitOnFailure(hr, "Failed to get web directory identifier for VirtualDir"); |
| 126 | if (*pwzData) |
| 127 | { |
| 128 | hr = ScaGetWebDirProperties(pwzData, hUserQuery, hWebDirPropQuery, &pvdir->swp); |
| 129 | ExitOnFailure(hr, "Failed to get web directory for VirtualDir"); |
| 130 | |
| 131 | pvdir->fHasProperties = TRUE; |
| 132 | } |
| 133 | |
| 134 | // get the application information for this web |
| 135 | hr = WcaGetRecordString(hRec, vdqApplication, &pwzData); |
| 136 | ExitOnFailure(hr, "Failed to get application identifier for VirtualDir"); |
| 137 | if (*pwzData) |
| 138 | { |
| 139 | hr = ScaGetWebApplication(NULL, pwzData, hWebAppQuery, hWebAppExtQuery, &pvdir->swapp); |
| 140 | ExitOnFailure(hr, "Failed to get application for VirtualDir"); |
| 141 | |
| 142 | pvdir->fHasApplication = TRUE; |
| 143 | } |
| 144 | |
| 145 | hr = WcaGetRecordString(hRec, vdqVDir, &pwzData); |
| 146 | ExitOnFailure(hr, "Failed to get VDir for VirtualDir"); |
| 147 | |
| 148 | if (*pwzData && *ppsmmList) |
| 149 | { |
| 150 | hr = ScaGetMimeMap(mmptVDir, pwzData, ppsmmList, &pvdir->psmm); |
| 151 | ExitOnFailure(hr, "Failed to get mimemap for VirtualDir"); |
| 152 | } |
| 153 | |
| 154 | if (*pwzData && *ppshhList) |
| 155 | { |
| 156 | hr = ScaGetHttpHeader(hhptVDir, pwzData, ppshhList, &pvdir->pshh); |
| 157 | ExitOnFailure(hr, "Failed to get custom HTTP headers for VirtualDir: %ls", pwzData); |
| 158 | } |
| 159 | |
| 160 | if (*pwzData && *ppsweList) |
| 161 | { |
| 162 | hr = ScaGetWebError(weptVDir, pwzData, ppsweList, &pvdir->pswe); |
| 163 | ExitOnFailure(hr, "Failed to get custom web errors for VirtualDir: %ls", pwzData); |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | if (E_NOMOREITEMS == hr) |
| 168 | { |
| 169 | hr = S_OK; |
| 170 | } |
| 171 | ExitOnFailure(hr, "Failure while processing VirtualDirs"); |
| 172 | |
| 173 | LExit: |
| 174 | WcaFinishUnwrapQuery(hWrapQuery); |
| 175 | |
| 176 | ReleaseStr(pwzData); |
| 177 | return hr; |
| 178 | } |
| 179 | |
| 180 | |
| 181 | HRESULT ScaVirtualDirsInstall( |
| 182 | __in IMSAdminBase* piMetabase, |
| 183 | __in SCA_VDIR* psvdList, |
| 184 | __in SCA_APPPOOL * psapList |
| 185 | ) |
| 186 | { |
| 187 | Assert(piMetabase); |
| 188 | |
| 189 | HRESULT hr = S_OK; |
| 190 | SCA_VDIR* psvd = psvdList; |
| 191 | int i; |
| 192 | |
| 193 | while (psvd) |
| 194 | { |
| 195 | // On reinstall, we have to uninstall the old application, otherwise a duplicate will be created |
| 196 | if (WcaIsReInstalling(psvd->isInstalled, psvd->isAction)) |
| 197 | { |
| 198 | if (psvd->fHasApplication) |
| 199 | { |
| 200 | hr = ScaDeleteApp(piMetabase, psvd->wzVDirRoot); |
| 201 | ExitOnFailure(hr, "Failed to remove application for WebVDir as part of a reinstall"); |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | if (WcaIsInstalling(psvd->isInstalled, psvd->isAction)) |
| 206 | { |
| 207 | hr = ScaCreateMetabaseKey(piMetabase, psvd->wzVDirRoot, L""); |
| 208 | ExitOnFailure(hr, "Failed to create key for VirtualDir"); |
| 209 | hr = ScaWriteMetabaseValue(piMetabase, psvd->wzVDirRoot, L"", MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsWebVirtualDir"); |
| 210 | ExitOnFailure(hr, "Failed to write key type for for VirtualDir"); |
| 211 | i = 0x4000003e; // 1073741886; // default directory browsing rights |
| 212 | hr = ScaWriteMetabaseValue(piMetabase, psvd->wzVDirRoot, L"", MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, (LPVOID)((DWORD_PTR)i)); |
| 213 | ExitOnFailure(hr, "Failed to set directory browsing for VirtualDir"); |
| 214 | |
| 215 | hr = ScaWriteMetabaseValue(piMetabase, psvd->wzVDirRoot, L"", MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)psvd->wzDirectory); |
| 216 | ExitOnFailure(hr, "Failed to write Directory for VirtualDir"); |
| 217 | |
| 218 | if (psvd->fHasProperties) |
| 219 | { |
| 220 | ScaWriteWebDirProperties(piMetabase, psvd->wzVDirRoot, &psvd->swp); |
| 221 | ExitOnFailure(hr, "Failed to write directory properties for VirtualDir"); |
| 222 | } |
| 223 | |
| 224 | if (psvd->fHasApplication) |
| 225 | { |
| 226 | hr = ScaWriteWebApplication(piMetabase, psvd->wzVDirRoot, &psvd->swapp, psapList); |
| 227 | ExitOnFailure(hr, "Failed to write application for VirtualDir"); |
| 228 | } |
| 229 | |
| 230 | if (psvd->psmm) |
| 231 | { |
| 232 | hr = ScaWriteMimeMap(piMetabase, psvd->wzVDirRoot, psvd->psmm); |
| 233 | ExitOnFailure(hr, "Failed to write mimemap for VirtualDir"); |
| 234 | } |
| 235 | |
| 236 | if (psvd->pshh) |
| 237 | { |
| 238 | hr = ScaWriteHttpHeader(piMetabase, psvd->wzVDirRoot, psvd->pshh); |
| 239 | ExitOnFailure(hr, "Failed to write custom HTTP headers for VirtualDir"); |
| 240 | } |
| 241 | |
| 242 | if (psvd->pswe) |
| 243 | { |
| 244 | hr = ScaWriteWebError(piMetabase, weptVDir, psvd->wzVDirRoot, psvd->pswe); |
| 245 | ExitOnFailure(hr, "Failed to write custom web errors for VirtualDir"); |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | psvd = psvd->psvdNext; |
| 250 | } |
| 251 | |
| 252 | LExit: |
| 253 | return hr; |
| 254 | } |
| 255 | |
| 256 | |
| 257 | HRESULT ScaVirtualDirsUninstall( |
| 258 | __in IMSAdminBase* piMetabase, |
| 259 | __in SCA_VDIR* psvdList |
| 260 | ) |
| 261 | { |
| 262 | Assert(piMetabase); |
| 263 | |
| 264 | HRESULT hr = S_OK; |
| 265 | SCA_VDIR* psvd = psvdList; |
| 266 | |
| 267 | while (psvd) |
| 268 | { |
| 269 | if (WcaIsUninstalling(psvd->isInstalled, psvd->isAction)) |
| 270 | { |
| 271 | // delete the application for this virtual directory |
| 272 | if (psvd->fHasApplication) |
| 273 | { |
| 274 | hr = ScaDeleteApp(piMetabase, psvd->wzVDirRoot); |
| 275 | ExitOnFailure(hr, "Failed to remove application for WebVDir"); |
| 276 | } |
| 277 | |
| 278 | if (0 != lstrlenW(psvd->wzVDirRoot)) |
| 279 | { |
| 280 | hr = ScaDeleteMetabaseKey(piMetabase, psvd->wzVDirRoot, L""); |
| 281 | ExitOnFailure(hr, "Failed to remove VirtualDir '%ls' from metabase", psvd->wzKey); |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | psvd = psvd->psvdNext; |
| 286 | } |
| 287 | |
| 288 | LExit: |
| 289 | return hr; |
| 290 | } |
| 291 | |
| 292 | |
| 293 | void ScaVirtualDirsFreeList( |
| 294 | __in SCA_VDIR* psvdList |
| 295 | ) |
| 296 | { |
| 297 | SCA_VDIR* psvdDelete = psvdList; |
| 298 | while (psvdList) |
| 299 | { |
| 300 | psvdDelete = psvdList; |
| 301 | psvdList = psvdList->psvdNext; |
| 302 | |
| 303 | if (psvdDelete->psmm) |
| 304 | { |
| 305 | ScaMimeMapFreeList(psvdDelete->psmm); |
| 306 | } |
| 307 | |
| 308 | if (psvdDelete->pswe) |
| 309 | { |
| 310 | ScaWebErrorFreeList(psvdDelete->pswe); |
| 311 | } |
| 312 | |
| 313 | MemFree(psvdDelete); |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | |
| 318 | static HRESULT AddVirtualDirToList( |
| 319 | __in SCA_VDIR** ppsvdList |
| 320 | ) |
| 321 | { |
| 322 | HRESULT hr = S_OK; |
| 323 | SCA_VDIR* psvd = static_cast<SCA_VDIR*>(MemAlloc(sizeof(SCA_VDIR), TRUE)); |
| 324 | ExitOnNull(psvd, hr, E_OUTOFMEMORY, "failed to allocate memory for new vdir list element"); |
| 325 | |
| 326 | psvd->psvdNext= *ppsvdList; |
| 327 | *ppsvdList = psvd; |
| 328 | |
| 329 | LExit: |
| 330 | return hr; |
| 331 | } |