1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00

Cleanup application data dialog shown only data what exists + Uninstaller does not offer to delete application data, where are not any

Source commit: 5d1f4b8a6e495105e0c877b4854b497cb219ac26
This commit is contained in:
Martin Prikryl
2019-11-15 15:02:42 +00:00
parent 1635a26506
commit 15ce8199da
11 changed files with 247 additions and 211 deletions

View File

@@ -747,28 +747,69 @@ void __fastcall TConfiguration::CleanupConfiguration()
}
}
//---------------------------------------------------------------------------
void __fastcall TConfiguration::CleanupRegistry(const UnicodeString & CleanupSubKey, const UnicodeString & ParentKey)
bool TConfiguration::RegistryPathExists(const UnicodeString & RegistryPath)
{
std::unique_ptr<TRegistryStorage> Registry(new TRegistryStorage(RegistryStorageKey));
UnicodeString ParentKey = ExtractFileDir(RegistryPath);
UnicodeString SubKey = ExtractFileName(RegistryPath);
return
Registry->OpenRootKey(false) &&
(ParentKey.IsEmpty() ||
Registry->OpenSubKeyPath(ParentKey, false)) &&
Registry->KeyExists(SubKey);
}
//---------------------------------------------------------------------------
void __fastcall TConfiguration::CleanupRegistry(const UnicodeString & RegistryPath)
{
std::unique_ptr<TRegistryStorage> Registry(new TRegistryStorage(RegistryStorageKey));
UnicodeString ParentKey = ExtractFileDir(RegistryPath);
if (ParentKey.IsEmpty() ||
Registry->OpenSubKeyPath(ParentKey, false))
{
Registry->RecursiveDeleteSubKey(CleanupSubKey);
UnicodeString SubKey = ExtractFileName(RegistryPath);
Registry->RecursiveDeleteSubKey(SubKey);
}
}
//---------------------------------------------------------------------------
TStrings * TConfiguration::GetCaches()
{
std::unique_ptr<TStrings> Result(new TStringList());
Result->Add(SshHostKeysSubKey);
Result->Add(FtpsCertificateStorageKey);
Result->Add(HttpsCertificateStorageKey);
Result->Add(DirectoryStatisticsCacheKey);
Result->Add(TPath::Combine(ConfigurationSubKey, CDCacheKey));
Result->Add(TPath::Combine(ConfigurationSubKey, BannersKey));
Result->Add(TPath::Combine(ConfigurationSubKey, LastFingerprintsStorageKey));
return Result.release();
}
//---------------------------------------------------------------------------
bool __fastcall TConfiguration::HasAnyCache()
{
bool Result = false;
std::unique_ptr<TStrings> Caches(GetCaches());
for (int Index = 0; Index < Caches->Count; Index++)
{
if (RegistryPathExists(Caches->Strings[Index]))
{
Result = true;
break;
}
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TConfiguration::CleanupCaches()
{
try
{
CleanupRegistry(SshHostKeysSubKey);
CleanupRegistry(FtpsCertificateStorageKey);
CleanupRegistry(HttpsCertificateStorageKey);
CleanupRegistry(DirectoryStatisticsCacheKey);
CleanupRegistry(CDCacheKey, ConfigurationSubKey);
CleanupRegistry(BannersKey, ConfigurationSubKey);
CleanupRegistry(LastFingerprintsStorageKey, ConfigurationSubKey);
std::unique_ptr<TStrings> Caches(GetCaches());
for (int Index = 0; Index < Caches->Count; Index++)
{
CleanupRegistry(Caches->Strings[Index]);
}
}
catch (Exception & E)
{

View File

@@ -161,7 +161,7 @@ protected:
virtual void __fastcall LoadAdmin(THierarchicalStorage * Storage);
virtual UnicodeString __fastcall GetDefaultKeyFile();
virtual void __fastcall Saved();
void __fastcall CleanupRegistry(const UnicodeString & CleanupSubKey, const UnicodeString & ParentKey = UnicodeString());
void __fastcall CleanupRegistry(const UnicodeString & RegistryPath);
void __fastcall CopyAllStringsInSubKey(
THierarchicalStorage * Source, THierarchicalStorage * Target, const UnicodeString & Name);
bool __fastcall CopySubKey(THierarchicalStorage * Source, THierarchicalStorage * Target, const UnicodeString & Name);
@@ -186,6 +186,7 @@ protected:
UnicodeString __fastcall LoadCustomIniFileStorageName();
void __fastcall SaveCustomIniFileStorageName();
UnicodeString __fastcall GetRegistryStorageOverrideKey();
TStrings * GetCaches();
virtual UnicodeString __fastcall ModuleFileName();
@@ -224,6 +225,7 @@ public:
void __fastcall CleanupConfiguration();
void __fastcall CleanupIniFile();
void __fastcall CleanupCaches();
bool __fastcall HasAnyCache();
void __fastcall CleanupRandomSeedFile();
void __fastcall BeginUpdate();
void __fastcall EndUpdate();
@@ -255,6 +257,7 @@ public:
UnicodeString __fastcall GetFileDescription(const UnicodeString & FileName);
UnicodeString __fastcall GetFileVersion(const UnicodeString & FileName);
UnicodeString __fastcall GetFileMimeType(const UnicodeString & FileName);
bool RegistryPathExists(const UnicodeString & RegistryPath);
TStoredSessionList * __fastcall SelectFilezillaSessionsForImport(
TStoredSessionList * Sessions, UnicodeString & Error);

View File

@@ -56,6 +56,11 @@ void __fastcall PuttyInitialize()
strcpy(appname_, AppName.c_str());
}
//---------------------------------------------------------------------------
static bool DeleteRandomSeedOnExit()
{
return !HadRandomSeed && !SaveRandomSeed;
}
//---------------------------------------------------------------------------
void __fastcall PuttyFinalize()
{
if (SaveRandomSeed)
@@ -64,7 +69,7 @@ void __fastcall PuttyFinalize()
}
random_unref();
// random_ref in PuttyInitialize creates the seed file. Delete it, if didn't want to create it.
if (!HadRandomSeed && !SaveRandomSeed)
if (DeleteRandomSeedOnExit())
{
DeleteFile(ApiPath(Configuration->RandomSeedFileName));
}
@@ -81,6 +86,13 @@ void __fastcall DontSaveRandomSeed()
SaveRandomSeed = false;
}
//---------------------------------------------------------------------------
bool RandomSeedExists()
{
return
!DeleteRandomSeedOnExit() &&
FileExists(ApiPath(Configuration->RandomSeedFileName));
}
//---------------------------------------------------------------------------
TSecureShell * GetSecureShell(Plug * plug, bool & pfwd)
{
if (!is_ssh(plug) && !is_pfwd(plug))

View File

@@ -51,4 +51,6 @@ class THierarchicalStorage;
void WritePuttySettings(THierarchicalStorage * Storage, const UnicodeString & Settings);
void SavePuttyDefaults(const UnicodeString & Name);
//---------------------------------------------------------------------------
bool RandomSeedExists();
//---------------------------------------------------------------------------
#endif

View File

@@ -4,139 +4,104 @@
#include <Common.h>
#include <VCLCommon.h>
#include <CoreMain.h>
#include <WinConfiguration.h>
#include <TextsWin.h>
#include <HelpWin.h>
#include <PuttyTools.h>
#include "Cleanup.h"
//---------------------------------------------------------------------
#ifndef NO_RESOURCES
#pragma resource "*.dfm"
#endif
//---------------------------------------------------------------------
Boolean __fastcall DoCleanupDialog(TStoredSessionList *SessionList,
TConfiguration *Configuration)
bool __fastcall DoCleanupDialog()
{
Boolean Result;
TCleanupDialog *CleanupDialog;
try {
CleanupDialog = SafeFormCreate<TCleanupDialog>();
CleanupDialog->SessionList = SessionList;
CleanupDialog->Configuration = Configuration;
Result = (CleanupDialog->ShowModal() == DefaultResult(CleanupDialog));
if (Result)
{
Configuration->Usage->Inc(L"Cleanups");
for (int i = wdConfiguration; i <= wdTemporaryFolders; i++)
{
if (CleanupDialog->CleanupData[(TWinSCPData)i])
{
try
{
switch (i)
{
case wdConfiguration:
Configuration->CleanupConfiguration();
break;
case wdStoredSessions:
SessionList->Cleanup();
break;
case wdCaches:
Configuration->CleanupCaches();
break;
case wdConfigurationIniFile:
Configuration->CleanupIniFile();
break;
case wdRandomSeedFile:
Configuration->CleanupRandomSeedFile();
break;
case wdTemporaryFolders:
WinConfiguration->CleanupTemporaryFolders();
break;
}
}
catch(Exception & E)
{
ShowExtendedException(&E);
}
}
}
}
} __finally {
delete CleanupDialog;
std::unique_ptr<TCleanupDialog> CleanupDialog(SafeFormCreate<TCleanupDialog>());
return CleanupDialog->Execute();
}
//---------------------------------------------------------------------
void __fastcall DoCleanupDialogIfAnyDataAndWanted()
{
std::unique_ptr<TCleanupDialog> CleanupDialog(SafeFormCreate<TCleanupDialog>());
if (CleanupDialog->AnyData() &&
(MessageDialog(LoadStr(UNINSTALL_CLEANUP), qtConfirmation, qaYes | qaNo, HELP_UNINSTALL_CLEANUP) == qaYes))
{
CleanupDialog->Execute();
}
return Result;
}
//---------------------------------------------------------------------
__fastcall TCleanupDialog::TCleanupDialog(TComponent* AOwner)
: TForm(AOwner)
{
FAnyData = false;
FindData();
UseSystemSettings(this);
}
//---------------------------------------------------------------------
void __fastcall TCleanupDialog::AddLocation(int CaptionId, const UnicodeString & Location, TCleanupEvent Event)
{
FCaptions.push_back(LoadStr(CaptionId));
FLocations.push_back(Location);
FCleanupEvents.push_back(Event);
FAnyData = true;
}
//---------------------------------------------------------------------
void __fastcall TCleanupDialog::AddRegistryLocation(int CaptionId, const UnicodeString & Location, TCleanupEvent Event)
{
AddLocation(CaptionId, Configuration->RootKeyStr + L'\\' + Configuration->RegistryStorageKey + L'\\' + Location, Event);
}
//---------------------------------------------------------------------
bool __fastcall TCleanupDialog::AnyData()
{
return FAnyData;
}
//---------------------------------------------------------------------
void __fastcall TCleanupDialog::FindData()
{
// Add unconditionally (as it has a side effect of not saving the configuration)
AddRegistryLocation(CLEANUP_CONFIG, Configuration->ConfigurationSubKey, Configuration->CleanupConfiguration);
// But count as real data, only if it really exists
FAnyData = Configuration->RegistryPathExists(Configuration->ConfigurationSubKey);
if (Configuration->RegistryPathExists(Configuration->StoredSessionsSubKey))
{
AddRegistryLocation(CLEANUP_SESSIONS, Configuration->StoredSessionsSubKey, StoredSessions->Cleanup);
}
if (Configuration->HasAnyCache())
{
AddRegistryLocation(CLEANUP_HOSTKEYS, L"...", Configuration->CleanupCaches);
}
UnicodeString IniFilePath = ExpandEnvironmentVariables(Configuration->IniFileStorageNameForReading);
if (FileExists(IniFilePath))
{
AddLocation(CLEANUP_INIFILE, IniFilePath, Configuration->CleanupIniFile);
}
if (RandomSeedExists())
{
AddLocation(CLEANUP_SEEDFILE, Configuration->RandomSeedFileName, Configuration->CleanupRandomSeedFile);
}
if (WinConfiguration->AnyTemporaryFolders())
{
AddLocation(CLEANUP_TEMP_FOLDERS, WinConfiguration->TemporaryDir(true), WinConfiguration->CleanupTemporaryFolders);
}
}
//---------------------------------------------------------------------
void __fastcall TCleanupDialog::InitControls()
{
DebugAssert(FCaptions.size() == FLocations.size());
DebugAssert(FCaptions.size() == FCleanupEvents.size());
// Particularly in response to WM_DPICHANGED, the form may re-show
DataListView->Items->Clear();
for (int i = wdConfiguration; i <= wdTemporaryFolders; i++)
for (size_t Index = 0; Index < FCaptions.size(); Index++)
{
UnicodeString Caption;
UnicodeString Location;
switch (i)
{
case wdConfiguration:
Caption = LoadStr(CLEANUP_CONFIG);
Location = Configuration->ConfigurationSubKey;
break;
case wdStoredSessions:
Caption = LoadStr(CLEANUP_SESSIONS);
Location = Configuration->StoredSessionsSubKey;
break;
case wdCaches:
Caption = LoadStr(CLEANUP_HOSTKEYS);
Location = L"...";
break;
case wdConfigurationIniFile:
Caption = LoadStr(CLEANUP_INIFILE);
Location = ExpandEnvironmentVariables(Configuration->IniFileStorageNameForReading);
break;
case wdRandomSeedFile:
Caption = LoadStr(CLEANUP_SEEDFILE);
Location = ExpandEnvironmentVariables(Configuration->RandomSeedFile);
break;
case wdTemporaryFolders:
Caption = LoadStr(CLEANUP_TEMP_FOLDERS);
Location = WinConfiguration->TemporaryDir(true);
break;
default:
DebugFail();
break;
}
TListItem * Item = DataListView->Items->Add();
Item->Caption = Caption;
if (i < wdConfigurationIniFile)
{
Location = Configuration->RootKeyStr + L'\\' +
Configuration->RegistryStorageKey + L'\\' + Location;
}
Item->SubItems->Add(Location);
DebugAssert(Item->Index == i - 1);
Item->Caption = FCaptions[Index];
Item->SubItems->Add(FLocations[Index]);
}
AutoSizeListColumnsWidth(DataListView);
@@ -179,13 +144,33 @@ void __fastcall TCleanupDialog::DataListViewInfoTip(TObject * /*Sender*/,
ARRAYOFCONST((Item->Caption, Item->SubItems->Strings[0])));
}
//---------------------------------------------------------------------------
bool __fastcall TCleanupDialog::GetCleanupData(TWinSCPData Data)
{
return DataListView->Items->Item[Data - 1]->Checked;
}
//---------------------------------------------------------------------------
void __fastcall TCleanupDialog::HelpButtonClick(TObject * /*Sender*/)
{
FormHelp(this);
}
//---------------------------------------------------------------------------
bool __fastcall TCleanupDialog::Execute()
{
bool Result = (ShowModal() == DefaultResult(this));
if (Result)
{
Configuration->Usage->Inc(L"Cleanups");
for (int Index = 0; Index < DataListView->Items->Count; Index++)
{
if (DataListView->Items->Item[Index]->Checked)
{
try
{
FCleanupEvents[Index]();
}
catch (Exception & E)
{
ShowExtendedException(&E);
}
}
}
}
return Result;
}
//---------------------------------------------------------------------------

View File

@@ -12,9 +12,6 @@
#include <WinInterface.h>
#include <GUITools.h>
//---------------------------------------------------------------------
enum TWinSCPData {wdConfiguration = 1, wdStoredSessions, wdCaches,
wdConfigurationIniFile, wdRandomSeedFile, wdTemporaryFolders };
//---------------------------------------------------------------------
class TCleanupDialog : public TForm
{
__published:
@@ -34,19 +31,23 @@ __published:
TListItem *Item, UnicodeString &InfoTip);
void __fastcall HelpButtonClick(TObject *Sender);
private:
TStoredSessionList *FSessionList;
TConfiguration * FConfiguration;
std::vector<UnicodeString> FCaptions;
std::vector<UnicodeString> FLocations;
typedef void __fastcall (__closure *TCleanupEvent)();
std::vector<TCleanupEvent> FCleanupEvents;
bool FAnyData;
void __fastcall InitControls();
void __fastcall UpdateControls();
bool __fastcall GetCleanupData(TWinSCPData Data);
void __fastcall FindData();
void __fastcall AddLocation(int CaptionId, const UnicodeString & Location, TCleanupEvent Event);
void __fastcall AddRegistryLocation(int CaptionId, const UnicodeString & Location, TCleanupEvent Event);
INTERFACE_HOOK;
public:
virtual __fastcall TCleanupDialog(TComponent* AOwner);
__property TStoredSessionList *SessionList = { read=FSessionList, write=FSessionList };
__property TConfiguration * Configuration = { read=FConfiguration, write=FConfiguration };
__property Boolean CleanupData[TWinSCPData Data] = { read=GetCleanupData };
virtual __fastcall TCleanupDialog(TComponent * AOwner);
bool __fastcall Execute();
bool __fastcall AnyData();
};
//----------------------------------------------------------------------------
#endif

View File

@@ -1113,7 +1113,7 @@ void __fastcall TLoginDialog::ImportSessionsActionExecute(TObject * /*Sender*/)
//---------------------------------------------------------------------------
void __fastcall TLoginDialog::CleanUpActionExecute(TObject * /*Sender*/)
{
if (DoCleanupDialog(StoredSessions, Configuration))
if (DoCleanupDialog())
{
SaveState();
LoadSessions();

View File

@@ -2480,87 +2480,75 @@ UnicodeString __fastcall TWinConfiguration::TemporaryDir(bool Mask)
return UniqTempDir(ExpandedTemporaryDirectory(), L"scp", Mask);
}
//---------------------------------------------------------------------------
TStrings * __fastcall TWinConfiguration::DoFindTemporaryFolders(bool OnlyFirst)
{
std::unique_ptr<TStrings> Result(new TStringList());
TSearchRecOwned SRec;
UnicodeString Mask = TemporaryDir(true);
UnicodeString Directory = ExtractFilePath(Mask);
if (FindFirstUnchecked(Mask, faDirectory | faHidden, SRec) == 0)
{
do
{
if (SRec.IsDirectory())
{
Result->Add(Directory + SRec.Name);
}
}
while ((FindNextChecked(SRec) == 0) && (!OnlyFirst || Result->Count == 0));
}
if (Result->Count == 0)
{
Result.reset(NULL);
}
return Result.release();
}
//---------------------------------------------------------------------------
TStrings * __fastcall TWinConfiguration::FindTemporaryFolders()
{
TStrings * Result = new TStringList();
try
return DoFindTemporaryFolders(false);
}
//---------------------------------------------------------------------------
bool __fastcall TWinConfiguration::AnyTemporaryFolders()
{
std::unique_ptr<TStrings> Folders(DoFindTemporaryFolders(true));
return (Folders.get() != NULL);
}
//---------------------------------------------------------------------------
void __fastcall TWinConfiguration::CleanupTemporaryFolders()
{
std::unique_ptr<TStrings> Folders(FindTemporaryFolders());
if (Folders.get() != NULL)
{
TSearchRecOwned SRec;
UnicodeString Mask = TemporaryDir(true);
UnicodeString Directory = ExtractFilePath(Mask);
if (FindFirstUnchecked(Mask, faDirectory | faHidden, SRec) == 0)
{
do
{
if (SRec.IsDirectory())
{
Result->Add(Directory + SRec.Name);
}
}
while (FindNextChecked(SRec) == 0);
}
if (Result->Count == 0)
{
delete Result;
Result = NULL;
}
CleanupTemporaryFolders(Folders.get());
}
catch(...)
{
delete Result;
throw;
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TWinConfiguration::CleanupTemporaryFolders(TStrings * Folders)
{
if (DebugAlwaysTrue(Folders->Count > 0))
{
Usage->Inc(L"TemporaryDirectoryCleanups");
}
UnicodeString ErrorList;
TStrings * F;
if (Folders == NULL)
for (int i = 0; i < Folders->Count; i++)
{
F = FindTemporaryFolders();
}
else
{
F = Folders;
if (!DeleteDirectory(Folders->Strings[i]))
{
if (!ErrorList.IsEmpty())
{
ErrorList += L"\n";
}
ErrorList += Folders->Strings[i];
}
}
if (F != NULL)
if (!ErrorList.IsEmpty())
{
try
{
if (DebugAlwaysTrue(F->Count > 0))
{
Usage->Inc(L"TemporaryDirectoryCleanups");
}
for (int i = 0; i < F->Count; i++)
{
if (!DeleteDirectory(F->Strings[i]))
{
if (!ErrorList.IsEmpty())
{
ErrorList += L"\n";
}
ErrorList += F->Strings[i];
}
}
}
__finally
{
if (Folders == NULL)
{
delete F;
}
}
if (!ErrorList.IsEmpty())
{
throw ExtException(LoadStr(CLEANUP_TEMP_ERROR), ErrorList);
}
throw ExtException(LoadStr(CLEANUP_TEMP_ERROR), ErrorList);
}
}
//---------------------------------------------------------------------------
@@ -2737,7 +2725,9 @@ void __fastcall TWinConfiguration::UpdateEntryInJumpList(
FDontDecryptPasswords++;
Storage->AccessMode = smReadWrite;
if (Storage->OpenSubKey(ConfigurationSubKey, true))
// For initial call from UpdateJumpList, do not create the key if it does ot exist yet.
// To avoid creating the key if we are being started just for a maintenance task.
if (Storage->OpenSubKey(ConfigurationSubKey, !Name.IsEmpty()))
{
std::unique_ptr<TStringList> ListSessions(LoadJumpList(Storage, L"JumpList"));
std::unique_ptr<TStringList> ListWorkspaces(LoadJumpList(Storage, L"JumpListWorkspaces"));

View File

@@ -609,6 +609,7 @@ protected:
void __fastcall LoadExtensionList();
void __fastcall ReleaseExtensionTranslations();
void __fastcall LoadExtensionTranslations();
TStrings * __fastcall DoFindTemporaryFolders(bool OnlyFirst);
public:
__fastcall TWinConfiguration();
@@ -618,6 +619,8 @@ public:
virtual THierarchicalStorage * CreateScpStorage(bool & SessionList);
UnicodeString __fastcall TemporaryDir(bool Mask = false);
TStrings * __fastcall FindTemporaryFolders();
bool __fastcall AnyTemporaryFolders();
void __fastcall CleanupTemporaryFolders();
void __fastcall CleanupTemporaryFolders(TStrings * Folders = NULL);
UnicodeString __fastcall ExpandedTemporaryDirectory();
void __fastcall CheckDefaultTranslation();

View File

@@ -193,8 +193,8 @@ void __fastcall DoAboutDialog(TConfiguration * Configuration,
void __fastcall DoAboutDialog(TConfiguration *Configuration);
// forms\Cleanup.cpp
bool __fastcall DoCleanupDialog(TStoredSessionList *SessionList,
TConfiguration *Configuration);
bool __fastcall DoCleanupDialog();
void __fastcall DoCleanupDialogIfAnyDataAndWanted();
// forms\Console.cpp
void __fastcall DoConsoleDialog(TTerminal * Terminal,

View File

@@ -865,14 +865,13 @@ int __fastcall Execute()
if (Params->FindSwitch(L"UninstallCleanup"))
{
MaintenanceTask();
Configuration->DontSave();
// The innosetup cannot skip UninstallCleanup run task for silent uninstalls,
// workaround is that we create mutex in uninstaller, if it runs silent, and
// ignore the UninstallCleanup, when the mutex exists.
if ((OpenMutex(SYNCHRONIZE, false, L"WinSCPSilentUninstall") == NULL) &&
(MessageDialog(LoadStr(UNINSTALL_CLEANUP), qtConfirmation,
qaYes | qaNo, HELP_UNINSTALL_CLEANUP) == qaYes))
if (OpenMutex(SYNCHRONIZE, false, L"WinSCPSilentUninstall") == NULL)
{
DoCleanupDialog(StoredSessions, Configuration);
DoCleanupDialogIfAnyDataAndWanted();
}
}
else if (Params->FindSwitch(L"RegisterForDefaultProtocols") ||