aboutsummaryrefslogtreecommitdiff
path: root/src/ca/scadb.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/ca/scadb.cpp587
1 files changed, 587 insertions, 0 deletions
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
6LPCWSTR vcsSqlDatabaseQuery = L"SELECT `SqlDb`, `Server`, `Instance`, `Database`, "
7 L"`Component_`, `User_`, `FileSpec_`, `FileSpec_Log`, `Attributes` "
8 L"FROM `SqlDatabase`";
9enum eSqlDatabaseQuery { sdqSqlDb = 1, sdqServer, sdqInstance, sdqDatabase,
10 sdqComponent, sdqUser, sdqDbFileSpec, sdqLogFileSpec, sdqAttributes };
11
12LPCWSTR vcsSqlFileSpecQuery = L"SELECT `FileSpec`, `Name`, `Filename`, `Size`, "
13 L"`MaxSize`, `GrowthSize` FROM `SqlFileSpec` WHERE `FileSpec`=?";
14enum eSqlFileSpecQuery { sfsqFileSpec = 1, sfsqName, sfsqFilename, sfsqSize,
15 sfsqMaxSize, sfsqGrowth };
16
17
18// prototypes for private helper functions
19static HRESULT NewDb(
20 __out SCA_DB** ppsd
21 );
22
23static SCA_DB* AddDbToList(
24 __in SCA_DB* psdList,
25 __in SCA_DB* psd
26 );
27
28static HRESULT SchedCreateDatabase(
29 __in SCA_DB* psd
30 );
31
32static 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
42static HRESULT GetFileSpec(
43 __in MSIHANDLE hViewFileSpec,
44 __in LPCWSTR wzKey,
45 __in SQL_FILESPEC* psf
46 );
47
48
49HRESULT 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
194LExit:
195 if (psd)
196 {
197 ScaDbsFreeList(psd);
198 }
199
200 ReleaseStr(pwzComponent);
201 ReleaseStr(pwzId);
202 ReleaseStr(pwzData);
203 return hr;
204}
205
206
207SCA_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
226HRESULT 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
255LExit:
256 return hr;
257}
258
259
260HRESULT 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
287LExit:
288 return hr;
289}
290
291
292void 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
309static 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
319LExit:
320 return hr;
321}
322
323
324static 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
348static 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
450LExit:
451 ReleaseStr(pwzCustomActionData);
452 return hr;
453}
454
455
456HRESULT 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
497LExit:
498 ReleaseStr(pwzCustomActionData);
499 return hr;
500}
501
502
503HRESULT 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;
584LExit:
585 ReleaseStr(pwzData);
586 return hr;
587}