MDEV-27335 Windows, MSI - Bring the datadir location into the instance config UI

This commit is contained in:
Vladislav Vaintroub 2021-12-21 12:24:35 +01:00
parent 3712808ad2
commit 2a6e086902
3 changed files with 96 additions and 63 deletions

View file

@ -161,70 +161,100 @@ static void EscapeCommandLine(const wchar_t *in, wchar_t *out, size_t buflen)
} }
out[pos++]= 0; out[pos++]= 0;
} }
/*
Check for if directory is empty during install, bool IsDirectoryEmptyOrNonExisting(const wchar_t *dir) {
sets "<PROPERTY>_NOT_EMPTY" otherise wchar_t wildcard[MAX_PATH+3];
*/
extern "C" UINT __stdcall CheckDirectoryEmpty(MSIHANDLE hInstall,
const wchar_t *PropertyName)
{
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
wchar_t buf[MAX_PATH];
DWORD len = MAX_PATH;
WIN32_FIND_DATAW data; WIN32_FIND_DATAW data;
HANDLE h; HANDLE h;
bool empty; wcscpy_s(wildcard, MAX_PATH, dir);
wcscat_s(wildcard, MAX_PATH, L"*.*");
bool empty= true;
h= FindFirstFile(wildcard, &data);
if (h != INVALID_HANDLE_VALUE)
{
for (;;)
{
if (wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L".."))
{
empty= false;
break;
}
if (!FindNextFile(h, &data))
break;
}
FindClose(h);
}
return empty;
}
hr = WcaInitialize(hInstall, __FUNCTION__); /*
Check for valid data directory is empty during install
A valid data directory is non-existing, or empty.
In addition, it must be different from any directories that
are going to be installed. This is required. because the full
directory is removed on a feature uninstall, and we do not want
it to be lib or bin.
*/
extern "C" UINT __stdcall CheckDataDirectory(MSIHANDLE hInstall)
{
HRESULT hr= S_OK;
UINT er= ERROR_SUCCESS;
wchar_t datadir[MAX_PATH];
DWORD len= MAX_PATH;
bool empty;
wchar_t *path= 0;
MsiGetPropertyW(hInstall, L"DATADIR", datadir, &len);
hr= WcaInitialize(hInstall, __FUNCTION__);
ExitOnFailure(hr, "Failed to initialize"); ExitOnFailure(hr, "Failed to initialize");
WcaLog(LOGMSG_STANDARD, "Initialized."); WcaLog(LOGMSG_STANDARD, "Initialized.");
MsiGetPropertyW(hInstall, PropertyName, buf, &len); WcaLog(LOGMSG_STANDARD, "Checking files in %S", datadir);
wcscat_s(buf, MAX_PATH, L"*.*"); empty= IsDirectoryEmptyOrNonExisting(datadir);
if (empty)
WcaLog(LOGMSG_STANDARD, "Checking files in %S", buf); WcaLog(LOGMSG_STANDARD, "DATADIR is empty or non-existent");
h= FindFirstFile(buf, &data);
if (h != INVALID_HANDLE_VALUE)
{
empty= true;
for(;;)
{
if (wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L".."))
{
empty= false;
break;
}
if (!FindNextFile(h, &data))
break;
}
FindClose(h);
}
else else
WcaLog(LOGMSG_STANDARD, "DATADIR is NOT empty");
if (!empty)
{ {
/* Non-existent directory, we handle it as empty */ WcaSetProperty(L"DATADIRERROR", L"data directory exist and not empty");
empty = true; goto LExit;
} }
WcaSetProperty(L"DATADIRERROR", L"");
if(empty)
WcaLog(LOGMSG_STANDARD, "Directory %S is empty or non-existent",
PropertyName);
else
WcaLog(LOGMSG_STANDARD, "Directory %S is NOT empty", PropertyName);
wcscpy_s(buf, MAX_PATH, PropertyName);
wcscat_s(buf, L"NOTEMPTY");
WcaSetProperty(buf, empty? L"":L"1");
WcaGetFormattedString(L"[INSTALLDIR]",&path);
if (path && !wcsicmp(datadir, path))
{
WcaSetProperty(L"DATADIRERROR", L"data directory can not be "
L"installation root directory");
ReleaseStr(path);
goto LExit;
}
for (auto dir :
{L"[INSTALLDIR]bin\\", L"[INSTALLDIR]include\\",
L"[INSTALLDIR]lib\\", L"[INSTALLDIR]share\\"})
{
WcaGetFormattedString(dir, &path);
if (path && !wcsnicmp(datadir, path, wcslen(path)))
{
const wchar_t *subdir= dir + sizeof("[INSTALLDIR]") - 1;
wchar_t msg[MAX_PATH]= L"data directory conflicts with '";
wcsncat_s(msg, subdir, wcslen(subdir) - 1);
wcscat_s(msg, L"' directory, which is part of this installation");
WcaSetProperty(L"DATADIRERROR", msg);
ReleaseStr(path);
goto LExit;
}
ReleaseStr(path);
path= 0;
}
LExit: LExit:
return WcaFinalize(er); return WcaFinalize(er);
} }
extern "C" UINT __stdcall CheckDataDirectoryEmpty(MSIHANDLE hInstall)
{
return CheckDirectoryEmpty(hInstall, L"DATADIR");
}
bool CheckServiceExists(const wchar_t *name) bool CheckServiceExists(const wchar_t *name)
{ {

View file

@ -5,6 +5,6 @@ PresetDatabaseProperties
RemoveDataDirectory RemoveDataDirectory
CreateDatabaseRollback CreateDatabaseRollback
CheckDatabaseProperties CheckDatabaseProperties
CheckDataDirectoryEmpty CheckDataDirectory
CheckDBInUse CheckDBInUse
CheckServiceUpgrades CheckServiceUpgrades

View file

@ -230,12 +230,22 @@
<Control Id="CheckBoxUTF8" Type="CheckBox" X="8" Y="154" Width="250" Height="18" Property="UTF8" CheckBoxValue="1" TabSkip="no"> <Control Id="CheckBoxUTF8" Type="CheckBox" X="8" Y="154" Width="250" Height="18" Property="UTF8" CheckBoxValue="1" TabSkip="no">
<Text>{\Font1}Use UTF8 as default server's character set</Text> <Text>{\Font1}Use UTF8 as default server's character set</Text>
</Control> </Control>
<Control Type="Text" Id="Text11" Width="67" Height="17" X="8" Y="190" Text="{\Font1}Data directory" />
<Control Type="PathEdit" Id="TxtDir" Width="175" Height="18" X="80" Y="190" Property="DATADIR">
</Control>
<Control Id="btnDirBrowse" Type="PushButton" Width="56" Height="17" X="278" Y="190" Text="Browse...">
<Publish Property="_BrowseProperty" Value="DATADIR" Order="1">1</Publish>
<Publish Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>
</Control>
<!-- Navigation buttons--> <!-- Navigation buttons-->
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="&amp;Back"> <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="&amp;Back">
<Publish Event="NewDialog" Value="CustomizeDlg">1</Publish> <Publish Event="NewDialog" Value="CustomizeDlg">1</Publish>
</Control> </Control>
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="&amp;Next"> <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="&amp;Next">
<Publish Event="DoAction" Value="CheckDataDirectory">1</Publish>
<Publish Property="WarningText" Value="Invalid data directory, choose a different one. Error: [DATADIRERROR]">
DATADIRERROR
</Publish>
<Publish Property="WarningText" Value="Passwords do not match."><![CDATA[PASSWORD <> RootPasswordConfirm]]></Publish> <Publish Property="WarningText" Value="Passwords do not match."><![CDATA[PASSWORD <> RootPasswordConfirm]]></Publish>
<Publish Event="SpawnDialog" Value="WarningDlg"><![CDATA[WarningText <>""]]></Publish> <Publish Event="SpawnDialog" Value="WarningDlg"><![CDATA[WarningText <>""]]></Publish>
<Publish Property="SERVICENAME" Value="MariaDB">NOT SERVICENAME AND NOT WarningText</Publish> <Publish Property="SERVICENAME" Value="MariaDB">NOT SERVICENAME AND NOT WarningText</Publish>
@ -335,7 +345,7 @@
</UI> </UI>
<Property Id="CRLF" Value="&#xD;&#xA;" /> <Property Id="CRLF" Value="&#xD;&#xA;" />
<CustomAction Id="CheckDataDirectoryEmpty" BinaryKey="wixca.dll" DllEntry="CheckDataDirectoryEmpty" Execute="immediate" Impersonate="yes"/> <CustomAction Id="CheckDataDirectory" BinaryKey="wixca.dll" DllEntry="CheckDataDirectory" Execute="immediate" Impersonate="yes"/>
<!-- What to do when navigation buttons are clicked --> <!-- What to do when navigation buttons are clicked -->
<UI Id="MyWixUI_Mondo"> <UI Id="MyWixUI_Mondo">
<UIRef Id="WixUI_FeatureTree" /> <UIRef Id="WixUI_FeatureTree" />
@ -355,13 +365,6 @@
<Publish Dialog="CustomizeDlg" Control="Back" Event="NewDialog" Value="NewOrUpgradeInstanceDlg" Order="999"> <Publish Dialog="CustomizeDlg" Control="Back" Event="NewDialog" Value="NewOrUpgradeInstanceDlg" Order="999">
NOT Installed AND UpgradableServiceFound NOT Installed AND UpgradableServiceFound
</Publish> </Publish>
<Publish Dialog="CustomizeDlg" Control="Next" Event="DoAction" Value="CheckDataDirectoryEmpty" Order="1"><![CDATA[&DBInstance=3 AND NOT !DBInstance=3]]></Publish>
<Publish Dialog="CustomizeDlg" Property="DATADIRNOTEMPTY" Control="Next" Order="1"><![CDATA[NOT(&DBInstance=3 AND NOT !DBInstance=3)]]></Publish>
<Publish Dialog="CustomizeDlg" Control="Next" Property="WarningText" Order="2"
Value="Selected data directory [DATADIR] is not empty. Either clean it, or choose another location for 'Database Instance' feature.">
DATADIRNOTEMPTY
</Publish>
<Publish Dialog="CustomizeDlg" Control="Next" Event="SpawnDialog" Value="WarningDlg" Order="3">WarningText</Publish>
<Publish Dialog="CustomizeDlg" Control="Next" Event="NewDialog" Value="ConfirmDataCleanupDlg" Order="4"> <Publish Dialog="CustomizeDlg" Control="Next" Event="NewDialog" Value="ConfirmDataCleanupDlg" Order="4">
<![CDATA[(&DBInstance=2) AND (!DBInstance=3)]]> <![CDATA[(&DBInstance=2) AND (!DBInstance=3)]]>
</Publish> </Publish>
@ -634,13 +637,13 @@
Property="FailureProgram" Property="FailureProgram"
Execute="deferred" /> Execute="deferred" />
<CustomAction Id='ErrorDataDirNotEmpty' <CustomAction Id='ErrorDataDir'
Error='Chosen data directory [DATADIR] is not empty. It must be empty prior to installation.'/> Error='Invalid data directory, choose a different one. Error : [DATADIRERROR]'/>
<InstallExecuteSequence> <InstallExecuteSequence>
<Custom Action="CheckDataDirectoryEmpty" After="CostFinalize"> <Custom Action="CheckDataDirectory" After="CostFinalize">
<![CDATA[&DBInstance=3 AND NOT !DBInstance=3 AND OLDERVERSIONBEINGUPGRADED=""]]> <![CDATA[&DBInstance=3 AND NOT !DBInstance=3 AND OLDERVERSIONBEINGUPGRADED=""]]>
</Custom> </Custom>
<Custom Action="ErrorDataDirNotEmpty" After="CheckDataDirectoryEmpty" >DATADIRNOTEMPTY</Custom> <Custom Action="ErrorDataDir" After="CheckDataDirectory">DATADIRERROR</Custom>
<Custom Action="CheckDatabaseProperties" Before="CreateDatabaseCommand">SERVICENAME</Custom> <Custom Action="CheckDatabaseProperties" Before="CreateDatabaseCommand">SERVICENAME</Custom>
<Custom Action="CreateDatabaseCommand" After="CostFinalize" > <Custom Action="CreateDatabaseCommand" After="CostFinalize" >
<![CDATA[&DBInstance=3 AND NOT !DBInstance=3 AND OLDERVERSIONBEINGUPGRADED=""]]> <![CDATA[&DBInstance=3 AND NOT !DBInstance=3 AND OLDERVERSIONBEINGUPGRADED=""]]>