diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ca/CustomMsiErrors.h | 10 | ||||
| -rw-r--r-- | src/ca/precomp.h | 14 | ||||
| -rw-r--r-- | src/ca/sca.h | 33 | ||||
| -rw-r--r-- | src/ca/scacost.h | 7 | ||||
| -rw-r--r-- | src/ca/scadb.cpp | 587 | ||||
| -rw-r--r-- | src/ca/scadb.h | 55 | ||||
| -rw-r--r-- | src/ca/scaexec.cpp | 393 | ||||
| -rw-r--r-- | src/ca/scasql.cpp | 113 | ||||
| -rw-r--r-- | src/ca/scasqlstr.cpp | 728 | ||||
| -rw-r--r-- | src/ca/scasqlstr.h | 51 | ||||
| -rw-r--r-- | src/ca/scauser.cpp | 82 | ||||
| -rw-r--r-- | src/ca/scauser.h | 40 | ||||
| -rw-r--r-- | src/ca/sqlca.def | 8 | ||||
| -rw-r--r-- | src/ca/sqlca.vcxproj | 11 |
14 files changed, 2131 insertions, 1 deletions
diff --git a/src/ca/CustomMsiErrors.h b/src/ca/CustomMsiErrors.h new file mode 100644 index 00000000..b568d01c --- /dev/null +++ b/src/ca/CustomMsiErrors.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | #define msierrSQLFailedCreateDatabase 26201 | ||
| 5 | #define msierrSQLFailedDropDatabase 26202 | ||
| 6 | #define msierrSQLFailedConnectDatabase 26203 | ||
| 7 | #define msierrSQLFailedExecString 26204 | ||
| 8 | #define msierrSQLDatabaseAlreadyExists 26205 | ||
| 9 | |||
| 10 | //Last available is 26250 \ No newline at end of file | ||
diff --git a/src/ca/precomp.h b/src/ca/precomp.h index 3edad7ed..7a5074b3 100644 --- a/src/ca/precomp.h +++ b/src/ca/precomp.h | |||
| @@ -2,12 +2,26 @@ | |||
| 2 | // 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 | // 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. |
| 3 | 3 | ||
| 4 | 4 | ||
| 5 | #if _WIN32_MSI < 150 | ||
| 6 | #define _WIN32_MSI 150 | ||
| 7 | #endif | ||
| 8 | |||
| 5 | #include <windows.h> | 9 | #include <windows.h> |
| 6 | #include <msiquery.h> | 10 | #include <msiquery.h> |
| 7 | 11 | ||
| 12 | #include <strsafe.h> | ||
| 13 | |||
| 8 | #define MAXUINT USHRT_MAX | 14 | #define MAXUINT USHRT_MAX |
| 9 | #include <Setup.Configuration.h> | 15 | #include <Setup.Configuration.h> |
| 10 | 16 | ||
| 11 | #include "wcautil.h" | 17 | #include "wcautil.h" |
| 12 | #include "fileutil.h" | 18 | #include "fileutil.h" |
| 19 | #include "memutil.h" | ||
| 13 | #include "strutil.h" | 20 | #include "strutil.h" |
| 21 | #include "wiutil.h" | ||
| 22 | |||
| 23 | #include "CustomMsiErrors.h" | ||
| 24 | |||
| 25 | #include "sca.h" | ||
| 26 | #include "scacost.h" | ||
| 27 | #include "scasqlstr.h" | ||
diff --git a/src/ca/sca.h b/src/ca/sca.h new file mode 100644 index 00000000..bc36344e --- /dev/null +++ b/src/ca/sca.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | // Generic action enum. | ||
| 5 | enum SCA_ACTION | ||
| 6 | { | ||
| 7 | SCA_ACTION_NONE, | ||
| 8 | SCA_ACTION_INSTALL, | ||
| 9 | SCA_ACTION_UNINSTALL | ||
| 10 | }; | ||
| 11 | |||
| 12 | // sql database attributes definitions | ||
| 13 | enum SCADB_ATTRIBUTES | ||
| 14 | { | ||
| 15 | SCADB_CREATE_ON_INSTALL = 0x00000001, | ||
| 16 | SCADB_DROP_ON_UNINSTALL = 0x00000002, | ||
| 17 | SCADB_CONTINUE_ON_ERROR = 0x00000004, | ||
| 18 | SCADB_DROP_ON_INSTALL = 0x00000008, | ||
| 19 | SCADB_CREATE_ON_UNINSTALL = 0x00000010, | ||
| 20 | SCADB_CONFIRM_OVERWRITE = 0x00000020, | ||
| 21 | SCADB_CREATE_ON_REINSTALL = 0x00000040, | ||
| 22 | SCADB_DROP_ON_REINSTALL = 0x00000080, | ||
| 23 | }; | ||
| 24 | |||
| 25 | // sql string/script attributes definitions | ||
| 26 | enum SCASQL_ATTRIBUTES | ||
| 27 | { | ||
| 28 | SCASQL_EXECUTE_ON_INSTALL = 0x00000001, | ||
| 29 | SCASQL_EXECUTE_ON_UNINSTALL = 0x00000002, | ||
| 30 | SCASQL_CONTINUE_ON_ERROR = 0x00000004, | ||
| 31 | SCASQL_ROLLBACK = 0x00000008, | ||
| 32 | SCASQL_EXECUTE_ON_REINSTALL = 0x00000010, | ||
| 33 | }; | ||
diff --git a/src/ca/scacost.h b/src/ca/scacost.h new file mode 100644 index 00000000..6ea7e465 --- /dev/null +++ b/src/ca/scacost.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | const UINT COST_SQL_CREATEDB = 10000; | ||
| 5 | const UINT COST_SQL_DROPDB = 5000; | ||
| 6 | const UINT COST_SQL_CONNECTDB = 5000; | ||
| 7 | const UINT COST_SQL_STRING = 5000; | ||
diff --git a/src/ca/scadb.cpp b/src/ca/scadb.cpp new file mode 100644 index 00000000..9f9efca2 --- /dev/null +++ b/src/ca/scadb.cpp | |||
| @@ -0,0 +1,587 @@ | |||
| 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 | // sql queries | ||
| 6 | LPCWSTR vcsSqlDatabaseQuery = L"SELECT `SqlDb`, `Server`, `Instance`, `Database`, " | ||
| 7 | L"`Component_`, `User_`, `FileSpec_`, `FileSpec_Log`, `Attributes` " | ||
| 8 | L"FROM `SqlDatabase`"; | ||
| 9 | enum eSqlDatabaseQuery { sdqSqlDb = 1, sdqServer, sdqInstance, sdqDatabase, | ||
| 10 | sdqComponent, sdqUser, sdqDbFileSpec, sdqLogFileSpec, sdqAttributes }; | ||
| 11 | |||
| 12 | LPCWSTR vcsSqlFileSpecQuery = L"SELECT `FileSpec`, `Name`, `Filename`, `Size`, " | ||
| 13 | L"`MaxSize`, `GrowthSize` FROM `SqlFileSpec` WHERE `FileSpec`=?"; | ||
| 14 | enum eSqlFileSpecQuery { sfsqFileSpec = 1, sfsqName, sfsqFilename, sfsqSize, | ||
| 15 | sfsqMaxSize, sfsqGrowth }; | ||
| 16 | |||
| 17 | |||
| 18 | // prototypes for private helper functions | ||
| 19 | static HRESULT NewDb( | ||
| 20 | __out SCA_DB** ppsd | ||
| 21 | ); | ||
| 22 | |||
| 23 | static SCA_DB* AddDbToList( | ||
| 24 | __in SCA_DB* psdList, | ||
| 25 | __in SCA_DB* psd | ||
| 26 | ); | ||
| 27 | |||
| 28 | static HRESULT SchedCreateDatabase( | ||
| 29 | __in SCA_DB* psd | ||
| 30 | ); | ||
| 31 | |||
| 32 | static HRESULT SchedDropDatabase( | ||
| 33 | __in LPCWSTR wzKey, LPCWSTR wzServer, | ||
| 34 | __in LPCWSTR wzInstance, | ||
| 35 | __in LPCWSTR wzDatabase, | ||
| 36 | __in int iAttributes, | ||
| 37 | __in BOOL fIntegratedAuth, | ||
| 38 | __in LPCWSTR wzUser, | ||
| 39 | __in LPCWSTR wzPassword | ||
| 40 | ); | ||
| 41 | |||
| 42 | static HRESULT GetFileSpec( | ||
| 43 | __in MSIHANDLE hViewFileSpec, | ||
| 44 | __in LPCWSTR wzKey, | ||
| 45 | __in SQL_FILESPEC* psf | ||
| 46 | ); | ||
| 47 | |||
| 48 | |||
| 49 | HRESULT ScaDbsRead( | ||
| 50 | __inout SCA_DB** ppsdList, | ||
| 51 | __in SCA_ACTION saAction | ||
| 52 | ) | ||
| 53 | { | ||
| 54 | HRESULT hr = S_OK; | ||
| 55 | UINT er = ERROR_SUCCESS; | ||
| 56 | PMSIHANDLE hView; | ||
| 57 | PMSIHANDLE hRec; | ||
| 58 | PMSIHANDLE hViewFileSpec = NULL; | ||
| 59 | |||
| 60 | LPWSTR pwzData = NULL; | ||
| 61 | LPWSTR pwzId = NULL; | ||
| 62 | LPWSTR pwzComponent = NULL; | ||
| 63 | |||
| 64 | SCA_DB* psd = NULL; | ||
| 65 | |||
| 66 | if (S_OK != WcaTableExists(L"SqlDatabase")) | ||
| 67 | { | ||
| 68 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaCreateDatabase() - SqlDatabase table not present"); | ||
| 69 | ExitFunction1(hr = S_FALSE); | ||
| 70 | } | ||
| 71 | |||
| 72 | if (S_OK == WcaTableExists(L"SqlFileSpec")) | ||
| 73 | { | ||
| 74 | hr = WcaOpenView(vcsSqlFileSpecQuery, &hViewFileSpec); | ||
| 75 | ExitOnFailure(hr, "failed to open view on SqlFileSpec table"); | ||
| 76 | } | ||
| 77 | |||
| 78 | // loop through all the sql databases | ||
| 79 | hr = WcaOpenExecuteView(vcsSqlDatabaseQuery, &hView); | ||
| 80 | ExitOnFailure(hr, "Failed to open view on SqlDatabase table"); | ||
| 81 | while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) | ||
| 82 | { | ||
| 83 | BOOL fHasComponent = FALSE; | ||
| 84 | INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; | ||
| 85 | INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; | ||
| 86 | |||
| 87 | hr = WcaGetRecordString(hRec, sdqSqlDb, &pwzId); | ||
| 88 | ExitOnFailure(hr, "Failed to get SqlDatabase.SqlDb"); | ||
| 89 | |||
| 90 | hr = WcaGetRecordString(hRec, sdqComponent, &pwzComponent); | ||
| 91 | ExitOnFailure(hr, "Failed to get Component for database: '%ls'", psd->wzKey); | ||
| 92 | if (pwzComponent && *pwzComponent) | ||
| 93 | { | ||
| 94 | fHasComponent = TRUE; | ||
| 95 | |||
| 96 | er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction); | ||
| 97 | hr = HRESULT_FROM_WIN32(er); | ||
| 98 | ExitOnFailure(hr, "Failed to get state for component: %ls", pwzComponent); | ||
| 99 | |||
| 100 | // If we're doing install but the Component is not being installed or we're doing | ||
| 101 | // uninstall but the Component is not being uninstalled, skip it. | ||
| 102 | if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) || | ||
| 103 | (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction)) | ||
| 104 | { | ||
| 105 | continue; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | hr = NewDb(&psd); | ||
| 110 | ExitOnFailure(hr, "Failed to allocate memory for new database: %D", pwzId); | ||
| 111 | |||
| 112 | hr = ::StringCchCopyW(psd->wzKey, countof(psd->wzKey), pwzId); | ||
| 113 | ExitOnFailure(hr, "Failed to copy SqlDatabase.SqlDbL: %ls", pwzId); | ||
| 114 | |||
| 115 | hr = ::StringCchCopyW(psd->wzComponent, countof(psd->wzComponent), pwzComponent); | ||
| 116 | ExitOnFailure(hr, "Failed to copy SqlDatabase.Component_: %ls", pwzComponent); | ||
| 117 | |||
| 118 | psd->fHasComponent = fHasComponent; | ||
| 119 | psd->isInstalled = isInstalled; | ||
| 120 | psd->isAction = isAction; | ||
| 121 | |||
| 122 | hr = WcaGetRecordFormattedString(hRec, sdqServer, &pwzData); | ||
| 123 | ExitOnFailure(hr, "Failed to get Server for database: '%ls'", psd->wzKey); | ||
| 124 | hr = ::StringCchCopyW(psd->wzServer, countof(psd->wzServer), pwzData); | ||
| 125 | ExitOnFailure(hr, "Failed to copy server string to database object:%ls", pwzData); | ||
| 126 | |||
| 127 | hr = WcaGetRecordFormattedString(hRec, sdqInstance, &pwzData); | ||
| 128 | ExitOnFailure(hr, "Failed to get Instance for database: '%ls'", psd->wzKey); | ||
| 129 | hr = ::StringCchCopyW(psd->wzInstance, countof(psd->wzInstance), pwzData); | ||
| 130 | ExitOnFailure(hr, "Failed to copy instance string to database object:%ls", pwzData); | ||
| 131 | |||
| 132 | hr = WcaGetRecordFormattedString(hRec, sdqDatabase, &pwzData); | ||
| 133 | ExitOnFailure(hr, "Failed to get Database for database: '%ls'", psd->wzKey); | ||
| 134 | hr = ::StringCchCopyW(psd->wzDatabase, countof(psd->wzDatabase), pwzData); | ||
| 135 | ExitOnFailure(hr, "Failed to copy database string to database object:%ls", pwzData); | ||
| 136 | |||
| 137 | hr = WcaGetRecordInteger(hRec, sdqAttributes, &psd->iAttributes); | ||
| 138 | ExitOnFailure(hr, "Failed to get SqlDatabase.Attributes"); | ||
| 139 | |||
| 140 | hr = WcaGetRecordFormattedString(hRec, sdqUser, &pwzData); | ||
| 141 | ExitOnFailure(hr, "Failed to get User record for database: '%ls'", psd->wzKey); | ||
| 142 | |||
| 143 | // if a user was specified | ||
| 144 | if (*pwzData) | ||
| 145 | { | ||
| 146 | psd->fUseIntegratedAuth = FALSE; | ||
| 147 | hr = ScaGetUser(pwzData, &psd->scau); | ||
| 148 | ExitOnFailure(hr, "Failed to get user information for database: '%ls'", psd->wzKey); | ||
| 149 | } | ||
| 150 | else | ||
| 151 | { | ||
| 152 | psd->fUseIntegratedAuth = TRUE; | ||
| 153 | // integrated authorization doesn't have a User record | ||
| 154 | } | ||
| 155 | |||
| 156 | hr = WcaGetRecordString(hRec, sdqDbFileSpec, &pwzData); | ||
| 157 | ExitOnFailure(hr, "Failed to get Database FileSpec for database: '%ls'", psd->wzKey); | ||
| 158 | |||
| 159 | // if a database filespec was specified | ||
| 160 | if (*pwzData) | ||
| 161 | { | ||
| 162 | hr = GetFileSpec(hViewFileSpec, pwzData, &psd->sfDb); | ||
| 163 | ExitOnFailure(hr, "failed to get FileSpec for: %ls", pwzData); | ||
| 164 | if (S_OK == hr) | ||
| 165 | { | ||
| 166 | psd->fHasDbSpec = TRUE; | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | hr = WcaGetRecordString(hRec, sdqLogFileSpec, &pwzData); | ||
| 171 | ExitOnFailure(hr, "Failed to get Log FileSpec for database: '%ls'", psd->wzKey); | ||
| 172 | |||
| 173 | // if a log filespec was specified | ||
| 174 | if (*pwzData) | ||
| 175 | { | ||
| 176 | hr = GetFileSpec(hViewFileSpec, pwzData, &psd->sfLog); | ||
| 177 | ExitOnFailure(hr, "failed to get FileSpec for: %ls", pwzData); | ||
| 178 | if (S_OK == hr) | ||
| 179 | { | ||
| 180 | psd->fHasLogSpec = TRUE; | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | *ppsdList = AddDbToList(*ppsdList, psd); | ||
| 185 | psd = NULL; // set the db NULL so it doesn't accidentally get freed below | ||
| 186 | } | ||
| 187 | |||
| 188 | if (E_NOMOREITEMS == hr) | ||
| 189 | { | ||
| 190 | hr = S_OK; | ||
| 191 | } | ||
| 192 | ExitOnFailure(hr, "Failure occured while processing SqlDatabase table"); | ||
| 193 | |||
| 194 | LExit: | ||
| 195 | if (psd) | ||
| 196 | { | ||
| 197 | ScaDbsFreeList(psd); | ||
| 198 | } | ||
| 199 | |||
| 200 | ReleaseStr(pwzComponent); | ||
| 201 | ReleaseStr(pwzId); | ||
| 202 | ReleaseStr(pwzData); | ||
| 203 | return hr; | ||
| 204 | } | ||
| 205 | |||
| 206 | |||
| 207 | SCA_DB* ScaDbsFindDatabase( | ||
| 208 | __in LPCWSTR wzSqlDb, | ||
| 209 | __in SCA_DB* psdList | ||
| 210 | ) | ||
| 211 | { | ||
| 212 | SCA_DB* psd = NULL; | ||
| 213 | |||
| 214 | for (psd = psdList; psd; psd = psd->psdNext) | ||
| 215 | { | ||
| 216 | if (0 == lstrcmpW(wzSqlDb, psd->wzKey)) | ||
| 217 | { | ||
| 218 | break; | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | return psd; | ||
| 223 | } | ||
| 224 | |||
| 225 | |||
| 226 | HRESULT ScaDbsInstall( | ||
| 227 | __in SCA_DB* psdList | ||
| 228 | ) | ||
| 229 | { | ||
| 230 | HRESULT hr = S_FALSE; // assume nothing will be done | ||
| 231 | SCA_DB* psd = NULL; | ||
| 232 | |||
| 233 | for (psd = psdList; psd; psd = psd->psdNext) | ||
| 234 | { | ||
| 235 | if (psd->fHasComponent) | ||
| 236 | { | ||
| 237 | // if we need to drop, do that first | ||
| 238 | if (((psd->iAttributes & SCADB_DROP_ON_INSTALL) && WcaIsInstalling(psd->isInstalled, psd->isAction) && !WcaIsReInstalling(psd->isInstalled, psd->isAction)) || | ||
| 239 | ((psd->iAttributes & SCADB_DROP_ON_REINSTALL) && WcaIsReInstalling(psd->isInstalled, psd->isAction))) | ||
| 240 | { | ||
| 241 | hr = SchedDropDatabase(psd->wzKey, psd->wzServer, psd->wzInstance, psd->wzDatabase, psd->iAttributes, psd->fUseIntegratedAuth, psd->scau.wzName, psd->scau.wzPassword); | ||
| 242 | ExitOnFailure(hr, "Failed to drop database %ls", psd->wzKey); | ||
| 243 | } | ||
| 244 | |||
| 245 | // if installing this component | ||
| 246 | if (((psd->iAttributes & SCADB_CREATE_ON_INSTALL) && WcaIsInstalling(psd->isInstalled, psd->isAction) && !WcaIsReInstalling(psd->isInstalled, psd->isAction)) || | ||
| 247 | ((psd->iAttributes & SCADB_CREATE_ON_REINSTALL) && WcaIsReInstalling(psd->isInstalled, psd->isAction))) | ||
| 248 | { | ||
| 249 | hr = SchedCreateDatabase(psd); | ||
| 250 | ExitOnFailure(hr, "Failed to ensure database %ls exists", psd->wzKey); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | LExit: | ||
| 256 | return hr; | ||
| 257 | } | ||
| 258 | |||
| 259 | |||
| 260 | HRESULT ScaDbsUninstall( | ||
| 261 | __in SCA_DB* psdList | ||
| 262 | ) | ||
| 263 | { | ||
| 264 | HRESULT hr = S_FALSE; // assume nothing will be done | ||
| 265 | SCA_DB* psd = NULL; | ||
| 266 | |||
| 267 | for (psd = psdList; psd; psd = psd->psdNext) | ||
| 268 | { | ||
| 269 | if (psd->fHasComponent) | ||
| 270 | { | ||
| 271 | // if we need to drop do that first | ||
| 272 | if ((psd->iAttributes & SCADB_DROP_ON_UNINSTALL) && WcaIsUninstalling(psd->isInstalled, psd->isAction)) | ||
| 273 | { | ||
| 274 | hr = SchedDropDatabase(psd->wzKey, psd->wzServer, psd->wzInstance, psd->wzDatabase, psd->iAttributes, psd->fUseIntegratedAuth, psd->scau.wzName, psd->scau.wzPassword); | ||
| 275 | ExitOnFailure(hr, "Failed to drop database %ls", psd->wzKey); | ||
| 276 | } | ||
| 277 | |||
| 278 | // install the db | ||
| 279 | if ((psd->iAttributes & SCADB_CREATE_ON_UNINSTALL) && WcaIsUninstalling(psd->isInstalled, psd->isAction)) | ||
| 280 | { | ||
| 281 | hr = SchedCreateDatabase(psd); | ||
| 282 | ExitOnFailure(hr, "Failed to ensure database %ls exists", psd->wzKey); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | LExit: | ||
| 288 | return hr; | ||
| 289 | } | ||
| 290 | |||
| 291 | |||
| 292 | void ScaDbsFreeList( | ||
| 293 | __in SCA_DB* psdList | ||
| 294 | ) | ||
| 295 | { | ||
| 296 | SCA_DB* psdDelete = psdList; | ||
| 297 | while (psdList) | ||
| 298 | { | ||
| 299 | psdDelete = psdList; | ||
| 300 | psdList = psdList->psdNext; | ||
| 301 | |||
| 302 | MemFree(psdDelete); | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | |||
| 307 | // private helper functions | ||
| 308 | |||
| 309 | static HRESULT NewDb( | ||
| 310 | __out SCA_DB** ppsd | ||
| 311 | ) | ||
| 312 | { | ||
| 313 | HRESULT hr = S_OK; | ||
| 314 | SCA_DB* psd = static_cast<SCA_DB*>(MemAlloc(sizeof(SCA_DB), TRUE)); | ||
| 315 | ExitOnNull(psd, hr, E_OUTOFMEMORY, "failed to allocate memory for new database element"); | ||
| 316 | |||
| 317 | *ppsd = psd; | ||
| 318 | |||
| 319 | LExit: | ||
| 320 | return hr; | ||
| 321 | } | ||
| 322 | |||
| 323 | |||
| 324 | static SCA_DB* AddDbToList( | ||
| 325 | __in SCA_DB* psdList, | ||
| 326 | __in SCA_DB* psd | ||
| 327 | ) | ||
| 328 | { | ||
| 329 | if (psdList) | ||
| 330 | { | ||
| 331 | SCA_DB* psdT = psdList; | ||
| 332 | while (psdT->psdNext) | ||
| 333 | { | ||
| 334 | psdT = psdT->psdNext; | ||
| 335 | } | ||
| 336 | |||
| 337 | psdT->psdNext = psd; | ||
| 338 | } | ||
| 339 | else | ||
| 340 | { | ||
| 341 | psdList = psd; | ||
| 342 | } | ||
| 343 | |||
| 344 | return psdList; | ||
| 345 | } | ||
| 346 | |||
| 347 | |||
| 348 | static HRESULT SchedCreateDatabase( | ||
| 349 | __in SCA_DB* psd | ||
| 350 | ) | ||
| 351 | { | ||
| 352 | HRESULT hr = S_OK; | ||
| 353 | WCHAR* pwzCustomActionData = NULL; | ||
| 354 | |||
| 355 | hr = WcaWriteStringToCaData(psd->wzKey, &pwzCustomActionData); | ||
| 356 | ExitOnFailure(hr, "failed to add DBKey to CustomActionData"); | ||
| 357 | |||
| 358 | hr = WcaWriteStringToCaData(psd->wzServer, &pwzCustomActionData); | ||
| 359 | ExitOnFailure(hr, "Failed to add server name to CustomActionData"); | ||
| 360 | |||
| 361 | hr = WcaWriteStringToCaData(psd->wzInstance, &pwzCustomActionData); | ||
| 362 | ExitOnFailure(hr, "Failed to add server instance to CustomActionData"); | ||
| 363 | |||
| 364 | hr = WcaWriteStringToCaData(psd->wzDatabase, &pwzCustomActionData); | ||
| 365 | ExitOnFailure(hr, "Failed to add database name to CustomActionData"); | ||
| 366 | |||
| 367 | hr = WcaWriteIntegerToCaData(psd->iAttributes, &pwzCustomActionData); | ||
| 368 | ExitOnFailure(hr, "Failed to add Sql attributes to CustomActionData"); | ||
| 369 | |||
| 370 | hr = WcaWriteStringToCaData(psd->fUseIntegratedAuth ? L"1" : L"0", &pwzCustomActionData); | ||
| 371 | ExitOnFailure(hr, "Failed to add if integrated connection to CustomActionData"); | ||
| 372 | |||
| 373 | hr = WcaWriteStringToCaData(psd->scau.wzName, &pwzCustomActionData); | ||
| 374 | ExitOnFailure(hr, "Failed to add server user to CustomActionData"); | ||
| 375 | |||
| 376 | hr = WcaWriteStringToCaData(psd->scau.wzPassword, &pwzCustomActionData); | ||
| 377 | ExitOnFailure(hr, "Failed to add user password to CustomActionData"); | ||
| 378 | |||
| 379 | // Check to see if the database exists, if it does not then schedule a rollback | ||
| 380 | // so we clean up after ourselves if the creation of the database fails or is | ||
| 381 | // aborted. It is interesting to note that we can do this check here because the | ||
| 382 | // deferred CustomActions are Impersonated. That means this scheduling action and | ||
| 383 | // the execution actions all run with the same user context, so it is safe to | ||
| 384 | // to do the check. | ||
| 385 | hr = SqlDatabaseExists(psd->wzServer, psd->wzInstance, psd->wzDatabase, psd->fUseIntegratedAuth, psd->scau.wzName, psd->scau.wzPassword, NULL); | ||
| 386 | if (S_FALSE == hr) | ||
| 387 | { | ||
| 388 | hr = WcaDoDeferredAction(L"RollbackCreateDatabase", pwzCustomActionData, COST_SQL_CREATEDB); | ||
| 389 | ExitOnFailure(hr, "Failed to schedule RollbackCreateDatabase action"); | ||
| 390 | } | ||
| 391 | |||
| 392 | // database filespec | ||
| 393 | if (psd->fHasDbSpec) | ||
| 394 | { | ||
| 395 | hr = WcaWriteStringToCaData(L"1", &pwzCustomActionData); | ||
| 396 | ExitOnFailure(hr, "failed to specify that do have db.filespec to CustomActionData"); | ||
| 397 | |||
| 398 | hr = WcaWriteStringToCaData(psd->sfDb.wzName, &pwzCustomActionData); | ||
| 399 | ExitOnFailure(hr, "failed to add FileSpec.Name to CustomActionData"); | ||
| 400 | |||
| 401 | hr = WcaWriteStringToCaData(psd->sfDb.wzFilename, &pwzCustomActionData); | ||
| 402 | ExitOnFailure(hr, "failed to add FileSpec.Filename to CustomActionData"); | ||
| 403 | |||
| 404 | hr = WcaWriteStringToCaData(psd->sfDb.wzSize, &pwzCustomActionData); | ||
| 405 | ExitOnFailure(hr, "Failed to add FileSpec.Size to CustomActionData"); | ||
| 406 | |||
| 407 | hr = WcaWriteStringToCaData(psd->sfDb.wzMaxSize, &pwzCustomActionData); | ||
| 408 | ExitOnFailure(hr, "Failed to add FileSpec.MaxSize to CustomActionData"); | ||
| 409 | |||
| 410 | hr = WcaWriteStringToCaData(psd->sfDb.wzGrow, &pwzCustomActionData); | ||
| 411 | ExitOnFailure(hr, "Failed to add FileSpec.GrowthSize to CustomActionData"); | ||
| 412 | } | ||
| 413 | else | ||
| 414 | { | ||
| 415 | hr = WcaWriteStringToCaData(L"0", &pwzCustomActionData); | ||
| 416 | ExitOnFailure(hr, "failed to specify that do not have db.filespec to CustomActionData"); | ||
| 417 | } | ||
| 418 | |||
| 419 | // log filespec | ||
| 420 | if (psd->fHasLogSpec) | ||
| 421 | { | ||
| 422 | hr = WcaWriteStringToCaData(L"1", &pwzCustomActionData); | ||
| 423 | ExitOnFailure(hr, "failed to specify that do have log.filespec to CustomActionData"); | ||
| 424 | |||
| 425 | hr = WcaWriteStringToCaData(psd->sfLog.wzName, &pwzCustomActionData); | ||
| 426 | ExitOnFailure(hr, "failed to add FileSpec.Name to CustomActionData"); | ||
| 427 | |||
| 428 | hr = WcaWriteStringToCaData(psd->sfLog.wzFilename, &pwzCustomActionData); | ||
| 429 | ExitOnFailure(hr, "failed to add FileSpec.Filename to CustomActionData"); | ||
| 430 | |||
| 431 | hr = WcaWriteStringToCaData(psd->sfLog.wzSize, &pwzCustomActionData); | ||
| 432 | ExitOnFailure(hr, "Failed to add FileSpec.Size to CustomActionData"); | ||
| 433 | |||
| 434 | hr = WcaWriteStringToCaData(psd->sfLog.wzMaxSize, &pwzCustomActionData); | ||
| 435 | ExitOnFailure(hr, "Failed to add FileSpec.MaxSize to CustomActionData"); | ||
| 436 | |||
| 437 | hr = WcaWriteStringToCaData(psd->sfLog.wzGrow, &pwzCustomActionData); | ||
| 438 | ExitOnFailure(hr, "Failed to add FileSpec.GrowthSize to CustomActionData"); | ||
| 439 | } | ||
| 440 | else | ||
| 441 | { | ||
| 442 | hr = WcaWriteStringToCaData(L"0", &pwzCustomActionData); | ||
| 443 | ExitOnFailure(hr, "failed to specify that do not have log.filespec to CustomActionData"); | ||
| 444 | } | ||
| 445 | |||
| 446 | // schedule the CreateDatabase action | ||
| 447 | hr = WcaDoDeferredAction(L"CreateDatabase", pwzCustomActionData, COST_SQL_CREATEDB); | ||
| 448 | ExitOnFailure(hr, "Failed to schedule CreateDatabase action"); | ||
| 449 | |||
| 450 | LExit: | ||
| 451 | ReleaseStr(pwzCustomActionData); | ||
| 452 | return hr; | ||
| 453 | } | ||
| 454 | |||
| 455 | |||
| 456 | HRESULT SchedDropDatabase( | ||
| 457 | __in LPCWSTR wzKey, | ||
| 458 | __in LPCWSTR wzServer, | ||
| 459 | __in LPCWSTR wzInstance, | ||
| 460 | __in LPCWSTR wzDatabase, | ||
| 461 | __in int iAttributes, | ||
| 462 | __in BOOL fIntegratedAuth, | ||
| 463 | __in LPCWSTR wzUser, | ||
| 464 | __in LPCWSTR wzPassword | ||
| 465 | ) | ||
| 466 | { | ||
| 467 | HRESULT hr = S_OK; | ||
| 468 | WCHAR* pwzCustomActionData = NULL; | ||
| 469 | |||
| 470 | hr = WcaWriteStringToCaData(wzKey, &pwzCustomActionData); | ||
| 471 | ExitOnFailure(hr, "failed to add DBKey to CustomActionData"); | ||
| 472 | |||
| 473 | hr = WcaWriteStringToCaData(wzServer, &pwzCustomActionData); | ||
| 474 | ExitOnFailure(hr, "Failed to add server name to CustomActionData"); | ||
| 475 | |||
| 476 | hr = WcaWriteStringToCaData(wzInstance, &pwzCustomActionData); | ||
| 477 | ExitOnFailure(hr, "Failed to add server instance to CustomActionData"); | ||
| 478 | |||
| 479 | hr = WcaWriteStringToCaData(wzDatabase, &pwzCustomActionData); | ||
| 480 | ExitOnFailure(hr, "Failed to add database name to CustomActionData"); | ||
| 481 | |||
| 482 | hr = WcaWriteIntegerToCaData(iAttributes, &pwzCustomActionData); | ||
| 483 | ExitOnFailure(hr, "Failed to add server name to CustomActionData"); | ||
| 484 | |||
| 485 | hr = WcaWriteStringToCaData(fIntegratedAuth ? L"1" : L"0", &pwzCustomActionData); | ||
| 486 | ExitOnFailure(hr, "Failed to add server name to CustomActionData"); | ||
| 487 | |||
| 488 | hr = WcaWriteStringToCaData(wzUser, &pwzCustomActionData); | ||
| 489 | ExitOnFailure(hr, "Failed to add server user to CustomActionData"); | ||
| 490 | |||
| 491 | hr = WcaWriteStringToCaData(wzPassword, &pwzCustomActionData); | ||
| 492 | ExitOnFailure(hr, "Failed to add user password to CustomActionData"); | ||
| 493 | |||
| 494 | hr = WcaDoDeferredAction(L"DropDatabase", pwzCustomActionData, COST_SQL_DROPDB); | ||
| 495 | ExitOnFailure(hr, "Failed to schedule DropDatabase action"); | ||
| 496 | |||
| 497 | LExit: | ||
| 498 | ReleaseStr(pwzCustomActionData); | ||
| 499 | return hr; | ||
| 500 | } | ||
| 501 | |||
| 502 | |||
| 503 | HRESULT GetFileSpec( | ||
| 504 | __in MSIHANDLE hViewFileSpec, | ||
| 505 | __in LPCWSTR wzKey, | ||
| 506 | __in SQL_FILESPEC* psf | ||
| 507 | ) | ||
| 508 | { | ||
| 509 | HRESULT hr = S_OK; | ||
| 510 | PMSIHANDLE hRecFileSpec, hRec; | ||
| 511 | LPWSTR pwzData = NULL; | ||
| 512 | |||
| 513 | // create a record to do the fetch | ||
| 514 | hRecFileSpec = ::MsiCreateRecord(1); | ||
| 515 | if (!hRecFileSpec) | ||
| 516 | { | ||
| 517 | ExitOnFailure(hr = E_UNEXPECTED, "failed to create record for filespec: %ls", wzKey); | ||
| 518 | } | ||
| 519 | hr = WcaSetRecordString(hRecFileSpec, 1, wzKey); | ||
| 520 | ExitOnFailure(hr, "failed to set record string for filespec: %ls", wzKey); | ||
| 521 | |||
| 522 | // get the FileSpec record | ||
| 523 | hr = WcaExecuteView(hViewFileSpec, hRecFileSpec); | ||
| 524 | ExitOnFailure(hr, "failed to execute view on SqlFileSpec table for filespec: %ls", wzKey); | ||
| 525 | hr = WcaFetchSingleRecord(hViewFileSpec, &hRec); | ||
| 526 | ExitOnFailure(hr, "failed to get record for filespec: %ls", wzKey); | ||
| 527 | |||
| 528 | // read the data out of the filespec record | ||
| 529 | hr = WcaGetRecordFormattedString(hRec, sfsqName, &pwzData); | ||
| 530 | ExitOnFailure(hr, "Failed to get SqlFileSpec.Name for filespec: %ls", wzKey); | ||
| 531 | hr = ::StringCchCopyW(psf->wzName, countof(psf->wzName), pwzData); | ||
| 532 | ExitOnFailure(hr, "Failed to copy SqlFileSpec.Name string: %ls", pwzData); | ||
| 533 | |||
| 534 | hr = WcaGetRecordFormattedString(hRec, sfsqFilename, &pwzData); | ||
| 535 | ExitOnFailure(hr, "Failed to get SqlFileSpec.Filename for filespec: %ls", wzKey); | ||
| 536 | if (*pwzData) | ||
| 537 | { | ||
| 538 | hr = ::StringCchCopyW(psf->wzFilename, countof(psf->wzFilename), pwzData); | ||
| 539 | ExitOnFailure(hr, "Failed to copy filename to filespec object: %ls", pwzData); | ||
| 540 | } | ||
| 541 | else // if there is no file, skip this FILESPEC | ||
| 542 | { | ||
| 543 | WcaLog(LOGMSG_VERBOSE, "No filename specified, skipping FileSpec: %ls", psf->wzName); | ||
| 544 | ExitFunction1(hr = S_FALSE); | ||
| 545 | } | ||
| 546 | |||
| 547 | hr = WcaGetRecordFormattedString(hRec, sfsqSize, &pwzData); | ||
| 548 | ExitOnFailure(hr, "Failed to get SqlFileSpec.Size for filespec: %ls", wzKey); | ||
| 549 | if (*pwzData) | ||
| 550 | { | ||
| 551 | hr = ::StringCchCopyW(psf->wzSize, countof(psf->wzSize), pwzData); | ||
| 552 | ExitOnFailure(hr, "Failed to copy size to filespec object: %ls", pwzData); | ||
| 553 | } | ||
| 554 | else | ||
| 555 | { | ||
| 556 | psf->wzSize[0] = 0; | ||
| 557 | } | ||
| 558 | |||
| 559 | hr = WcaGetRecordFormattedString(hRec, sfsqMaxSize, &pwzData); | ||
| 560 | ExitOnFailure(hr, "Failed to get SqlFileSpec.MaxSize for filespec: %ls", wzKey); | ||
| 561 | if (*pwzData) | ||
| 562 | { | ||
| 563 | hr = ::StringCchCopyW(psf->wzMaxSize, countof(psf->wzMaxSize), pwzData); | ||
| 564 | ExitOnFailure(hr, "Failed to copy max size to filespec object: %ls", pwzData); | ||
| 565 | } | ||
| 566 | else | ||
| 567 | { | ||
| 568 | psf->wzMaxSize[0] = 0; | ||
| 569 | } | ||
| 570 | |||
| 571 | hr = WcaGetRecordFormattedString(hRec, sfsqGrowth, &pwzData); | ||
| 572 | ExitOnFailure(hr, "Failed to get SqlFileSpec.GrowthSize for filespec: %ls", wzKey); | ||
| 573 | if (*pwzData) | ||
| 574 | { | ||
| 575 | hr = ::StringCchCopyW(psf->wzGrow, countof(psf->wzGrow), pwzData); | ||
| 576 | ExitOnFailure(hr, "Failed to copy growth size to filespec object: %ls", pwzData); | ||
| 577 | } | ||
| 578 | else | ||
| 579 | { | ||
| 580 | psf->wzGrow[0] = 0; | ||
| 581 | } | ||
| 582 | |||
| 583 | hr = S_OK; | ||
| 584 | LExit: | ||
| 585 | ReleaseStr(pwzData); | ||
| 586 | return hr; | ||
| 587 | } | ||
diff --git a/src/ca/scadb.h b/src/ca/scadb.h new file mode 100644 index 00000000..885e84c2 --- /dev/null +++ b/src/ca/scadb.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scauser.h" | ||
| 6 | #include "sqlutil.h" | ||
| 7 | |||
| 8 | struct SCA_DB | ||
| 9 | { | ||
| 10 | // darwin information | ||
| 11 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 12 | BOOL fHasComponent; | ||
| 13 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 14 | INSTALLSTATE isInstalled, isAction; | ||
| 15 | |||
| 16 | WCHAR wzServer[MAX_DARWIN_COLUMN + 1]; | ||
| 17 | WCHAR wzInstance[MAX_DARWIN_COLUMN + 1]; | ||
| 18 | WCHAR wzDatabase[MAX_DARWIN_COLUMN + 1]; | ||
| 19 | |||
| 20 | int iAttributes; | ||
| 21 | |||
| 22 | BOOL fUseIntegratedAuth; | ||
| 23 | SCA_USER scau; | ||
| 24 | |||
| 25 | BOOL fHasDbSpec; | ||
| 26 | SQL_FILESPEC sfDb; | ||
| 27 | BOOL fHasLogSpec; | ||
| 28 | SQL_FILESPEC sfLog; | ||
| 29 | |||
| 30 | SCA_DB* psdNext; | ||
| 31 | }; | ||
| 32 | |||
| 33 | |||
| 34 | // prototypes | ||
| 35 | HRESULT ScaDbsRead( | ||
| 36 | __inout SCA_DB** ppsdList, | ||
| 37 | __in SCA_ACTION saAction | ||
| 38 | ); | ||
| 39 | |||
| 40 | SCA_DB* ScaDbsFindDatabase( | ||
| 41 | __in LPCWSTR wzSqlDb, | ||
| 42 | __in SCA_DB* psdList | ||
| 43 | ); | ||
| 44 | |||
| 45 | HRESULT ScaDbsInstall( | ||
| 46 | __in SCA_DB* psdList | ||
| 47 | ); | ||
| 48 | |||
| 49 | HRESULT ScaDbsUninstall( | ||
| 50 | __in SCA_DB* psdList | ||
| 51 | ); | ||
| 52 | |||
| 53 | void ScaDbsFreeList( | ||
| 54 | __in SCA_DB* psdList | ||
| 55 | ); | ||
diff --git a/src/ca/scaexec.cpp b/src/ca/scaexec.cpp new file mode 100644 index 00000000..7a30f52a --- /dev/null +++ b/src/ca/scaexec.cpp | |||
| @@ -0,0 +1,393 @@ | |||
| 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 | |||
| 6 | /******************************************************************** | ||
| 7 | * CreateDatabase - CUSTOM ACTION ENTRY POINT for creating databases | ||
| 8 | * | ||
| 9 | * Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword | ||
| 10 | * ****************************************************************/ | ||
| 11 | extern "C" UINT __stdcall CreateDatabase(MSIHANDLE hInstall) | ||
| 12 | { | ||
| 13 | //AssertSz(FALSE, "debug CreateDatabase here"); | ||
| 14 | UINT er = ERROR_SUCCESS; | ||
| 15 | HRESULT hr = S_OK; | ||
| 16 | |||
| 17 | LPWSTR pwzData = NULL; | ||
| 18 | IDBCreateSession* pidbSession = NULL; | ||
| 19 | BSTR bstrErrorDescription = NULL; | ||
| 20 | LPWSTR pwz = NULL; | ||
| 21 | LPWSTR pwzDatabaseKey = NULL; | ||
| 22 | LPWSTR pwzServer = NULL; | ||
| 23 | LPWSTR pwzInstance = NULL; | ||
| 24 | LPWSTR pwzDatabase = NULL; | ||
| 25 | LPWSTR pwzTemp = NULL; | ||
| 26 | int iAttributes; | ||
| 27 | BOOL fIntegratedAuth; | ||
| 28 | LPWSTR pwzUser = NULL; | ||
| 29 | LPWSTR pwzPassword = NULL; | ||
| 30 | BOOL fHaveDbFileSpec = FALSE; | ||
| 31 | SQL_FILESPEC sfDb; | ||
| 32 | BOOL fHaveLogFileSpec = FALSE; | ||
| 33 | SQL_FILESPEC sfLog; | ||
| 34 | BOOL fInitializedCom = FALSE; | ||
| 35 | |||
| 36 | memset(&sfDb, 0, sizeof(sfDb)); | ||
| 37 | memset(&sfLog, 0, sizeof(sfLog)); | ||
| 38 | |||
| 39 | hr = WcaInitialize(hInstall, "CreateDatabase"); | ||
| 40 | ExitOnFailure(hr, "failed to initialize"); | ||
| 41 | |||
| 42 | hr = ::CoInitialize(NULL); | ||
| 43 | ExitOnFailure(hr, "failed to intialize COM"); | ||
| 44 | fInitializedCom = TRUE; | ||
| 45 | |||
| 46 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
| 47 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 48 | |||
| 49 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | ||
| 50 | |||
| 51 | pwz = pwzData; | ||
| 52 | hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey); // SQL Server | ||
| 53 | ExitOnFailure(hr, "failed to read database key from custom action data: %ls", pwz); | ||
| 54 | hr = WcaReadStringFromCaData(&pwz, &pwzServer); // SQL Server | ||
| 55 | ExitOnFailure(hr, "failed to read server from custom action data: %ls", pwz); | ||
| 56 | hr = WcaReadStringFromCaData(&pwz, &pwzInstance); // SQL Server Instance | ||
| 57 | ExitOnFailure(hr, "failed to read server instance from custom action data: %ls", pwz); | ||
| 58 | hr = WcaReadStringFromCaData(&pwz, &pwzDatabase); // SQL Database | ||
| 59 | ExitOnFailure(hr, "failed to read server instance from custom action data: %ls", pwz); | ||
| 60 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | ||
| 61 | ExitOnFailure(hr, "failed to read attributes from custom action data: %ls", pwz); | ||
| 62 | hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fIntegratedAuth)); // Integrated Windows Authentication? | ||
| 63 | ExitOnFailure(hr, "failed to read integrated auth flag from custom action data: %ls", pwz); | ||
| 64 | hr = WcaReadStringFromCaData(&pwz, &pwzUser); // SQL User | ||
| 65 | ExitOnFailure(hr, "failed to read user from custom action data: %ls", pwz); | ||
| 66 | hr = WcaReadStringFromCaData(&pwz, &pwzPassword); // SQL User Password | ||
| 67 | ExitOnFailure(hr, "failed to read user from custom action data: %ls", pwz); | ||
| 68 | |||
| 69 | // db file spec | ||
| 70 | hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fHaveDbFileSpec)); | ||
| 71 | ExitOnFailure(hr, "failed to read db file spec from custom action data: %ls", pwz); | ||
| 72 | |||
| 73 | if (fHaveDbFileSpec) | ||
| 74 | { | ||
| 75 | hr = WcaReadStringFromCaData(&pwz, &pwzTemp); | ||
| 76 | ExitOnFailure(hr, "failed to read db file spec name from custom action data: %ls", pwz); | ||
| 77 | hr = ::StringCchCopyW(sfDb.wzName, countof(sfDb.wzName), pwzTemp); | ||
| 78 | ExitOnFailure(hr, "failed to copy db file spec name: %ls", pwzTemp); | ||
| 79 | |||
| 80 | hr = WcaReadStringFromCaData(&pwz, &pwzTemp); | ||
| 81 | ExitOnFailure(hr, "failed to read db file spec filename from custom action data: %ls", pwz); | ||
| 82 | hr = ::StringCchCopyW(sfDb.wzFilename, countof(sfDb.wzFilename), pwzTemp); | ||
| 83 | ExitOnFailure(hr, "failed to copy db file spec filename: %ls", pwzTemp); | ||
| 84 | |||
| 85 | hr = WcaReadStringFromCaData(&pwz, &pwzTemp); | ||
| 86 | ExitOnFailure(hr, "failed to read db file spec size from custom action data: %ls", pwz); | ||
| 87 | hr = ::StringCchCopyW(sfDb.wzSize, countof(sfDb.wzSize), pwzTemp); | ||
| 88 | ExitOnFailure(hr, "failed to copy db file spec size value: %ls", pwzTemp); | ||
| 89 | |||
| 90 | hr = WcaReadStringFromCaData(&pwz, &pwzTemp); | ||
| 91 | ExitOnFailure(hr, "failed to read db file spec max size from custom action data: %ls", pwz); | ||
| 92 | hr = ::StringCchCopyW(sfDb.wzMaxSize, countof(sfDb.wzMaxSize), pwzTemp); | ||
| 93 | ExitOnFailure(hr, "failed to copy db file spec max size: %ls", pwzTemp); | ||
| 94 | |||
| 95 | hr = WcaReadStringFromCaData(&pwz, &pwzTemp); | ||
| 96 | ExitOnFailure(hr, "failed to read db file spec grow from custom action data: %ls", pwz); | ||
| 97 | hr = ::StringCchCopyW(sfDb.wzGrow, countof(sfDb.wzGrow), pwzTemp); | ||
| 98 | ExitOnFailure(hr, "failed to copy db file spec grow value: %ls", pwzTemp); | ||
| 99 | } | ||
| 100 | |||
| 101 | // log file spec | ||
| 102 | hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fHaveLogFileSpec)); | ||
| 103 | ExitOnFailure(hr, "failed to read log file spec from custom action data: %ls", pwz); | ||
| 104 | if (fHaveLogFileSpec) | ||
| 105 | { | ||
| 106 | hr = WcaReadStringFromCaData(&pwz, &pwzTemp); | ||
| 107 | ExitOnFailure(hr, "failed to read log file spec name from custom action data: %ls", pwz); | ||
| 108 | hr = ::StringCchCopyW(sfLog.wzName, countof(sfDb.wzName), pwzTemp); | ||
| 109 | ExitOnFailure(hr, "failed to copy log file spec name: %ls", pwzTemp); | ||
| 110 | |||
| 111 | hr = WcaReadStringFromCaData(&pwz, &pwzTemp); | ||
| 112 | ExitOnFailure(hr, "failed to read log file spec filename from custom action data: %ls", pwz); | ||
| 113 | hr = ::StringCchCopyW(sfLog.wzFilename, countof(sfDb.wzFilename), pwzTemp); | ||
| 114 | ExitOnFailure(hr, "failed to copy log file spec filename: %ls", pwzTemp); | ||
| 115 | |||
| 116 | hr = WcaReadStringFromCaData(&pwz, &pwzTemp); | ||
| 117 | ExitOnFailure(hr, "failed to read log file spec size from custom action data: %ls", pwz); | ||
| 118 | hr = ::StringCchCopyW(sfLog.wzSize, countof(sfDb.wzSize), pwzTemp); | ||
| 119 | ExitOnFailure(hr, "failed to copy log file spec size value: %ls", pwzTemp); | ||
| 120 | |||
| 121 | hr = WcaReadStringFromCaData(&pwz, &pwzTemp); | ||
| 122 | ExitOnFailure(hr, "failed to read log file spec max size from custom action data: %ls", pwz); | ||
| 123 | hr = ::StringCchCopyW(sfLog.wzMaxSize, countof(sfDb.wzMaxSize), pwzTemp); | ||
| 124 | ExitOnFailure(hr, "failed to copy log file spec max size: %ls", pwzTemp); | ||
| 125 | |||
| 126 | hr = WcaReadStringFromCaData(&pwz, &pwzTemp); | ||
| 127 | ExitOnFailure(hr, "failed to read log file spec grow from custom action data: %ls", pwz); | ||
| 128 | hr = ::StringCchCopyW(sfLog.wzGrow, countof(sfDb.wzGrow), pwzTemp); | ||
| 129 | ExitOnFailure(hr, "failed to copy log file spec grow value: %ls", pwzTemp); | ||
| 130 | } | ||
| 131 | |||
| 132 | if (iAttributes & SCADB_CONFIRM_OVERWRITE) | ||
| 133 | { | ||
| 134 | // Check if the database already exists | ||
| 135 | hr = SqlDatabaseExists(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &bstrErrorDescription); | ||
| 136 | MessageExitOnFailure(hr, msierrSQLFailedCreateDatabase, "failed to check if database exists: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription); | ||
| 137 | |||
| 138 | if (S_OK == hr) // found an existing database, confirm that they don't want to stop before it gets trampled, in no UI case just continue anyways | ||
| 139 | { | ||
| 140 | hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); | ||
| 141 | if (IDNO == WcaErrorMessage(msierrSQLDatabaseAlreadyExists, hr, MB_YESNO, 1, pwzDatabase)) | ||
| 142 | ExitOnFailure(hr, "failed to initialize"); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | hr = SqlDatabaseEnsureExists(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, fHaveDbFileSpec ? &sfDb : NULL, fHaveLogFileSpec ? &sfLog : NULL, &bstrErrorDescription); | ||
| 147 | if ((iAttributes & SCADB_CONTINUE_ON_ERROR) && FAILED(hr)) | ||
| 148 | { | ||
| 149 | WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to create SQL database but continuing, error: %ls, Database: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzDatabase); | ||
| 150 | hr = S_OK; | ||
| 151 | } | ||
| 152 | MessageExitOnFailure(hr, msierrSQLFailedCreateDatabase, "failed to create to database: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription); | ||
| 153 | |||
| 154 | hr = WcaProgressMessage(COST_SQL_CONNECTDB, FALSE); | ||
| 155 | LExit: | ||
| 156 | ReleaseStr(pwzDatabaseKey); | ||
| 157 | ReleaseStr(pwzServer); | ||
| 158 | ReleaseStr(pwzInstance); | ||
| 159 | ReleaseStr(pwzDatabase); | ||
| 160 | ReleaseStr(pwzUser); | ||
| 161 | ReleaseStr(pwzPassword); | ||
| 162 | ReleaseObject(pidbSession); | ||
| 163 | ReleaseBSTR(bstrErrorDescription); | ||
| 164 | |||
| 165 | if (fInitializedCom) | ||
| 166 | { | ||
| 167 | ::CoUninitialize(); | ||
| 168 | } | ||
| 169 | |||
| 170 | if (FAILED(hr)) | ||
| 171 | { | ||
| 172 | er = ERROR_INSTALL_FAILURE; | ||
| 173 | } | ||
| 174 | return WcaFinalize(er); | ||
| 175 | } | ||
| 176 | |||
| 177 | |||
| 178 | /******************************************************************** | ||
| 179 | DropDatabase - CUSTOM ACTION ENTRY POINT for removing databases | ||
| 180 | |||
| 181 | Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword | ||
| 182 | * ****************************************************************/ | ||
| 183 | extern "C" UINT __stdcall DropDatabase(MSIHANDLE hInstall) | ||
| 184 | { | ||
| 185 | //Assert(FALSE); | ||
| 186 | UINT er = ERROR_SUCCESS; | ||
| 187 | HRESULT hr = S_OK; | ||
| 188 | |||
| 189 | LPWSTR pwzData = NULL; | ||
| 190 | IDBCreateSession* pidbSession = NULL; | ||
| 191 | BSTR bstrErrorDescription = NULL; | ||
| 192 | LPWSTR pwz = NULL; | ||
| 193 | LPWSTR pwzDatabaseKey = NULL; | ||
| 194 | LPWSTR pwzServer = NULL; | ||
| 195 | LPWSTR pwzInstance = NULL; | ||
| 196 | LPWSTR pwzDatabase = NULL; | ||
| 197 | long lAttributes; | ||
| 198 | BOOL fIntegratedAuth; | ||
| 199 | LPWSTR pwzUser = NULL; | ||
| 200 | LPWSTR pwzPassword = NULL; | ||
| 201 | BOOL fInitializedCom = TRUE; | ||
| 202 | |||
| 203 | hr = WcaInitialize(hInstall, "DropDatabase"); | ||
| 204 | ExitOnFailure(hr, "failed to initialize"); | ||
| 205 | |||
| 206 | hr = ::CoInitialize(NULL); | ||
| 207 | ExitOnFailure(hr, "failed to intialize COM"); | ||
| 208 | fInitializedCom = TRUE; | ||
| 209 | |||
| 210 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
| 211 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 212 | |||
| 213 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | ||
| 214 | |||
| 215 | pwz = pwzData; | ||
| 216 | hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey); | ||
| 217 | ExitOnFailure(hr, "failed to read database key"); | ||
| 218 | hr = WcaReadStringFromCaData(&pwz, &pwzServer); | ||
| 219 | ExitOnFailure(hr, "failed to read server"); | ||
| 220 | hr = WcaReadStringFromCaData(&pwz, &pwzInstance); | ||
| 221 | ExitOnFailure(hr, "failed to read instance"); | ||
| 222 | hr = WcaReadStringFromCaData(&pwz, &pwzDatabase); | ||
| 223 | ExitOnFailure(hr, "failed to read database"); | ||
| 224 | hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&lAttributes)); | ||
| 225 | ExitOnFailure(hr, "failed to read attributes"); | ||
| 226 | hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fIntegratedAuth)); // Integrated Windows Authentication? | ||
| 227 | ExitOnFailure(hr, "failed to read integrated auth flag"); | ||
| 228 | hr = WcaReadStringFromCaData(&pwz, &pwzUser); | ||
| 229 | ExitOnFailure(hr, "failed to read user"); | ||
| 230 | hr = WcaReadStringFromCaData(&pwz, &pwzPassword); | ||
| 231 | ExitOnFailure(hr, "failed to read password"); | ||
| 232 | |||
| 233 | hr = SqlDropDatabase(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &bstrErrorDescription); | ||
| 234 | if ((lAttributes & SCADB_CONTINUE_ON_ERROR) && FAILED(hr)) | ||
| 235 | { | ||
| 236 | WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to drop SQL database but continuing, error: %ls, Database: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzDatabase); | ||
| 237 | hr = S_OK; | ||
| 238 | } | ||
| 239 | MessageExitOnFailure(hr, msierrSQLFailedDropDatabase, "failed to drop to database: '%ls', error: %ls", pwzDatabase, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription); | ||
| 240 | |||
| 241 | hr = WcaProgressMessage(COST_SQL_CONNECTDB, FALSE); | ||
| 242 | |||
| 243 | LExit: | ||
| 244 | ReleaseStr(pwzDatabaseKey); | ||
| 245 | ReleaseStr(pwzServer); | ||
| 246 | ReleaseStr(pwzInstance); | ||
| 247 | ReleaseStr(pwzDatabase); | ||
| 248 | ReleaseStr(pwzUser); | ||
| 249 | ReleaseStr(pwzPassword); | ||
| 250 | ReleaseStr(pwzData); | ||
| 251 | ReleaseObject(pidbSession); | ||
| 252 | ReleaseBSTR(bstrErrorDescription); | ||
| 253 | |||
| 254 | if (fInitializedCom) | ||
| 255 | { | ||
| 256 | ::CoUninitialize(); | ||
| 257 | } | ||
| 258 | |||
| 259 | if (FAILED(hr)) | ||
| 260 | { | ||
| 261 | er = ERROR_INSTALL_FAILURE; | ||
| 262 | } | ||
| 263 | return WcaFinalize(er); | ||
| 264 | } | ||
| 265 | |||
| 266 | |||
| 267 | /******************************************************************** | ||
| 268 | ExecuteSqlStrings - CUSTOM ACTION ENTRY POINT for running SQL strings | ||
| 269 | |||
| 270 | Input: deferred CustomActionData - DbKey\tServer\tInstance\tDatabase\tAttributes\tIntegratedAuth\tUser\tPassword\tSQLKey1\tSQLString1\tSQLKey2\tSQLString2\tSQLKey3\tSQLString3\t... | ||
| 271 | rollback CustomActionData - same as above | ||
| 272 | * ****************************************************************/ | ||
| 273 | extern "C" UINT __stdcall ExecuteSqlStrings(MSIHANDLE hInstall) | ||
| 274 | { | ||
| 275 | //Assert(FALSE); | ||
| 276 | UINT er = ERROR_SUCCESS; | ||
| 277 | HRESULT hr = S_OK; | ||
| 278 | HRESULT hrDB = S_OK; | ||
| 279 | |||
| 280 | LPWSTR pwzData = NULL; | ||
| 281 | IDBCreateSession* pidbSession = NULL; | ||
| 282 | BSTR bstrErrorDescription = NULL; | ||
| 283 | |||
| 284 | LPWSTR pwz = NULL; | ||
| 285 | LPWSTR pwzDatabaseKey = NULL; | ||
| 286 | LPWSTR pwzServer = NULL; | ||
| 287 | LPWSTR pwzInstance = NULL; | ||
| 288 | LPWSTR pwzDatabase = NULL; | ||
| 289 | int iAttributesDB; | ||
| 290 | int iAttributesSQL; | ||
| 291 | BOOL fIntegratedAuth; | ||
| 292 | LPWSTR pwzUser = NULL; | ||
| 293 | LPWSTR pwzPassword = NULL; | ||
| 294 | LPWSTR pwzSqlKey = NULL; | ||
| 295 | LPWSTR pwzSql = NULL; | ||
| 296 | BOOL fInitializedCom = FALSE; | ||
| 297 | |||
| 298 | hr = WcaInitialize(hInstall, "ExecuteSqlStrings"); | ||
| 299 | ExitOnFailure(hr, "failed to initialize"); | ||
| 300 | |||
| 301 | hr = ::CoInitialize(NULL); | ||
| 302 | ExitOnFailure(hr, "failed to intialize COM"); | ||
| 303 | fInitializedCom = TRUE; | ||
| 304 | |||
| 305 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | ||
| 306 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 307 | |||
| 308 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | ||
| 309 | |||
| 310 | pwz = pwzData; | ||
| 311 | hr = WcaReadStringFromCaData(&pwz, &pwzDatabaseKey); | ||
| 312 | ExitOnFailure(hr, "failed to read database key"); | ||
| 313 | hr = WcaReadStringFromCaData(&pwz, &pwzServer); | ||
| 314 | ExitOnFailure(hr, "failed to read server"); | ||
| 315 | hr = WcaReadStringFromCaData(&pwz, &pwzInstance); | ||
| 316 | ExitOnFailure(hr, "failed to read instance"); | ||
| 317 | hr = WcaReadStringFromCaData(&pwz, &pwzDatabase); | ||
| 318 | ExitOnFailure(hr, "failed to read database"); | ||
| 319 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributesDB); | ||
| 320 | ExitOnFailure(hr, "failed to read attributes"); | ||
| 321 | hr = WcaReadIntegerFromCaData(&pwz, reinterpret_cast<int *>(&fIntegratedAuth)); // Integrated Windows Authentication? | ||
| 322 | ExitOnFailure(hr, "failed to read integrated auth flag"); | ||
| 323 | hr = WcaReadStringFromCaData(&pwz, &pwzUser); | ||
| 324 | ExitOnFailure(hr, "failed to read user"); | ||
| 325 | hr = WcaReadStringFromCaData(&pwz, &pwzPassword); | ||
| 326 | ExitOnFailure(hr, "failed to read password"); | ||
| 327 | |||
| 328 | // Store off the result of the connect, only exit if we don't care if the database connection succeeds | ||
| 329 | // Wait to fail until later to see if we actually have work to do that is not set to continue on error | ||
| 330 | hrDB = SqlConnectDatabase(pwzServer, pwzInstance, pwzDatabase, fIntegratedAuth, pwzUser, pwzPassword, &pidbSession); | ||
| 331 | if ((iAttributesDB & SCADB_CONTINUE_ON_ERROR) && FAILED(hrDB)) | ||
| 332 | { | ||
| 333 | WcaLog(LOGMSG_STANDARD, "Error 0x%x: continuing after failure to connect to database: %ls", hrDB, pwzDatabase); | ||
| 334 | ExitFunction1(hr = S_OK); | ||
| 335 | } | ||
| 336 | |||
| 337 | while (S_OK == hr && S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzSqlKey))) | ||
| 338 | { | ||
| 339 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributesSQL); | ||
| 340 | ExitOnFailure(hr, "failed to read attributes for SQL string: %ls", pwzSqlKey); | ||
| 341 | |||
| 342 | hr = WcaReadStringFromCaData(&pwz, &pwzSql); | ||
| 343 | ExitOnFailure(hr, "failed to read SQL string for key: %ls", pwzSqlKey); | ||
| 344 | |||
| 345 | // If the SqlString row is set to continue on error and the DB connection failed, skip attempting to execute | ||
| 346 | if ((iAttributesSQL & SCASQL_CONTINUE_ON_ERROR) && FAILED(hrDB)) | ||
| 347 | { | ||
| 348 | WcaLog(LOGMSG_STANDARD, "Error 0x%x: continuing after failure to connect to database: %ls", hrDB, pwzDatabase); | ||
| 349 | continue; | ||
| 350 | } | ||
| 351 | |||
| 352 | // Now check if the DB connection succeeded | ||
| 353 | MessageExitOnFailure(hr = hrDB, msierrSQLFailedConnectDatabase, "failed to connect to database: '%ls'", pwzDatabase); | ||
| 354 | |||
| 355 | WcaLog(LOGMSG_VERBOSE, "Executing SQL string: %ls", pwzSql); | ||
| 356 | hr = SqlSessionExecuteQuery(pidbSession, pwzSql, NULL, NULL, &bstrErrorDescription); | ||
| 357 | if ((iAttributesSQL & SCASQL_CONTINUE_ON_ERROR) && FAILED(hr)) | ||
| 358 | { | ||
| 359 | WcaLog(LOGMSG_STANDARD, "Error 0x%x: failed to execute SQL string but continuing, error: %ls, SQL key: %ls SQL string: %ls", hr, NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzSqlKey, pwzSql); | ||
| 360 | hr = S_OK; | ||
| 361 | } | ||
| 362 | MessageExitOnFailure(hr, msierrSQLFailedExecString, "failed to execute SQL string, error: %ls, SQL key: %ls SQL string: %ls", NULL == bstrErrorDescription ? L"unknown error" : bstrErrorDescription, pwzSqlKey, pwzSql); | ||
| 363 | |||
| 364 | WcaProgressMessage(COST_SQL_STRING, FALSE); | ||
| 365 | } | ||
| 366 | if (E_NOMOREITEMS == hr) | ||
| 367 | { | ||
| 368 | hr = S_OK; | ||
| 369 | } | ||
| 370 | |||
| 371 | LExit: | ||
| 372 | ReleaseStr(pwzDatabaseKey); | ||
| 373 | ReleaseStr(pwzServer); | ||
| 374 | ReleaseStr(pwzInstance); | ||
| 375 | ReleaseStr(pwzDatabase); | ||
| 376 | ReleaseStr(pwzUser); | ||
| 377 | ReleaseStr(pwzPassword); | ||
| 378 | ReleaseStr(pwzData); | ||
| 379 | |||
| 380 | ReleaseBSTR(bstrErrorDescription); | ||
| 381 | ReleaseObject(pidbSession); | ||
| 382 | |||
| 383 | if (fInitializedCom) | ||
| 384 | { | ||
| 385 | ::CoUninitialize(); | ||
| 386 | } | ||
| 387 | |||
| 388 | if (FAILED(hr)) | ||
| 389 | { | ||
| 390 | er = ERROR_INSTALL_FAILURE; | ||
| 391 | } | ||
| 392 | return WcaFinalize(er); | ||
| 393 | } | ||
diff --git a/src/ca/scasql.cpp b/src/ca/scasql.cpp new file mode 100644 index 00000000..5e3edd1c --- /dev/null +++ b/src/ca/scasql.cpp | |||
| @@ -0,0 +1,113 @@ | |||
| 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 ConfigureSqlData( | ||
| 7 | __in SCA_ACTION saAction | ||
| 8 | ); | ||
| 9 | |||
| 10 | |||
| 11 | /******************************************************************** | ||
| 12 | InstallSqlData - CUSTOM ACTION ENTRY POINT for installing | ||
| 13 | SQL data | ||
| 14 | |||
| 15 | ********************************************************************/ | ||
| 16 | extern "C" UINT __stdcall InstallSqlData( | ||
| 17 | __in MSIHANDLE hInstall | ||
| 18 | ) | ||
| 19 | { | ||
| 20 | HRESULT hr = S_OK; | ||
| 21 | UINT er = ERROR_SUCCESS; | ||
| 22 | |||
| 23 | // initialize | ||
| 24 | hr = WcaInitialize(hInstall, "InstallSqlData"); | ||
| 25 | ExitOnFailure(hr, "Failed to initialize"); | ||
| 26 | |||
| 27 | hr = ConfigureSqlData(SCA_ACTION_INSTALL); | ||
| 28 | |||
| 29 | LExit: | ||
| 30 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 31 | return WcaFinalize(er); | ||
| 32 | } | ||
| 33 | |||
| 34 | |||
| 35 | /******************************************************************** | ||
| 36 | UninstallSqlData - CUSTOM ACTION ENTRY POINT for uninstalling | ||
| 37 | SQL data | ||
| 38 | |||
| 39 | ********************************************************************/ | ||
| 40 | extern "C" UINT __stdcall UninstallSqlData( | ||
| 41 | __in MSIHANDLE hInstall | ||
| 42 | ) | ||
| 43 | { | ||
| 44 | HRESULT hr = S_OK; | ||
| 45 | UINT er = ERROR_SUCCESS; | ||
| 46 | |||
| 47 | // initialize | ||
| 48 | hr = WcaInitialize(hInstall, "UninstallCertificates"); | ||
| 49 | ExitOnFailure(hr, "Failed to initialize"); | ||
| 50 | |||
| 51 | hr = ConfigureSqlData(SCA_ACTION_UNINSTALL); | ||
| 52 | |||
| 53 | LExit: | ||
| 54 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 55 | return WcaFinalize(er); | ||
| 56 | } | ||
| 57 | |||
| 58 | |||
| 59 | static HRESULT ConfigureSqlData( | ||
| 60 | __in SCA_ACTION saAction | ||
| 61 | ) | ||
| 62 | { | ||
| 63 | //AssertSz(FALSE, "debug ConfigureSqlData()"); | ||
| 64 | HRESULT hr = S_OK; | ||
| 65 | |||
| 66 | SCA_DB* psdList = NULL; | ||
| 67 | SCA_SQLSTR* psssList = NULL; | ||
| 68 | |||
| 69 | // check for the prerequsite tables | ||
| 70 | if (S_OK != WcaTableExists(L"SqlDatabase")) | ||
| 71 | { | ||
| 72 | WcaLog(LOGMSG_VERBOSE, "skipping SQL CustomAction, no SqlDatabase table"); | ||
| 73 | ExitFunction1(hr = S_FALSE); | ||
| 74 | } | ||
| 75 | |||
| 76 | // read tables | ||
| 77 | hr = ScaDbsRead(&psdList, saAction); | ||
| 78 | ExitOnFailure(hr, "failed to read SqlDatabase table"); | ||
| 79 | |||
| 80 | hr = ScaSqlStrsRead(&psssList, saAction); | ||
| 81 | ExitOnFailure(hr, "failed to read SqlStrings table"); | ||
| 82 | |||
| 83 | hr = ScaSqlStrsReadScripts(&psssList, saAction); | ||
| 84 | ExitOnFailure(hr, "failed to read SqlScripts table"); | ||
| 85 | |||
| 86 | if (SCA_ACTION_UNINSTALL == saAction) | ||
| 87 | { | ||
| 88 | // do uninstall actions (order is important!) | ||
| 89 | hr = ScaSqlStrsUninstall(psdList, psssList); | ||
| 90 | ExitOnFailure(hr, "failed to execute uninstall SQL strings"); | ||
| 91 | |||
| 92 | hr = ScaDbsUninstall(psdList); | ||
| 93 | ExitOnFailure(hr, "failed to uninstall databases"); | ||
| 94 | } | ||
| 95 | else | ||
| 96 | { | ||
| 97 | // do install actions (order is important!) | ||
| 98 | hr = ScaDbsInstall(psdList); | ||
| 99 | ExitOnFailure(hr, "failed to install databases"); | ||
| 100 | |||
| 101 | hr = ScaSqlStrsInstall(psdList, psssList); | ||
| 102 | ExitOnFailure(hr, "failed to execute install SQL strings, length may be too long, try add GO to break up"); | ||
| 103 | } | ||
| 104 | |||
| 105 | LExit: | ||
| 106 | if (psssList) | ||
| 107 | ScaSqlStrsFreeList(psssList); | ||
| 108 | |||
| 109 | if (psdList) | ||
| 110 | ScaDbsFreeList(psdList); | ||
| 111 | |||
| 112 | return hr; | ||
| 113 | } | ||
diff --git a/src/ca/scasqlstr.cpp b/src/ca/scasqlstr.cpp new file mode 100644 index 00000000..3108e307 --- /dev/null +++ b/src/ca/scasqlstr.cpp | |||
| @@ -0,0 +1,728 @@ | |||
| 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 | // sql queries | ||
| 6 | LPCWSTR vcsSqlStringQuery = L"SELECT `String`, `SqlDb_`, `Component_`,`SQL`,`User_`,`Attributes`,`Sequence` " | ||
| 7 | L"FROM `SqlString` ORDER BY `SqlDb_`,`Sequence`"; | ||
| 8 | enum eSqlStringQuery { ssqSqlString = 1, ssqSqlDb, ssqComponent, ssqSQL, ssqUser, ssqAttributes, ssqSequence }; | ||
| 9 | |||
| 10 | LPCWSTR vcsSqlScriptQuery = L"SELECT `ScriptBinary_`,`Script`, `SqlDb_`, `Component_`,`User_`,`Attributes`,`Sequence` " | ||
| 11 | L"FROM `SqlScript` ORDER BY `SqlDb_`,`Sequence`"; | ||
| 12 | enum eSqlScriptQuery { sscrqScriptBinary=1, sscrqSqlScript, sscrqSqlDb, sscrqComponent, sscrqUser, sscrqAttributes, sscrqSequence }; | ||
| 13 | |||
| 14 | LPCWSTR vcsSqlBinaryScriptQuery = L"SELECT `Data` FROM `Binary` WHERE `Name`=?"; | ||
| 15 | enum eSqlBinaryScriptQuery { ssbsqData = 1 }; | ||
| 16 | |||
| 17 | |||
| 18 | // prototypes for private helper functions | ||
| 19 | static HRESULT NewSqlStr( | ||
| 20 | __out SCA_SQLSTR** ppsss | ||
| 21 | ); | ||
| 22 | static SCA_SQLSTR* AddSqlStrToList( | ||
| 23 | __in SCA_SQLSTR* psssList, | ||
| 24 | __in SCA_SQLSTR* psss | ||
| 25 | ); | ||
| 26 | static HRESULT ExecuteStrings( | ||
| 27 | __in SCA_DB* psdList, | ||
| 28 | __in SCA_SQLSTR* psssList, | ||
| 29 | __in BOOL fInstall | ||
| 30 | ); | ||
| 31 | |||
| 32 | HRESULT ScaSqlStrsRead( | ||
| 33 | __inout SCA_SQLSTR** ppsssList, | ||
| 34 | __in SCA_ACTION saAction | ||
| 35 | ) | ||
| 36 | { | ||
| 37 | HRESULT hr = S_OK; | ||
| 38 | UINT er = ERROR_SUCCESS; | ||
| 39 | PMSIHANDLE hView, hRec; | ||
| 40 | PMSIHANDLE hViewUser, hRecUser; | ||
| 41 | |||
| 42 | LPWSTR pwzComponent = NULL; | ||
| 43 | LPWSTR pwzData = NULL; | ||
| 44 | |||
| 45 | SCA_SQLSTR* psss = NULL; | ||
| 46 | |||
| 47 | if (S_OK != WcaTableExists(L"SqlString") || S_OK != WcaTableExists(L"SqlDatabase")) | ||
| 48 | { | ||
| 49 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaSqlStrsRead() - SqlString and/or SqlDatabase table not present"); | ||
| 50 | ExitFunction1(hr = S_FALSE); | ||
| 51 | } | ||
| 52 | |||
| 53 | // loop through all the sql strings | ||
| 54 | hr = WcaOpenExecuteView(vcsSqlStringQuery, &hView); | ||
| 55 | ExitOnFailure(hr, "Failed to open view on SqlString table"); | ||
| 56 | while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) | ||
| 57 | { | ||
| 58 | INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; | ||
| 59 | INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; | ||
| 60 | |||
| 61 | hr = WcaGetRecordString(hRec, ssqComponent, &pwzComponent); | ||
| 62 | ExitOnFailure(hr, "Failed to get Component for SQL String."); | ||
| 63 | |||
| 64 | er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction); | ||
| 65 | hr = HRESULT_FROM_WIN32(er); | ||
| 66 | ExitOnFailure(hr, "Failed to get state for component: %ls", pwzComponent); | ||
| 67 | |||
| 68 | // If we're doing install but the Component is not being installed or we're doing | ||
| 69 | // uninstall but the Component is not being uninstalled, skip it. | ||
| 70 | if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) || | ||
| 71 | (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction)) | ||
| 72 | { | ||
| 73 | continue; | ||
| 74 | } | ||
| 75 | |||
| 76 | hr = NewSqlStr(&psss); | ||
| 77 | ExitOnFailure(hr, "failed to allocation new sql string element"); | ||
| 78 | |||
| 79 | psss->isInstalled = isInstalled; | ||
| 80 | psss->isAction = isAction; | ||
| 81 | |||
| 82 | hr = WcaGetRecordString(hRec, ssqSqlString, &pwzData); | ||
| 83 | ExitOnFailure(hr, "Failed to get SqlString.String"); | ||
| 84 | hr = ::StringCchCopyW(psss->wzKey, countof(psss->wzKey), pwzData); | ||
| 85 | ExitOnFailure(hr, "Failed to copy SqlString.String: %ls", pwzData); | ||
| 86 | |||
| 87 | // find the database information for this string | ||
| 88 | hr = WcaGetRecordString(hRec, ssqSqlDb, &pwzData); | ||
| 89 | ExitOnFailure(hr, "Failed to get SqlString.SqlDb_ for SqlString '%ls'", psss->wzKey); | ||
| 90 | hr = ::StringCchCopyW(psss->wzSqlDb, countof(psss->wzSqlDb), pwzData); | ||
| 91 | ExitOnFailure(hr, "Failed to copy SqlString.SqlDb_: %ls", pwzData); | ||
| 92 | |||
| 93 | hr = WcaGetRecordInteger(hRec, ssqAttributes, &psss->iAttributes); | ||
| 94 | ExitOnFailure(hr, "Failed to get SqlString.Attributes for SqlString '%ls'", psss->wzKey); | ||
| 95 | |||
| 96 | //get the sequence number for the string (note that this will be sequenced with scripts too) | ||
| 97 | hr = WcaGetRecordInteger(hRec, ssqSequence, &psss->iSequence); | ||
| 98 | ExitOnFailure(hr, "Failed to get SqlString.Sequence for SqlString '%ls'", psss->wzKey); | ||
| 99 | |||
| 100 | // execute SQL | ||
| 101 | hr = WcaGetRecordFormattedString(hRec, ssqSQL, &pwzData); | ||
| 102 | ExitOnFailure(hr, "Failed to get SqlString.SQL for SqlString '%ls'", psss->wzKey); | ||
| 103 | |||
| 104 | Assert(!psss->pwzSql); | ||
| 105 | hr = StrAllocString(&psss->pwzSql, pwzData, 0); | ||
| 106 | ExitOnFailure(hr, "Failed to alloc string for SqlString '%ls'", psss->wzKey); | ||
| 107 | |||
| 108 | *ppsssList = AddSqlStrToList(*ppsssList, psss); | ||
| 109 | psss = NULL; // set the sss to NULL so it doesn't get freed below | ||
| 110 | } | ||
| 111 | |||
| 112 | if (E_NOMOREITEMS == hr) | ||
| 113 | { | ||
| 114 | hr = S_OK; | ||
| 115 | } | ||
| 116 | ExitOnFailure(hr, "Failure occured while reading SqlString table"); | ||
| 117 | |||
| 118 | LExit: | ||
| 119 | // if anything was left over after an error clean it all up | ||
| 120 | if (psss) | ||
| 121 | { | ||
| 122 | ScaSqlStrsFreeList(psss); | ||
| 123 | } | ||
| 124 | |||
| 125 | ReleaseStr(pwzData); | ||
| 126 | ReleaseStr(pwzComponent); | ||
| 127 | |||
| 128 | return hr; | ||
| 129 | } | ||
| 130 | |||
| 131 | |||
| 132 | HRESULT ScaSqlStrsReadScripts( | ||
| 133 | __inout SCA_SQLSTR** ppsssList, | ||
| 134 | __in SCA_ACTION saAction | ||
| 135 | ) | ||
| 136 | { | ||
| 137 | HRESULT hr = S_OK; | ||
| 138 | UINT er = ERROR_SUCCESS; | ||
| 139 | |||
| 140 | PMSIHANDLE hView, hRec; | ||
| 141 | PMSIHANDLE hViewBinary, hRecBinary; | ||
| 142 | PMSIHANDLE hViewUser, hRecUser; | ||
| 143 | |||
| 144 | LPWSTR pwzComponent = NULL; | ||
| 145 | LPWSTR pwzData = NULL; | ||
| 146 | |||
| 147 | BYTE* pbScript = NULL; | ||
| 148 | DWORD cbRead = 0; | ||
| 149 | DWORD cbScript = 0; | ||
| 150 | DWORD cchScript = 0; | ||
| 151 | |||
| 152 | LPWSTR pwzScriptBuffer = NULL; | ||
| 153 | WCHAR* pwzScript = NULL; | ||
| 154 | WCHAR* pwz; | ||
| 155 | DWORD cch = 0; | ||
| 156 | |||
| 157 | SCA_SQLSTR sss; | ||
| 158 | SCA_SQLSTR* psss = NULL; | ||
| 159 | |||
| 160 | if (S_OK != WcaTableExists(L"SqlScript") || S_OK != WcaTableExists(L"SqlDatabase") || S_OK != WcaTableExists(L"Binary")) | ||
| 161 | { | ||
| 162 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaSqlStrsReadScripts() - SqlScripts and/or SqlDatabase table not present"); | ||
| 163 | ExitFunction1(hr = S_FALSE); | ||
| 164 | } | ||
| 165 | |||
| 166 | // open a view on the binary table | ||
| 167 | hr = WcaOpenView(vcsSqlBinaryScriptQuery, &hViewBinary); | ||
| 168 | ExitOnFailure(hr, "Failed to open view on Binary table for SqlScripts"); | ||
| 169 | |||
| 170 | // loop through all the sql scripts | ||
| 171 | hr = WcaOpenExecuteView(vcsSqlScriptQuery, &hView); | ||
| 172 | ExitOnFailure(hr, "Failed to open view on SqlScript table"); | ||
| 173 | while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) | ||
| 174 | { | ||
| 175 | INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; | ||
| 176 | INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; | ||
| 177 | |||
| 178 | hr = WcaGetRecordString(hRec, sscrqComponent, &pwzComponent); | ||
| 179 | ExitOnFailure(hr, "Failed to get Component for SQL Script."); | ||
| 180 | |||
| 181 | er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzComponent, &isInstalled, &isAction); | ||
| 182 | hr = HRESULT_FROM_WIN32(er); | ||
| 183 | ExitOnFailure(hr, "Failed to get state for component: %ls", pwzComponent); | ||
| 184 | |||
| 185 | // If we're doing install but the Component is not being installed or we're doing | ||
| 186 | // uninstall but the Component is not being uninstalled, skip it. | ||
| 187 | if ((WcaIsInstalling(isInstalled, isAction) && SCA_ACTION_INSTALL != saAction) || | ||
| 188 | (WcaIsUninstalling(isInstalled, isAction) && SCA_ACTION_UNINSTALL != saAction)) | ||
| 189 | { | ||
| 190 | continue; | ||
| 191 | } | ||
| 192 | |||
| 193 | ::ZeroMemory(&sss, sizeof(sss)); | ||
| 194 | |||
| 195 | sss.isInstalled = isInstalled; | ||
| 196 | sss.isAction = isAction; | ||
| 197 | |||
| 198 | hr = WcaGetRecordString(hRec, sscrqSqlScript, &pwzData); | ||
| 199 | ExitOnFailure(hr, "Failed to get SqlScript.Script"); | ||
| 200 | hr = ::StringCchCopyW(sss.wzKey, countof(sss.wzKey), pwzData); | ||
| 201 | ExitOnFailure(hr, "Failed to copy SqlScript.Script: %ls", pwzData); | ||
| 202 | |||
| 203 | // find the database information for this string | ||
| 204 | hr = WcaGetRecordString(hRec, sscrqSqlDb, &pwzData); | ||
| 205 | ExitOnFailure(hr, "Failed to get SqlScript.SqlDb_ for SqlScript '%ls'", sss.wzKey); | ||
| 206 | hr = ::StringCchCopyW(sss.wzSqlDb, countof(sss.wzSqlDb), pwzData); | ||
| 207 | ExitOnFailure(hr, "Failed to copy SqlScritp.SqlDbb: %ls", pwzData); | ||
| 208 | |||
| 209 | hr = WcaGetRecordInteger(hRec, sscrqAttributes, &sss.iAttributes); | ||
| 210 | ExitOnFailure(hr, "Failed to get SqlScript.Attributes for SqlScript '%ls'", sss.wzKey); | ||
| 211 | |||
| 212 | hr = WcaGetRecordInteger(hRec, sscrqSequence, &sss.iSequence); | ||
| 213 | ExitOnFailure(hr, "Failed to get SqlScript.Sequence for SqlScript '%ls'", sss.wzKey); | ||
| 214 | |||
| 215 | // get the sql script out of the binary stream | ||
| 216 | hr = WcaExecuteView(hViewBinary, hRec); | ||
| 217 | ExitOnFailure(hr, "Failed to open SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey); | ||
| 218 | hr = WcaFetchSingleRecord(hViewBinary, &hRecBinary); | ||
| 219 | ExitOnFailure(hr, "Failed to fetch SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey); | ||
| 220 | |||
| 221 | // Note: We need to allocate an extra character on the stream to NULL terminate the SQL script. | ||
| 222 | // The WcaGetRecordStream() function won't let us add extra space on the end of the stream | ||
| 223 | // so we'll read the stream "the old fashioned way". | ||
| 224 | //hr = WcaGetRecordStream(hRecBinary, ssbsqData, (BYTE**)&pbScript, &cbScript); | ||
| 225 | //ExitOnFailure(hr, "Failed to read SqlScript.BinaryScript_ for SqlScript '%ls'", sss.wzKey); | ||
| 226 | er = ::MsiRecordReadStream(hRecBinary, ssbsqData, NULL, &cbRead); | ||
| 227 | hr = HRESULT_FROM_WIN32(er); | ||
| 228 | ExitOnFailure(hr, "failed to get size of stream"); | ||
| 229 | |||
| 230 | cbScript = cbRead + sizeof(WCHAR); // we may have an ANSI SQL script but leave enough to even NULL terminate a WCHAR string | ||
| 231 | hr = WcaAllocStream(&pbScript, cbScript); // this will allocate a fully zeroed out buffer so our string will be NULL terminated | ||
| 232 | ExitOnFailure(hr, "failed to allocate data for stream"); | ||
| 233 | |||
| 234 | er = ::MsiRecordReadStream(hRecBinary, ssbsqData, reinterpret_cast<char*>(pbScript), &cbRead); //read the buffer but leave the space for the NULL terminator | ||
| 235 | hr = HRESULT_FROM_WIN32(er); | ||
| 236 | ExitOnFailure(hr, "failed to read from stream"); | ||
| 237 | |||
| 238 | Assert(cbRead + sizeof(WCHAR) == cbScript); | ||
| 239 | |||
| 240 | // Check for the UNICODE BOM file marker. | ||
| 241 | if ((0xFF == *pbScript) && (0xFE == *(pbScript + 1))) | ||
| 242 | { | ||
| 243 | // Copy the UNICODE string after the BOM marker (subtract one because we'll skip the BOM marker). | ||
| 244 | cchScript = (cbScript / sizeof(WCHAR)) - 1; | ||
| 245 | |||
| 246 | hr = StrAllocString(&pwzScriptBuffer, reinterpret_cast<LPWSTR>(pbScript) + 1, 0); | ||
| 247 | ExitOnFailure(hr, "Failed to allocate WCHAR string of size '%d'", cchScript); | ||
| 248 | } | ||
| 249 | else | ||
| 250 | { | ||
| 251 | // We have an ANSI string so convert it to UNICODE. | ||
| 252 | cchScript = cbScript; | ||
| 253 | |||
| 254 | hr = StrAllocStringAnsi(&pwzScriptBuffer, reinterpret_cast<LPCSTR>(pbScript), 0, CP_ACP); | ||
| 255 | ExitOnFailure(hr, "Failed to allocate WCHAR string of size '%d'", cchScript); | ||
| 256 | } | ||
| 257 | |||
| 258 | // Free the byte buffer since it has been converted to a new UNICODE string, one way or another. | ||
| 259 | if (pbScript) | ||
| 260 | { | ||
| 261 | WcaFreeStream(pbScript); | ||
| 262 | pbScript = NULL; | ||
| 263 | } | ||
| 264 | |||
| 265 | // Process the SQL script stripping out unnecessary stuff (like comments) and looking for "GO" statements. | ||
| 266 | pwzScript = pwzScriptBuffer; | ||
| 267 | while (cchScript && pwzScript && *pwzScript) | ||
| 268 | { | ||
| 269 | // strip off leading whitespace | ||
| 270 | while (cchScript && *pwzScript && iswspace(*pwzScript)) | ||
| 271 | { | ||
| 272 | ++pwzScript; | ||
| 273 | --cchScript; | ||
| 274 | } | ||
| 275 | |||
| 276 | Assert(0 <= cchScript); | ||
| 277 | |||
| 278 | // if there is a SQL comment remove it | ||
| 279 | while (cchScript && L'/' == *pwzScript && L'*' == *(pwzScript + 1)) | ||
| 280 | { | ||
| 281 | // go until end of comment | ||
| 282 | while (cchScript && *pwzScript && *(pwzScript + 1) && !(L'*' == *pwzScript && L'/' == *(pwzScript + 1))) | ||
| 283 | { | ||
| 284 | ++pwzScript; | ||
| 285 | --cchScript; | ||
| 286 | } | ||
| 287 | |||
| 288 | Assert(2 <= cchScript); | ||
| 289 | |||
| 290 | if (2 <= cchScript) | ||
| 291 | { | ||
| 292 | // to account for */ at end | ||
| 293 | pwzScript+=2; | ||
| 294 | cchScript-=2; | ||
| 295 | } | ||
| 296 | |||
| 297 | Assert(0 <= cchScript); | ||
| 298 | |||
| 299 | // strip off any new leading whitespace | ||
| 300 | while (cchScript && *pwzScript && iswspace(*pwzScript)) | ||
| 301 | { | ||
| 302 | ++pwzScript; | ||
| 303 | --cchScript; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | while (cchScript && L'-' == *pwzScript && L'-' == *(pwzScript + 1)) | ||
| 308 | { | ||
| 309 | // go past the new line character | ||
| 310 | while (cchScript && *pwzScript && L'\n' != *pwzScript) | ||
| 311 | { | ||
| 312 | ++pwzScript; | ||
| 313 | --cchScript; | ||
| 314 | } | ||
| 315 | |||
| 316 | Assert(0 <= cchScript); | ||
| 317 | |||
| 318 | if (cchScript && L'\n' == *pwzScript) | ||
| 319 | { | ||
| 320 | ++pwzScript; | ||
| 321 | --cchScript; | ||
| 322 | } | ||
| 323 | |||
| 324 | Assert(0 <= cchScript); | ||
| 325 | |||
| 326 | // strip off any new leading whitespace | ||
| 327 | while (cchScript && *pwzScript && iswspace(*pwzScript)) | ||
| 328 | { | ||
| 329 | ++pwzScript; | ||
| 330 | --cchScript; | ||
| 331 | } | ||
| 332 | } | ||
| 333 | |||
| 334 | Assert(0 <= cchScript); | ||
| 335 | |||
| 336 | // try to isolate a "GO" keyword and count the characters in the SQL string | ||
| 337 | pwz = pwzScript; | ||
| 338 | cch = 0; | ||
| 339 | while (cchScript && *pwz) | ||
| 340 | { | ||
| 341 | //skip past comment lines that might have "go" in them | ||
| 342 | //note that these comments are "in the middle" of our function, | ||
| 343 | //or possibly at the end of a line | ||
| 344 | if (cchScript && L'-' == *pwz && L'-' == *(pwz + 1)) | ||
| 345 | { | ||
| 346 | // skip past chars until the new line character | ||
| 347 | while (cchScript && *pwz && (L'\n' != *pwz)) | ||
| 348 | { | ||
| 349 | ++pwz; | ||
| 350 | ++cch; | ||
| 351 | --cchScript; | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 355 | //skip past comment lines of form /* to */ that might have "go" in them | ||
| 356 | //note that these comments are "in the middle" of our function, | ||
| 357 | //or possibly at the end of a line | ||
| 358 | if (cchScript && L'/' == *pwz && L'*' == *(pwz + 1)) | ||
| 359 | { | ||
| 360 | // skip past chars until the new line character | ||
| 361 | while (cchScript && *pwz && *(pwz + 1) && !((L'*' == *pwz) && (L'/' == *(pwz + 1)))) | ||
| 362 | { | ||
| 363 | ++pwz; | ||
| 364 | ++cch; | ||
| 365 | --cchScript; | ||
| 366 | } | ||
| 367 | |||
| 368 | if (2 <= cchScript) | ||
| 369 | { | ||
| 370 | // to account for */ at end | ||
| 371 | pwz+=2; | ||
| 372 | cch+=2; | ||
| 373 | cchScript-=2; | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | // Skip past strings that may be part of the SQL statement that might have a "go" in them | ||
| 378 | if ( cchScript && L'\'' == *pwz ) | ||
| 379 | { | ||
| 380 | ++pwz; | ||
| 381 | ++cch; | ||
| 382 | --cchScript; | ||
| 383 | |||
| 384 | // Skip past chars until the end of the string | ||
| 385 | while ( cchScript && *pwz && !(L'\'' == *pwz) ) | ||
| 386 | { | ||
| 387 | ++pwz; | ||
| 388 | ++cch; | ||
| 389 | --cchScript; | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | // Skip past strings that may be part of the SQL statement that might have a "go" in them | ||
| 394 | if ( cchScript && L'\"' == *pwz ) | ||
| 395 | { | ||
| 396 | ++pwz; | ||
| 397 | ++cch; | ||
| 398 | --cchScript; | ||
| 399 | |||
| 400 | // Skip past chars until the end of the string | ||
| 401 | while ( cchScript && *pwz && !(L'\"' == *pwz) ) | ||
| 402 | { | ||
| 403 | ++pwz; | ||
| 404 | ++cch; | ||
| 405 | --cchScript; | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | // if "GO" is isolated | ||
| 410 | if ((pwzScript == pwz || iswspace(*(pwz - 1))) && | ||
| 411 | (L'G' == *pwz || L'g' == *pwz) && | ||
| 412 | (L'O' == *(pwz + 1) || L'o' == *(pwz + 1)) && | ||
| 413 | (0 == *(pwz + 2) || iswspace(*(pwz + 2)))) | ||
| 414 | { | ||
| 415 | *pwz = 0; // null terminate the SQL string on the "G" | ||
| 416 | pwz += 2; | ||
| 417 | cchScript -= 2; | ||
| 418 | break; // found "GO" now add SQL string to list | ||
| 419 | } | ||
| 420 | |||
| 421 | ++pwz; | ||
| 422 | ++cch; | ||
| 423 | --cchScript; | ||
| 424 | } | ||
| 425 | |||
| 426 | Assert(0 <= cchScript); | ||
| 427 | |||
| 428 | if (0 < cch) //don't process if there's nothing to process | ||
| 429 | { | ||
| 430 | // replace tabs with spaces | ||
| 431 | for (LPWSTR pwzTab = wcsstr(pwzScript, L"\t"); pwzTab; pwzTab = wcsstr(pwzTab, L"\t")) | ||
| 432 | *pwzTab = ' '; | ||
| 433 | |||
| 434 | // strip off whitespace at the end of the script string | ||
| 435 | for (LPWSTR pwzErase = pwzScript + cch - 1; pwzScript < pwzErase && iswspace(*pwzErase); pwzErase--) | ||
| 436 | { | ||
| 437 | *(pwzErase) = 0; | ||
| 438 | cch--; | ||
| 439 | } | ||
| 440 | } | ||
| 441 | |||
| 442 | if (0 < cch) | ||
| 443 | { | ||
| 444 | hr = NewSqlStr(&psss); | ||
| 445 | ExitOnFailure(hr, "failed to allocate new sql string element"); | ||
| 446 | |||
| 447 | // copy everything over | ||
| 448 | hr = ::StringCchCopyW(psss->wzKey, countof(psss->wzKey), sss.wzKey); | ||
| 449 | ExitOnFailure(hr, "Failed to copy key string to sqlstr object"); | ||
| 450 | hr = ::StringCchCopyW(psss->wzSqlDb, countof(psss->wzSqlDb), sss.wzSqlDb); | ||
| 451 | ExitOnFailure(hr, "Failed to copy DB string to sqlstr object"); | ||
| 452 | hr = ::StringCchCopyW(psss->wzComponent, countof(psss->wzComponent), sss.wzComponent); | ||
| 453 | ExitOnFailure(hr, "Failed to copy component string to sqlstr object"); | ||
| 454 | psss->isInstalled = sss.isInstalled; | ||
| 455 | psss->isAction = sss.isAction; | ||
| 456 | psss->iAttributes = sss.iAttributes; | ||
| 457 | psss->iSequence = sss.iSequence; | ||
| 458 | |||
| 459 | // cchRequired includes the NULL terminating char | ||
| 460 | hr = StrAllocString(&psss->pwzSql, pwzScript, 0); | ||
| 461 | ExitOnFailure(hr, "Failed to allocate string for SQL script: '%ls'", psss->wzKey); | ||
| 462 | |||
| 463 | *ppsssList = AddSqlStrToList(*ppsssList, psss); | ||
| 464 | psss = NULL; // set the db NULL so it doesn't accidentally get freed below | ||
| 465 | } | ||
| 466 | |||
| 467 | pwzScript = pwz; | ||
| 468 | } | ||
| 469 | } | ||
| 470 | |||
| 471 | if (E_NOMOREITEMS == hr) | ||
| 472 | { | ||
| 473 | hr = S_OK; | ||
| 474 | } | ||
| 475 | ExitOnFailure(hr, "Failure occured while reading SqlString table"); | ||
| 476 | |||
| 477 | LExit: | ||
| 478 | // if anything was left over after an error clean it all up | ||
| 479 | if (psss) | ||
| 480 | { | ||
| 481 | ScaSqlStrsFreeList(psss); | ||
| 482 | } | ||
| 483 | |||
| 484 | if (pbScript) | ||
| 485 | { | ||
| 486 | WcaFreeStream(pbScript); | ||
| 487 | } | ||
| 488 | |||
| 489 | ReleaseStr(pwzScriptBuffer); | ||
| 490 | ReleaseStr(pwzData); | ||
| 491 | ReleaseStr(pwzComponent); | ||
| 492 | |||
| 493 | return hr; | ||
| 494 | } | ||
| 495 | |||
| 496 | |||
| 497 | HRESULT ScaSqlStrsInstall( | ||
| 498 | __in SCA_DB* psdList, | ||
| 499 | __in SCA_SQLSTR* psssList | ||
| 500 | ) | ||
| 501 | { | ||
| 502 | HRESULT hr = ExecuteStrings(psdList, psssList, TRUE); | ||
| 503 | |||
| 504 | return hr; | ||
| 505 | } | ||
| 506 | |||
| 507 | |||
| 508 | HRESULT ScaSqlStrsUninstall( | ||
| 509 | __in SCA_DB* psdList, | ||
| 510 | __in SCA_SQLSTR* psssList | ||
| 511 | ) | ||
| 512 | { | ||
| 513 | HRESULT hr = ExecuteStrings(psdList, psssList, FALSE); | ||
| 514 | |||
| 515 | return hr; | ||
| 516 | } | ||
| 517 | |||
| 518 | |||
| 519 | void ScaSqlStrsFreeList( | ||
| 520 | __in SCA_SQLSTR* psssList | ||
| 521 | ) | ||
| 522 | { | ||
| 523 | SCA_SQLSTR* psssDelete = psssList; | ||
| 524 | while (psssList) | ||
| 525 | { | ||
| 526 | psssDelete = psssList; | ||
| 527 | psssList = psssList->psssNext; | ||
| 528 | |||
| 529 | if (psssDelete->pwzSql) | ||
| 530 | { | ||
| 531 | ReleaseStr(psssDelete->pwzSql); | ||
| 532 | } | ||
| 533 | |||
| 534 | MemFree(psssDelete); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | |||
| 539 | // private helper functions | ||
| 540 | |||
| 541 | static HRESULT NewSqlStr( | ||
| 542 | __out SCA_SQLSTR** ppsss | ||
| 543 | ) | ||
| 544 | { | ||
| 545 | HRESULT hr = S_OK; | ||
| 546 | SCA_SQLSTR* psss = static_cast<SCA_SQLSTR*>(MemAlloc(sizeof(SCA_SQLSTR), TRUE)); | ||
| 547 | ExitOnNull(psss, hr, E_OUTOFMEMORY, "failed to allocate memory for new sql string element"); | ||
| 548 | |||
| 549 | *ppsss = psss; | ||
| 550 | |||
| 551 | LExit: | ||
| 552 | return hr; | ||
| 553 | } | ||
| 554 | |||
| 555 | |||
| 556 | static SCA_SQLSTR* AddSqlStrToList( | ||
| 557 | __in SCA_SQLSTR* psssList, | ||
| 558 | __in SCA_SQLSTR* psss | ||
| 559 | ) | ||
| 560 | { | ||
| 561 | Assert(psss); //just checking | ||
| 562 | |||
| 563 | //make certain we have a valid sequence number; note that negatives are technically valid | ||
| 564 | if (MSI_NULL_INTEGER == psss->iSequence) | ||
| 565 | { | ||
| 566 | psss->iSequence = 0; | ||
| 567 | } | ||
| 568 | |||
| 569 | if (psssList) | ||
| 570 | { | ||
| 571 | //list already exists, so insert psss into the list in Sequence order | ||
| 572 | |||
| 573 | //see if we need to change the head, otherwise figure out where in the order it fits | ||
| 574 | if (psss->iSequence < psssList->iSequence) | ||
| 575 | { | ||
| 576 | psss->psssNext = psssList; | ||
| 577 | psssList = psss; | ||
| 578 | } | ||
| 579 | else | ||
| 580 | { | ||
| 581 | SCA_SQLSTR* psssT = psssList; | ||
| 582 | //note that if Sequence numbers are duplicated, as in the case of a sqlscript, | ||
| 583 | //we need to insert them "at the end" of the group so the sqlfile stays in order | ||
| 584 | while (psssT->psssNext && (psssT->psssNext->iSequence <= psss->iSequence)) | ||
| 585 | { | ||
| 586 | psssT = psssT->psssNext; | ||
| 587 | } | ||
| 588 | |||
| 589 | //insert our new psss AFTER psssT | ||
| 590 | psss->psssNext = psssT->psssNext; | ||
| 591 | psssT->psssNext = psss; | ||
| 592 | } | ||
| 593 | } | ||
| 594 | else | ||
| 595 | { | ||
| 596 | psssList = psss; | ||
| 597 | } | ||
| 598 | |||
| 599 | return psssList; | ||
| 600 | } | ||
| 601 | |||
| 602 | |||
| 603 | static HRESULT ExecuteStrings( | ||
| 604 | __in SCA_DB* psdList, | ||
| 605 | __in SCA_SQLSTR* psssList, | ||
| 606 | __in BOOL fInstall | ||
| 607 | ) | ||
| 608 | { | ||
| 609 | HRESULT hr = S_FALSE; // assume nothing will be done | ||
| 610 | |||
| 611 | int iRollback = -1; | ||
| 612 | int iOldRollback = iRollback; | ||
| 613 | |||
| 614 | LPCWSTR wzOldDb = NULL; | ||
| 615 | UINT uiCost = 0; | ||
| 616 | WCHAR* pwzCustomActionData = NULL; | ||
| 617 | WCHAR wzNumber[64]; | ||
| 618 | |||
| 619 | // loop through all sql strings | ||
| 620 | for (SCA_SQLSTR* psss = psssList; psss; psss = psss->psssNext) | ||
| 621 | { | ||
| 622 | // if installing this component | ||
| 623 | if ((fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_INSTALL) && WcaIsInstalling(psss->isInstalled, psss->isAction) && !WcaIsReInstalling(psss->isInstalled, psss->isAction)) || | ||
| 624 | (fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_REINSTALL) && WcaIsReInstalling(psss->isInstalled, psss->isAction)) || | ||
| 625 | (!fInstall && (psss->iAttributes & SCASQL_EXECUTE_ON_UNINSTALL) && WcaIsUninstalling(psss->isInstalled, psss->isAction))) | ||
| 626 | { | ||
| 627 | // determine if this is a rollback scheduling or normal deferred scheduling | ||
| 628 | if (psss->iAttributes & SCASQL_ROLLBACK) | ||
| 629 | { | ||
| 630 | iRollback = 1; | ||
| 631 | } | ||
| 632 | else | ||
| 633 | { | ||
| 634 | iRollback = 0; | ||
| 635 | } | ||
| 636 | |||
| 637 | // if we need to create a connection to a new server\database | ||
| 638 | if (!wzOldDb || 0 != lstrcmpW(wzOldDb, psss->wzSqlDb) || iOldRollback != iRollback) | ||
| 639 | { | ||
| 640 | const SCA_DB* psd = ScaDbsFindDatabase(psss->wzSqlDb, psdList); | ||
| 641 | if (!psd) | ||
| 642 | { | ||
| 643 | ExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "failed to find data for Database: %ls", psss->wzSqlDb); | ||
| 644 | } | ||
| 645 | |||
| 646 | if (-1 == iOldRollback) | ||
| 647 | { | ||
| 648 | iOldRollback = iRollback; | ||
| 649 | } | ||
| 650 | Assert(0 == iOldRollback || 1 == iOldRollback); | ||
| 651 | |||
| 652 | // if there was custom action data before, schedule the action to write it | ||
| 653 | if (pwzCustomActionData && *pwzCustomActionData) | ||
| 654 | { | ||
| 655 | Assert(pwzCustomActionData && *pwzCustomActionData && uiCost); | ||
| 656 | |||
| 657 | hr = WcaDoDeferredAction(1 == iOldRollback ? L"RollbackExecuteSqlStrings" : L"ExecuteSqlStrings", pwzCustomActionData, uiCost); | ||
| 658 | ExitOnFailure(hr, "failed to schedule ExecuteSqlStrings action, rollback: %d", iOldRollback); | ||
| 659 | iOldRollback = iRollback; | ||
| 660 | |||
| 661 | *pwzCustomActionData = L'\0'; | ||
| 662 | uiCost = 0; | ||
| 663 | } | ||
| 664 | |||
| 665 | Assert(!pwzCustomActionData || (pwzCustomActionData && 0 == *pwzCustomActionData) && 0 == uiCost); | ||
| 666 | |||
| 667 | hr = WcaWriteStringToCaData(psd->wzKey, &pwzCustomActionData); | ||
| 668 | ExitOnFailure(hr, "Failed to add SQL Server Database String to CustomActionData for Database String: %ls", psd->wzKey); | ||
| 669 | |||
| 670 | hr = WcaWriteStringToCaData(psd->wzServer, &pwzCustomActionData); | ||
| 671 | ExitOnFailure(hr, "Failed to add SQL Server to CustomActionData for Database String: %ls", psd->wzKey); | ||
| 672 | |||
| 673 | hr = WcaWriteStringToCaData(psd->wzInstance, &pwzCustomActionData); | ||
| 674 | ExitOnFailure(hr, "Failed to add SQL Instance to CustomActionData for Database String: %ls", psd->wzKey); | ||
| 675 | |||
| 676 | hr = WcaWriteStringToCaData(psd->wzDatabase, &pwzCustomActionData); | ||
| 677 | ExitOnFailure(hr, "Failed to add SQL Database to CustomActionData for Database String: %ls", psd->wzKey); | ||
| 678 | |||
| 679 | hr = ::StringCchPrintfW(wzNumber, countof(wzNumber), L"%d", psd->iAttributes); | ||
| 680 | ExitOnFailure(hr, "Failed to format attributes integer value to string"); | ||
| 681 | hr = WcaWriteStringToCaData(wzNumber, &pwzCustomActionData); | ||
| 682 | ExitOnFailure(hr, "Failed to add SQL Attributes to CustomActionData for Database String: %ls", psd->wzKey); | ||
| 683 | |||
| 684 | hr = ::StringCchPrintfW(wzNumber, countof(wzNumber), L"%d", psd->fUseIntegratedAuth); | ||
| 685 | ExitOnFailure(hr, "Failed to format UseIntegratedAuth integer value to string"); | ||
| 686 | hr = WcaWriteStringToCaData(wzNumber, &pwzCustomActionData); | ||
| 687 | ExitOnFailure(hr, "Failed to add SQL IntegratedAuth flag to CustomActionData for Database String: %ls", psd->wzKey); | ||
| 688 | |||
| 689 | hr = WcaWriteStringToCaData(psd->scau.wzName, &pwzCustomActionData); | ||
| 690 | ExitOnFailure(hr, "Failed to add SQL UserName to CustomActionData for Database String: %ls", psd->wzKey); | ||
| 691 | |||
| 692 | hr = WcaWriteStringToCaData(psd->scau.wzPassword, &pwzCustomActionData); | ||
| 693 | ExitOnFailure(hr, "Failed to add SQL Password to CustomActionData for Database String: %ls", psd->wzKey); | ||
| 694 | |||
| 695 | uiCost += COST_SQL_CONNECTDB; | ||
| 696 | |||
| 697 | wzOldDb = psss->wzSqlDb; | ||
| 698 | } | ||
| 699 | |||
| 700 | WcaLog(LOGMSG_VERBOSE, "Scheduling SQL string: %ls", psss->pwzSql); | ||
| 701 | |||
| 702 | hr = WcaWriteStringToCaData(psss->wzKey, &pwzCustomActionData); | ||
| 703 | ExitOnFailure(hr, "Failed to add SQL Key to CustomActionData for SQL string: %ls", psss->wzKey); | ||
| 704 | |||
| 705 | hr = WcaWriteIntegerToCaData(psss->iAttributes, &pwzCustomActionData); | ||
| 706 | ExitOnFailure(hr, "failed to add attributes to CustomActionData for SQL string: %ls", psss->wzKey); | ||
| 707 | |||
| 708 | hr = WcaWriteStringToCaData(psss->pwzSql, &pwzCustomActionData); | ||
| 709 | ExitOnFailure(hr, "Failed to to add SQL Query to CustomActionData for SQL string: %ls", psss->wzKey); | ||
| 710 | uiCost += COST_SQL_STRING; | ||
| 711 | } | ||
| 712 | } | ||
| 713 | |||
| 714 | if (pwzCustomActionData && *pwzCustomActionData) | ||
| 715 | { | ||
| 716 | Assert(pwzCustomActionData && *pwzCustomActionData && uiCost); | ||
| 717 | hr = WcaDoDeferredAction(1 == iRollback ? L"RollbackExecuteSqlStrings" : L"ExecuteSqlStrings", pwzCustomActionData, uiCost); | ||
| 718 | ExitOnFailure(hr, "Failed to schedule ExecuteSqlStrings action"); | ||
| 719 | |||
| 720 | *pwzCustomActionData = L'\0'; | ||
| 721 | uiCost = 0; | ||
| 722 | } | ||
| 723 | |||
| 724 | LExit: | ||
| 725 | ReleaseStr(pwzCustomActionData); | ||
| 726 | |||
| 727 | return hr; | ||
| 728 | } | ||
diff --git a/src/ca/scasqlstr.h b/src/ca/scasqlstr.h new file mode 100644 index 00000000..a6f6df1c --- /dev/null +++ b/src/ca/scasqlstr.h | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | #include "scadb.h" | ||
| 6 | |||
| 7 | struct SCA_SQLSTR | ||
| 8 | { | ||
| 9 | // darwin information | ||
| 10 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 11 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 12 | INSTALLSTATE isInstalled, isAction; | ||
| 13 | |||
| 14 | WCHAR wzSqlDb[MAX_DARWIN_COLUMN + 1]; | ||
| 15 | |||
| 16 | BOOL fHasUser; | ||
| 17 | SCA_USER scau; | ||
| 18 | |||
| 19 | LPWSTR pwzSql; | ||
| 20 | int iAttributes; | ||
| 21 | int iSequence; //used to sequence SqlString and SqlScript tables together | ||
| 22 | |||
| 23 | SCA_SQLSTR* psssNext; | ||
| 24 | }; | ||
| 25 | |||
| 26 | |||
| 27 | // prototypes | ||
| 28 | HRESULT ScaSqlStrsRead( | ||
| 29 | __inout SCA_SQLSTR** ppsssList, | ||
| 30 | __in SCA_ACTION saAction | ||
| 31 | ); | ||
| 32 | |||
| 33 | HRESULT ScaSqlStrsReadScripts( | ||
| 34 | __inout SCA_SQLSTR** ppsssList, | ||
| 35 | __in SCA_ACTION saAction | ||
| 36 | ); | ||
| 37 | |||
| 38 | HRESULT ScaSqlStrsInstall( | ||
| 39 | __in SCA_DB* psdList, | ||
| 40 | __in SCA_SQLSTR* psssList | ||
| 41 | ); | ||
| 42 | |||
| 43 | HRESULT ScaSqlStrsUninstall( | ||
| 44 | __in SCA_DB* psdList, | ||
| 45 | __in SCA_SQLSTR* psssList | ||
| 46 | ); | ||
| 47 | |||
| 48 | void ScaSqlStrsFreeList( | ||
| 49 | __in SCA_SQLSTR* psssList | ||
| 50 | ); | ||
| 51 | |||
diff --git a/src/ca/scauser.cpp b/src/ca/scauser.cpp new file mode 100644 index 00000000..4d74e4d4 --- /dev/null +++ b/src/ca/scauser.cpp | |||
| @@ -0,0 +1,82 @@ | |||
| 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 | LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Password` FROM `User` WHERE `User`=?"; | ||
| 6 | enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqPassword }; | ||
| 7 | |||
| 8 | |||
| 9 | HRESULT __stdcall ScaGetUser( | ||
| 10 | __in LPCWSTR wzUser, | ||
| 11 | __out SCA_USER* pscau | ||
| 12 | ) | ||
| 13 | { | ||
| 14 | if (!wzUser || !pscau) | ||
| 15 | { | ||
| 16 | return E_INVALIDARG; | ||
| 17 | } | ||
| 18 | |||
| 19 | HRESULT hr = S_OK; | ||
| 20 | PMSIHANDLE hView, hRec; | ||
| 21 | |||
| 22 | LPWSTR pwzData = NULL; | ||
| 23 | |||
| 24 | // clear struct and bail right away if no user key was passed to search for | ||
| 25 | ::ZeroMemory(pscau, sizeof(*pscau)); | ||
| 26 | if (!*wzUser) | ||
| 27 | { | ||
| 28 | ExitFunction1(hr = S_OK); | ||
| 29 | } | ||
| 30 | |||
| 31 | hRec = ::MsiCreateRecord(1); | ||
| 32 | hr = WcaSetRecordString(hRec, 1, wzUser); | ||
| 33 | ExitOnFailure(hr, "Failed to look up User"); | ||
| 34 | |||
| 35 | hr = WcaOpenView(vcsUserQuery, &hView); | ||
| 36 | ExitOnFailure(hr, "Failed to open view on User table"); | ||
| 37 | hr = WcaExecuteView(hView, hRec); | ||
| 38 | ExitOnFailure(hr, "Failed to execute view on User table"); | ||
| 39 | |||
| 40 | hr = WcaFetchSingleRecord(hView, &hRec); | ||
| 41 | if (S_OK == hr) | ||
| 42 | { | ||
| 43 | hr = WcaGetRecordString(hRec, vuqUser, &pwzData); | ||
| 44 | ExitOnFailure(hr, "Failed to get User.User"); | ||
| 45 | hr = ::StringCchCopyW(pscau->wzKey, countof(pscau->wzKey), pwzData); | ||
| 46 | ExitOnFailure(hr, "Failed to copy key string to user object"); | ||
| 47 | |||
| 48 | hr = WcaGetRecordString(hRec, vuqComponent, &pwzData); | ||
| 49 | ExitOnFailure(hr, "Failed to get User.Component_"); | ||
| 50 | hr = ::StringCchCopyW(pscau->wzComponent, countof(pscau->wzComponent), pwzData); | ||
| 51 | ExitOnFailure(hr, "Failed to copy component string to user object"); | ||
| 52 | |||
| 53 | hr = WcaGetRecordFormattedString(hRec, vuqName, &pwzData); | ||
| 54 | ExitOnFailure(hr, "Failed to get User.Name"); | ||
| 55 | hr = ::StringCchCopyW(pscau->wzName, countof(pscau->wzName), pwzData); | ||
| 56 | ExitOnFailure(hr, "Failed to copy name string to user object"); | ||
| 57 | |||
| 58 | hr = WcaGetRecordFormattedString(hRec, vuqDomain, &pwzData); | ||
| 59 | ExitOnFailure(hr, "Failed to get User.Domain"); | ||
| 60 | hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); | ||
| 61 | ExitOnFailure(hr, "Failed to copy domain string to user object"); | ||
| 62 | |||
| 63 | hr = WcaGetRecordFormattedString(hRec, vuqPassword, &pwzData); | ||
| 64 | ExitOnFailure(hr, "Failed to get User.Password"); | ||
| 65 | hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); | ||
| 66 | ExitOnFailure(hr, "Failed to copy password string to user object"); | ||
| 67 | } | ||
| 68 | else if (E_NOMOREITEMS == hr) | ||
| 69 | { | ||
| 70 | WcaLog(LOGMSG_STANDARD, "Error: Cannot locate User.User='%ls'", wzUser); | ||
| 71 | hr = E_FAIL; | ||
| 72 | } | ||
| 73 | else | ||
| 74 | { | ||
| 75 | ExitOnFailure(hr, "Error or found multiple matching User rows"); | ||
| 76 | } | ||
| 77 | |||
| 78 | LExit: | ||
| 79 | ReleaseStr(pwzData); | ||
| 80 | |||
| 81 | return hr; | ||
| 82 | } | ||
diff --git a/src/ca/scauser.h b/src/ca/scauser.h new file mode 100644 index 00000000..20e561f2 --- /dev/null +++ b/src/ca/scauser.h | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | |||
| 5 | |||
| 6 | // structs | ||
| 7 | struct SCA_GROUP | ||
| 8 | { | ||
| 9 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 10 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 11 | |||
| 12 | WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; | ||
| 13 | WCHAR wzName[MAX_DARWIN_COLUMN + 1]; | ||
| 14 | |||
| 15 | SCA_GROUP *psgNext; | ||
| 16 | }; | ||
| 17 | |||
| 18 | struct SCA_USER | ||
| 19 | { | ||
| 20 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 21 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 22 | INSTALLSTATE isInstalled; | ||
| 23 | INSTALLSTATE isAction; | ||
| 24 | |||
| 25 | WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; | ||
| 26 | WCHAR wzName[MAX_DARWIN_COLUMN + 1]; | ||
| 27 | WCHAR wzPassword[MAX_DARWIN_COLUMN + 1]; | ||
| 28 | INT iAttributes; | ||
| 29 | |||
| 30 | SCA_GROUP *psgGroups; | ||
| 31 | |||
| 32 | SCA_USER *psuNext; | ||
| 33 | }; | ||
| 34 | |||
| 35 | |||
| 36 | // prototypes | ||
| 37 | HRESULT __stdcall ScaGetUser( | ||
| 38 | __in LPCWSTR wzUser, | ||
| 39 | __out SCA_USER* pscau | ||
| 40 | ); | ||
diff --git a/src/ca/sqlca.def b/src/ca/sqlca.def index e16626b3..e899d560 100644 --- a/src/ca/sqlca.def +++ b/src/ca/sqlca.def | |||
| @@ -4,4 +4,10 @@ | |||
| 4 | LIBRARY "sqlca" | 4 | LIBRARY "sqlca" |
| 5 | 5 | ||
| 6 | EXPORTS | 6 | EXPORTS |
| 7 | 7 | ;scaexec.cpp | |
| 8 | CreateDatabase | ||
| 9 | DropDatabase | ||
| 10 | ExecuteSqlStrings | ||
| 11 | ;scasql.cpp | ||
| 12 | InstallSqlData | ||
| 13 | UninstallSqlData | ||
diff --git a/src/ca/sqlca.vcxproj b/src/ca/sqlca.vcxproj index 3d638f6e..b1f7dafa 100644 --- a/src/ca/sqlca.vcxproj +++ b/src/ca/sqlca.vcxproj | |||
| @@ -45,11 +45,22 @@ | |||
| 45 | <ClCompile Include="dllmain.cpp"> | 45 | <ClCompile Include="dllmain.cpp"> |
| 46 | <PrecompiledHeader>Create</PrecompiledHeader> | 46 | <PrecompiledHeader>Create</PrecompiledHeader> |
| 47 | </ClCompile> | 47 | </ClCompile> |
| 48 | <ClCompile Include="scadb.cpp" /> | ||
| 49 | <ClCompile Include="scaexec.cpp" /> | ||
| 50 | <ClCompile Include="scasql.cpp" /> | ||
| 51 | <ClCompile Include="scasqlstr.cpp" /> | ||
| 52 | <ClCompile Include="scauser.cpp" /> | ||
| 48 | <ClCompile Include="sqlca.cpp" /> | 53 | <ClCompile Include="sqlca.cpp" /> |
| 49 | </ItemGroup> | 54 | </ItemGroup> |
| 50 | 55 | ||
| 51 | <ItemGroup> | 56 | <ItemGroup> |
| 57 | <ClInclude Include="CustomMsiErrors.h" /> | ||
| 52 | <ClInclude Include="precomp.h" /> | 58 | <ClInclude Include="precomp.h" /> |
| 59 | <ClInclude Include="sca.h" /> | ||
| 60 | <ClInclude Include="scacost.h" /> | ||
| 61 | <ClInclude Include="scadb.h" /> | ||
| 62 | <ClInclude Include="scasqlstr.h" /> | ||
| 63 | <ClInclude Include="scauser.h" /> | ||
| 53 | </ItemGroup> | 64 | </ItemGroup> |
| 54 | 65 | ||
| 55 | <ItemGroup> | 66 | <ItemGroup> |
