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

File checksum calculation support for SCP protocol and SFTP protocol via secondary shell session using shell commands like sha256sum

Part of Bug 52
https://winscp.net/tracker/52

Source commit: 6804a5d18405a91e8d0a2e0beccf2c31d43ed3f1
This commit is contained in:
Martin Prikryl
2022-07-15 17:32:02 +00:00
parent e69b2bc2a6
commit b4c490b497
9 changed files with 318 additions and 48 deletions

View File

@@ -120,6 +120,7 @@ void __fastcall TConfiguration::Default()
FParallelDurationThreshold = 10;
FMimeTypes = UnicodeString();
FCertificateStorage = EmptyStr;
FChecksumCommands = EmptyStr;
FDontReloadMoreThanSessions = 1000;
FScriptProgressFileNameLimit = 25;
FKeyVersion = 0;

View File

@@ -81,6 +81,7 @@ private:
int FScriptProgressFileNameLimit;
int FKeyVersion;
UnicodeString FCertificateStorage;
UnicodeString FChecksumCommands;
bool FDisablePasswordStoring;
bool FForceBanners;
@@ -331,6 +332,7 @@ public:
__property UnicodeString ExternalIpAddress = { read = FExternalIpAddress, write = SetExternalIpAddress };
__property UnicodeString CertificateStorage = { read = FCertificateStorage, write = SetCertificateStorage };
__property UnicodeString CertificateStorageExpanded = { read = GetCertificateStorageExpanded };
__property UnicodeString ChecksumCommands = { read = FChecksumCommands };
__property int LocalPortNumberMin = { read = FLocalPortNumberMin, write = SetLocalPortNumberMin };
__property int LocalPortNumberMax = { read = FLocalPortNumberMax, write = SetLocalPortNumberMax };
__property bool TryFtpWhenSshFails = { read = FTryFtpWhenSshFails, write = SetTryFtpWhenSshFails };

View File

@@ -1213,8 +1213,9 @@ private:
__fastcall TBackgroundTerminal::TBackgroundTerminal(TTerminal * MainTerminal,
TSessionData * SessionData, TConfiguration * Configuration, TTerminalItem * Item,
const UnicodeString & Name) :
TSecondaryTerminal(MainTerminal, SessionData, Configuration, Name), FItem(Item)
TSecondaryTerminal(MainTerminal, SessionData, Configuration, Name, NULL), FItem(Item)
{
ActionLog->Enabled = false;
}
//---------------------------------------------------------------------------
bool __fastcall TBackgroundTerminal::DoQueryReopen(Exception * /*E*/)

View File

@@ -442,6 +442,7 @@ bool __fastcall TSCPFileSystem::IsCapable(int Capability) const
case fcRemoteCopy:
case fcRemoveCtrlZUpload:
case fcRemoveBOMUpload:
case fcCalculatingChecksum:
return true;
case fcTextMode:
@@ -454,7 +455,6 @@ bool __fastcall TSCPFileSystem::IsCapable(int Capability) const
case fcLoadingAdditionalProperties:
case fcCheckingSpaceAvailable:
case fcIgnorePermErrors:
case fcCalculatingChecksum:
case fcSecondaryShell: // has fcShellAnyCommand
case fcGroupOwnerChangingByID: // by name
case fcMoveToQueue:
@@ -681,6 +681,11 @@ void __fastcall TSCPFileSystem::ExecCommand(const UnicodeString & Cmd, int Param
ReadCommandOutput(COParams, &CmdString);
}
//---------------------------------------------------------------------------
void TSCPFileSystem::InvalidOutputError(const UnicodeString & Command)
{
FTerminal->TerminalError(FMTLOAD(INVALID_OUTPUT_ERROR, (Command, Output->Text)));
}
//---------------------------------------------------------------------------
void __fastcall TSCPFileSystem::ExecCommand(TFSCommand Cmd, const TVarRec * args,
int size, int Params)
{
@@ -695,8 +700,7 @@ void __fastcall TSCPFileSystem::ExecCommand(TFSCommand Cmd, const TVarRec * args
if (((MinL >= 0) && (MinL > FOutput->Count)) ||
((MaxL >= 0) && (MaxL > FOutput->Count)))
{
FTerminal->TerminalError(FmtLoadStr(INVALID_OUTPUT_ERROR,
ARRAYOFCONST((FullCommand, Output->Text))));
InvalidOutputError(FullCommand);
}
}
}
@@ -1299,11 +1303,184 @@ bool __fastcall TSCPFileSystem::LoadFilesProperties(TStrings * /*FileList*/ )
return false;
}
//---------------------------------------------------------------------------
void __fastcall TSCPFileSystem::CalculateFilesChecksum(
const UnicodeString & DebugUsedArg(Alg), TStrings * DebugUsedArg(FileList), TCalculatedChecksumEvent,
TFileOperationProgressType *, bool DebugUsedArg(FirstLevel))
UnicodeString TSCPFileSystem::CalculateFilesChecksumInitialize(const UnicodeString & Alg)
{
DebugFail();
std::unique_ptr<TStrings> Algs(new TStringList());
GetSupportedChecksumAlgs(Algs.get());
return FindIdent(Alg, Algs.get());
}
//---------------------------------------------------------------------------
UnicodeString TSCPFileSystem::ParseFileChecksum(
const UnicodeString & Line, const UnicodeString & FileName, const UnicodeString & Command)
{
int P = Line.Pos(L" ");
if ((P < 0) ||
(P == Line.Length()) ||
((Line[P + 1] != L' ') && (Line[P + 1] != L'*')) ||
(Line.SubString(P + 2, Line.Length() - P - 1) != FileName))
{
InvalidOutputError(Command);
}
return Line.SubString(1, P - 1);
}
//---------------------------------------------------------------------------
void TSCPFileSystem::ProcessFileChecksum(
TCalculatedChecksumEvent OnCalculatedChecksum, TChecksumSessionAction & Action, TFileOperationProgressType * OperationProgress,
bool FirstLevel, const UnicodeString & FileName, const UnicodeString & Alg, const UnicodeString & Checksum)
{
bool Success = !Checksum.IsEmpty();
if (Success)
{
if (OnCalculatedChecksum != NULL)
{
OnCalculatedChecksum(UnixExtractFileName(FileName), Alg, Checksum);
}
Action.Checksum(Alg, Checksum);
}
if (FirstLevel)
{
TOnceDoneOperation OnceDoneOperation; // not used
OperationProgress->Finish(FileName, Success, OnceDoneOperation);
}
}
//---------------------------------------------------------------------------
void __fastcall TSCPFileSystem::CalculateFilesChecksum(
const UnicodeString & Alg, TStrings * FileList, TCalculatedChecksumEvent OnCalculatedChecksum,
TFileOperationProgressType * OperationProgress, bool FirstLevel)
{
FTerminal->CalculateSubFoldersChecksum(Alg, FileList, OnCalculatedChecksum, OperationProgress, FirstLevel);
TStrings * AlgDefs = FTerminal->GetShellChecksumAlgDefs();
int AlgIndex = AlgDefs->IndexOfName(Alg);
UnicodeString AlgCommand = (AlgIndex >= 0) ? AlgDefs->ValueFromIndex[AlgIndex] : Alg;
int Index = 0;
while ((Index < FileList->Count) && !OperationProgress->Cancel)
{
std::unique_ptr<TStrings> BatchFileList(new TStringList());
UnicodeString FileListCommandLine;
__int64 BatchSize = 0;
while (Index < FileList->Count)
{
TRemoteFile * File = DebugNotNull(dynamic_cast<TRemoteFile *>(FileList->Objects[Index]));
if (!File->IsDirectory)
{
UnicodeString FileName = FileList->Strings[Index];
UnicodeString FileListCommandLineBak = FileListCommandLine;
AddToShellFileListCommandLine(FileListCommandLine, FileName);
BatchSize += File->Size;
if (!FileListCommandLineBak.IsEmpty() &&
((FileListCommandLine.Length() > 2048) ||
(BatchSize > 1024*1024*1024)))
{
FileListCommandLine = FileListCommandLineBak;
break;
}
else
{
BatchFileList->AddObject(FileName, File);
}
}
Index++;
}
if (!FileListCommandLine.IsEmpty())
{
bool IndividualCommands = false;
std::unique_ptr<TStrings> BatchChecksums(new TStringList());
try
{
UnicodeString BatchCommand = FORMAT(L"%s %s", (AlgCommand, FileListCommandLine));
AnyCommand(BatchCommand, NULL);
if (Output->Count != BatchFileList->Count)
{
InvalidOutputError(BatchCommand);
}
// First do everything that can throw.
// Only once everything is checked, distribute the results.
for (int BatchIndex = 0; BatchIndex < BatchFileList->Count; BatchIndex++)
{
UnicodeString FileName = BatchFileList->Strings[BatchIndex];
UnicodeString Line = Output->Strings[BatchIndex];
UnicodeString Checksum = ParseFileChecksum(Line, FileName, BatchCommand);
BatchChecksums->Add(Checksum);
}
}
catch (Exception & E)
{
if (!FTerminal->Active)
{
throw;
}
else
{
IndividualCommands = true;
}
}
if (!IndividualCommands)
{
// None of this should throw
for (int BatchIndex = 0; BatchIndex < BatchFileList->Count; BatchIndex++)
{
UnicodeString FileName = BatchFileList->Strings[BatchIndex];
TRemoteFile * File = DebugNotNull(dynamic_cast<TRemoteFile *>(BatchFileList->Objects[BatchIndex]));
TChecksumSessionAction Action(FTerminal->ActionLog);
Action.FileName(File->FullFileName);
OperationProgress->SetFile(FileName);
UnicodeString Checksum = BatchChecksums->Strings[BatchIndex];
ProcessFileChecksum(OnCalculatedChecksum, Action, OperationProgress, FirstLevel, FileName, Alg, Checksum);
}
}
else
{
FTerminal->LogEvent(
L"Batch checksum calculation failed, falling back to calculating checksum individually for each file...");
for (int BatchIndex = 0; BatchIndex < BatchFileList->Count; BatchIndex++)
{
TRemoteFile * File = DebugNotNull(dynamic_cast<TRemoteFile *>(BatchFileList->Objects[BatchIndex]));
TChecksumSessionAction Action(FTerminal->ActionLog);
try
{
UnicodeString FileName = BatchFileList->Strings[BatchIndex];
OperationProgress->SetFile(FileName);
Action.FileName(File->FullFileName);
bool Success = false;
UnicodeString Checksum;
try
{
UnicodeString Command = FORMAT(L"%s %s", (AlgCommand, ShellQuoteStr(FileName)));
AnyCommand(Command, NULL);
if (Output->Count != 1)
{
InvalidOutputError(Command);
}
UnicodeString Line = Output->Strings[0];
Checksum = ParseFileChecksum(Line, FileName, Command);
}
__finally
{
ProcessFileChecksum(OnCalculatedChecksum, Action, OperationProgress, FirstLevel, FileName, Alg, Checksum);
}
}
catch (Exception & E)
{
FTerminal->RollbackAction(Action, OperationProgress, &E);
UnicodeString Error = FMTLOAD(CHECKSUM_ERROR, (File->FullFileName));
FTerminal->CommandError(&E, Error);
// Abort loop.
// TODO: retries? resume?
BatchIndex = BatchFileList->Count;
Index = FileList->Count;
}
}
}
}
}
}
//---------------------------------------------------------------------------
void __fastcall TSCPFileSystem::CustomCommandOnFile(const UnicodeString FileName,
@@ -2668,9 +2845,9 @@ void __fastcall TSCPFileSystem::SCPSink(const UnicodeString TargetDir,
}
}
//---------------------------------------------------------------------------
void __fastcall TSCPFileSystem::GetSupportedChecksumAlgs(TStrings * /*Algs*/)
void __fastcall TSCPFileSystem::GetSupportedChecksumAlgs(TStrings * Algs)
{
// NOOP
FTerminal->GetShellChecksumAlgs(Algs);
}
//---------------------------------------------------------------------------
void __fastcall TSCPFileSystem::LockFile(const UnicodeString & /*FileName*/, const TRemoteFile * /*File*/)

View File

@@ -30,6 +30,7 @@ public:
const TRemoteFile * File, const TRemoteProperties * Properties,
TChmodSessionAction & Action);
virtual bool __fastcall LoadFilesProperties(TStrings * FileList);
virtual UnicodeString CalculateFilesChecksumInitialize(const UnicodeString & Alg);
virtual void __fastcall CalculateFilesChecksum(
const UnicodeString & Alg, TStrings * FileList, TCalculatedChecksumEvent OnCalculatedChecksum,
TFileOperationProgressType * OperationProgress, bool FirstLevel);
@@ -117,6 +118,7 @@ private:
const UnicodeString & CmdString);
void __fastcall ExecCommand(TFSCommand Cmd, const TVarRec * args = NULL,
int size = 0, int Params = -1);
void InvalidOutputError(const UnicodeString & Command);
void __fastcall ReadCommandOutput(int Params, const UnicodeString * Cmd = NULL);
void __fastcall SCPResponse(bool * GotLastLine = NULL);
void __fastcall SCPDirectorySource(const UnicodeString DirectoryName,
@@ -145,6 +147,11 @@ private:
TOperationSide Side,
const TOverwriteFileParams * FileParams, const TCopyParamType * CopyParam,
int Params, TFileOperationProgressType * OperationProgress);
UnicodeString ParseFileChecksum(
const UnicodeString & Line, const UnicodeString & FileName, const UnicodeString & Command);
void ProcessFileChecksum(
TCalculatedChecksumEvent OnCalculatedChecksum, TChecksumSessionAction & Action, TFileOperationProgressType * OperationProgress,
bool FirstLevel, const UnicodeString & FileName, const UnicodeString & Alg, const UnicodeString & Checksum);
static bool __fastcall RemoveLastLine(UnicodeString & Line,
int & ReturnCode, UnicodeString LastLine = L"");

View File

@@ -1214,28 +1214,37 @@ void __fastcall TScript::DoCalculatedChecksum(
void __fastcall TScript::ChecksumProc(TScriptProcParams * Parameters)
{
CheckSession();
if (!FTerminal->IsCapable[fcCalculatingChecksum])
if (!FTerminal->IsCapable[fcCalculatingChecksum] &&
(!FTerminal->IsCapable[fcSecondaryShell] || FTerminal->IsEncryptingFiles()))
{
NotSupported();
}
UnicodeString Alg = Parameters->Param[1];
TStrings * FileList = CreateFileList(Parameters, 2, 2, fltQueryServer);
FTerminal->ExceptionOnFail = true;
try
// this is used only to log failures to open separate shell session,
// the actual call logging is done in TTerminal::CalculateFilesChecksum
TChecksumSessionAction Action(FTerminal->ActionLog);
if (EnsureCommandSessionFallback(fcCalculatingChecksum, Action))
{
if ((FileList->Count != 1) ||
DebugNotNull(dynamic_cast<TRemoteFile *>(FileList->Objects[0]))->IsDirectory)
{
throw Exception(FMTLOAD(NOT_FILE_ERROR, (FileList->Strings[0])));
}
Action.Cancel();
FTerminal->CalculateFilesChecksum(Alg, FileList, DoCalculatedChecksum);
}
__finally
{
FTerminal->ExceptionOnFail = false;
FreeFileList(FileList);
UnicodeString Alg = Parameters->Param[1];
TStrings * FileList = CreateFileList(Parameters, 2, 2, fltQueryServer);
FTerminal->ExceptionOnFail = true;
try
{
if ((FileList->Count != 1) ||
DebugNotNull(dynamic_cast<TRemoteFile *>(FileList->Objects[0]))->IsDirectory)
{
throw Exception(FMTLOAD(NOT_FILE_ERROR, (FileList->Strings[0])));
}
FTerminal->CalculateFilesChecksum(Alg, FileList, DoCalculatedChecksum);
}
__finally
{
FTerminal->ExceptionOnFail = false;
FreeFileList(FileList);
}
}
}
//---------------------------------------------------------------------------

View File

@@ -999,15 +999,23 @@ bool TParallelOperation::UpdateFileList(TQueueFileList * UpdateFileList)
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
__fastcall TTerminal::TTerminal(TSessionData * SessionData,
TConfiguration * Configuration)
__fastcall TTerminal::TTerminal(TSessionData * SessionData, TConfiguration * Configuration, TActionLog * ActionLog)
{
FConfiguration = Configuration;
FSessionData = new TSessionData(L"");
FSessionData->Assign(SessionData);
TDateTime Started = Now(); // use the same time for session and XML log
FLog = new TSessionLog(this, Started, FSessionData, Configuration);
FActionLog = new TActionLog(this, Started, FSessionData, Configuration);
if (ActionLog != NULL)
{
FActionLog = ActionLog;
FActionLogOwned = false;
}
else
{
FActionLog = new TActionLog(this, Started, FSessionData, Configuration);
FActionLogOwned = true;
}
FFiles = new TRemoteDirectory(this);
FExceptionOnFail = 0;
FInTransaction = 0;
@@ -1078,7 +1086,14 @@ __fastcall TTerminal::~TTerminal()
SAFE_DESTROY_EX(TCustomFileSystem, FFileSystem);
SAFE_DESTROY_EX(TSessionLog, FLog);
SAFE_DESTROY_EX(TActionLog, FActionLog);
if (FActionLogOwned)
{
SAFE_DESTROY_EX(TActionLog, FActionLog);
}
else
{
FActionLog = NULL;
}
delete FFiles;
delete FDirectoryCache;
delete FDirectoryChangesCache;
@@ -4512,6 +4527,7 @@ void __fastcall TTerminal::CalculateSubFoldersChecksum(
TOnceDoneOperation OnceDoneOperation; // unused
while ((Index < FileList->Count) && !OperationProgress->Cancel)
{
UnicodeString FileName = FileList->Strings[Index];
TRemoteFile * File = DebugNotNull(dynamic_cast<TRemoteFile *>(FileList->Objects[Index]));
if (File->IsDirectory &&
@@ -4532,7 +4548,8 @@ void __fastcall TTerminal::CalculateSubFoldersChecksum(
for (int Index = 0; Index < SubFiles->Count; Index++)
{
TRemoteFile * SubFile = SubFiles->Files[Index];
SubFileList->AddObject(SubFile->FullFileName, SubFile);
UnicodeString SubFileName = UnixCombinePaths(FileName, SubFile->FileName);
SubFileList->AddObject(SubFileName, SubFile);
}
FFileSystem->CalculateFilesChecksum(Alg, SubFileList.get(), OnCalculatedChecksum, OperationProgress, false);
@@ -4561,9 +4578,11 @@ void __fastcall TTerminal::CalculateFilesChecksum(
try
{
UnicodeString NormalizedAlg = FFileSystem->CalculateFilesChecksumInitialize(Alg);
TCustomFileSystem * FileSystem = GetFileSystemForCapability(fcCalculatingChecksum);
FFileSystem->CalculateFilesChecksum(NormalizedAlg, FileList, OnCalculatedChecksum, &Progress, true);
UnicodeString NormalizedAlg = FileSystem->CalculateFilesChecksumInitialize(Alg);
FileSystem->CalculateFilesChecksum(NormalizedAlg, FileList, OnCalculatedChecksum, &Progress, true);
}
__finally
{
@@ -4937,7 +4956,7 @@ bool __fastcall TTerminal::GetCommandSessionOpened()
//---------------------------------------------------------------------------
TTerminal * __fastcall TTerminal::CreateSecondarySession(const UnicodeString & Name, TSessionData * SessionData)
{
std::unique_ptr<TTerminal> Result(new TSecondaryTerminal(this, SessionData, Configuration, Name));
std::unique_ptr<TTerminal> Result(new TSecondaryTerminal(this, SessionData, Configuration, Name, ActionLog));
Result->AutoReadDirectory = false;
@@ -6662,9 +6681,55 @@ const TFileSystemInfo & __fastcall TTerminal::GetFileSystemInfo(bool Retrieve)
return FFileSystem->GetFileSystemInfo(Retrieve);
}
//---------------------------------------------------------------------
TStrings * TTerminal::GetShellChecksumAlgDefs()
{
if (FShellChecksumAlgDefs.get() == NULL)
{
UnicodeString ChecksumCommandsDef = Configuration->ChecksumCommands;
if (ChecksumCommandsDef.IsEmpty())
{
UnicodeString Delimiter(L",");
AddToList(ChecksumCommandsDef, Sha512ChecksumAlg + L"=sha512sum", Delimiter);
AddToList(ChecksumCommandsDef, Sha384ChecksumAlg + L"=sha384sum", Delimiter);
AddToList(ChecksumCommandsDef, Sha256ChecksumAlg + L"=sha256sum", Delimiter);
AddToList(ChecksumCommandsDef, Sha224ChecksumAlg + L"=sha224sum", Delimiter);
AddToList(ChecksumCommandsDef, Sha1ChecksumAlg + L"=sha1sum", Delimiter);
AddToList(ChecksumCommandsDef, Md5ChecksumAlg + L"=md5sums", Delimiter);
}
FShellChecksumAlgDefs.reset(new TStringList());
FShellChecksumAlgDefs->CommaText = ChecksumCommandsDef;
}
return FShellChecksumAlgDefs.get();
}
//---------------------------------------------------------------------
void TTerminal::GetShellChecksumAlgs(TStrings * Algs)
{
TStrings * AlgDefs = GetShellChecksumAlgDefs();
for (int Index = 0; Index < AlgDefs->Count; Index++)
{
Algs->Add(AlgDefs->Names[Index]);
}
}
//---------------------------------------------------------------------
void __fastcall TTerminal::GetSupportedChecksumAlgs(TStrings * Algs)
{
FFileSystem->GetSupportedChecksumAlgs(Algs);
if (!IsCapable[fcCalculatingChecksum] && IsCapable[fcSecondaryShell])
{
// Both return the same anyway
if (CommandSessionOpened)
{
FCommandSession->GetSupportedChecksumAlgs(Algs);
}
else
{
GetShellChecksumAlgs(Algs);
}
}
else
{
FFileSystem->GetSupportedChecksumAlgs(Algs);
}
}
//---------------------------------------------------------------------
UnicodeString __fastcall TTerminal::GetPassword()
@@ -7789,8 +7854,11 @@ void __fastcall TTerminal::ReflectSettings()
{
DebugAssert(FLog != NULL);
FLog->ReflectSettings();
DebugAssert(FActionLog != NULL);
FActionLog->ReflectSettings();
if (FActionLogOwned)
{
DebugAssert(FActionLog != NULL);
FActionLog->ReflectSettings();
}
// also FTunnelLog ?
}
//---------------------------------------------------------------------------
@@ -8371,13 +8439,13 @@ bool TTerminal::IsValidFile(TRemoteFile * File)
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
__fastcall TSecondaryTerminal::TSecondaryTerminal(TTerminal * MainTerminal,
TSessionData * ASessionData, TConfiguration * Configuration, const UnicodeString & Name) :
TTerminal(ASessionData, Configuration),
__fastcall TSecondaryTerminal::TSecondaryTerminal(
TTerminal * MainTerminal, TSessionData * ASessionData, TConfiguration * Configuration,
const UnicodeString & Name, TActionLog * ActionLog) :
TTerminal(ASessionData, Configuration, ActionLog),
FMainTerminal(MainTerminal)
{
Log->SetParent(FMainTerminal->Log, Name);
ActionLog->Enabled = false;
SessionData->NonPersistant();
DebugAssert(FMainTerminal != NULL);
FMainTerminal->FSecondaryTerminals++;

View File

@@ -160,6 +160,7 @@ private:
TSessionData * FSessionData;
TSessionLog * FLog;
TActionLog * FActionLog;
bool FActionLogOwned;
TConfiguration * FConfiguration;
UnicodeString FCurrentDirectory;
Integer FExceptionOnFail;
@@ -211,6 +212,7 @@ private:
TNotifyEvent FOnClose;
TCallbackGuard * FCallbackGuard;
TFindingFileEvent FOnFindingFile;
std::unique_ptr<TStrings> FShellChecksumAlgDefs;
bool FEnableSecureShellUsage;
bool FCollectFileSystemUsage;
bool FRememberedPasswordTried;
@@ -491,6 +493,8 @@ protected:
void __fastcall CalculateSubFoldersChecksum(
const UnicodeString & Alg, TStrings * FileList, TCalculatedChecksumEvent OnCalculatedChecksum,
TFileOperationProgressType * OperationProgress, bool FirstLevel);
void GetShellChecksumAlgs(TStrings * Algs);
TStrings * GetShellChecksumAlgDefs();
UnicodeString __fastcall EncryptFileName(const UnicodeString & Path, bool EncryptNewFiles);
UnicodeString __fastcall DecryptFileName(const UnicodeString & Path, bool DecryptFullPath, bool DontCache);
@@ -500,7 +504,7 @@ protected:
__property TFileOperationProgressType * OperationProgress = { read=FOperationProgress };
public:
__fastcall TTerminal(TSessionData * SessionData, TConfiguration * Configuration);
__fastcall TTerminal(TSessionData * SessionData, TConfiguration * Configuration, TActionLog * ActionLog = NULL);
__fastcall ~TTerminal();
void __fastcall Open();
void __fastcall Close();
@@ -673,9 +677,9 @@ public:
class TSecondaryTerminal : public TTerminal
{
public:
__fastcall TSecondaryTerminal(TTerminal * MainTerminal,
TSessionData * SessionData, TConfiguration * Configuration,
const UnicodeString & Name);
__fastcall TSecondaryTerminal(
TTerminal * MainTerminal, TSessionData * SessionData, TConfiguration * Configuration,
const UnicodeString & Name, TActionLog * ActionLog);
void __fastcall UpdateFromMain();

View File

@@ -4494,8 +4494,8 @@ void __fastcall TCustomScpExplorerForm::CalculateChecksum(const UnicodeString &
TStrings * FileList, TCalculatedChecksumEvent OnCalculatedChecksum,
bool & Close)
{
// terminal can be already closed (e.g. dropped connection)
if (Terminal != NULL)
if ((Terminal != NULL) && // terminal can be already closed (e.g. dropped connection)
EnsureCommandSessionFallback(fcCalculatingChecksum))
{
Configuration->Usage->Inc(L"ChecksumCalculated");
@@ -4606,7 +4606,8 @@ bool __fastcall TCustomScpExplorerForm::SetProperties(TOperationSide Side, TStri
if (CapableGroupChanging) Flags |= cpGroup;
TCalculateChecksumEvent CalculateChecksumEvent = NULL;
if (Terminal->IsCapable[fcCalculatingChecksum])
if (Terminal->IsCapable[fcCalculatingChecksum] ||
(Terminal->IsCapable[fcSecondaryShell] && !Terminal->IsEncryptingFiles()))
{
CalculateChecksumEvent = CalculateChecksum;
}