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

Refactoring checksum calculation to share more code between FTP and SFTP in anticipation of reusing it for SCP/Shell

Source commit: 9a5138737031573ad64085fa64ef8fdd7fca8f77
This commit is contained in:
Martin Prikryl
2022-07-01 12:23:03 +00:00
parent fb707f79f3
commit 03e38c75ae
14 changed files with 179 additions and 208 deletions

View File

@@ -1098,14 +1098,14 @@ bool __fastcall TFTPFileSystem::LoadFilesProperties(TStrings * /*FileList*/)
return false;
}
//---------------------------------------------------------------------------
UnicodeString __fastcall TFTPFileSystem::DoCalculateFileChecksum(
bool UsingHashCommand, const UnicodeString & Alg, TRemoteFile * File)
UnicodeString __fastcall TFTPFileSystem::DoCalculateFileChecksum(const UnicodeString & Alg, TRemoteFile * File)
{
// Overview of server supporting various hash commands is at:
// https://datatracker.ietf.org/doc/html/draft-bryan-ftpext-hash-02#appendix-B
UnicodeString CommandName;
bool UsingHashCommand = UsingHashCommandChecksum(Alg);
if (UsingHashCommand)
{
CommandName = HashCommand;
@@ -1215,82 +1215,49 @@ UnicodeString __fastcall TFTPFileSystem::DoCalculateFileChecksum(
return LowerCase(Hash);
}
//---------------------------------------------------------------------------
void __fastcall TFTPFileSystem::DoCalculateFilesChecksum(bool UsingHashCommand,
void __fastcall TFTPFileSystem::CalculateFilesChecksum(
const UnicodeString & Alg, TStrings * FileList, TStrings * Checksums,
TCalculatedChecksumEvent OnCalculatedChecksum,
TFileOperationProgressType * OperationProgress, bool FirstLevel)
{
TOnceDoneOperation OnceDoneOperation; // not used
FTerminal->CalculateSubFoldersChecksum(Alg, FileList, OnCalculatedChecksum, OperationProgress, FirstLevel);
int Index = 0;
TOnceDoneOperation OnceDoneOperation; // not used
while ((Index < FileList->Count) && !OperationProgress->Cancel)
{
TRemoteFile * File = (TRemoteFile *)FileList->Objects[Index];
DebugAssert(File != NULL);
if (File->IsDirectory)
{
if (FTerminal->CanRecurseToDirectory(File) &&
IsRealFile(File->FileName) &&
// recurse into subdirectories only if we have callback function
(OnCalculatedChecksum != NULL))
{
OperationProgress->SetFile(File->FileName);
TRemoteFileList * SubFiles =
FTerminal->CustomReadDirectoryListing(File->FullFileName, false);
if (SubFiles != NULL)
{
TStrings * SubFileList = new TStringList();
bool Success = false;
try
{
OperationProgress->SetFile(File->FileName);
for (int Index = 0; Index < SubFiles->Count; Index++)
{
TRemoteFile * SubFile = SubFiles->Files[Index];
SubFileList->AddObject(SubFile->FullFileName, SubFile);
}
// do not collect checksums for files in subdirectories,
// only send back checksums via callback
DoCalculateFilesChecksum(UsingHashCommand, Alg, SubFileList, NULL,
OnCalculatedChecksum, OperationProgress, false);
Success = true;
}
__finally
{
delete SubFiles;
delete SubFileList;
if (FirstLevel)
{
OperationProgress->Finish(File->FileName, Success, OnceDoneOperation);
}
}
}
}
}
else
if (!File->IsDirectory)
{
TChecksumSessionAction Action(FTerminal->ActionLog);
try
{
OperationProgress->SetFile(File->FileName);
Action.FileName(FTerminal->AbsolutePath(File->FullFileName, true));
UnicodeString Checksum = DoCalculateFileChecksum(UsingHashCommand, Alg, File);
if (OnCalculatedChecksum != NULL)
bool Success = false;
try
{
OnCalculatedChecksum(File->FileName, Alg, Checksum);
UnicodeString Checksum = DoCalculateFileChecksum(Alg, File);
if (OnCalculatedChecksum != NULL)
{
OnCalculatedChecksum(File->FileName, Alg, Checksum);
}
Action.Checksum(Alg, Checksum);
if (Checksums != NULL)
{
Checksums->Add(Checksum);
}
Success = true;
}
Action.Checksum(Alg, Checksum);
if (Checksums != NULL)
__finally
{
Checksums->Add(Checksum);
if (FirstLevel)
{
OperationProgress->Finish(File->FileName, Success, OnceDoneOperation);
}
}
}
catch (Exception & E)
@@ -1311,41 +1278,30 @@ void __fastcall TFTPFileSystem::DoCalculateFilesChecksum(bool UsingHashCommand,
}
}
//---------------------------------------------------------------------------
void __fastcall TFTPFileSystem::CalculateFilesChecksum(const UnicodeString & Alg,
TStrings * FileList, TStrings * Checksums,
TCalculatedChecksumEvent OnCalculatedChecksum)
UnicodeString TFTPFileSystem::CalculateFilesChecksumInitialize(const UnicodeString & Alg)
{
TFileOperationProgressType Progress(&FTerminal->DoProgress, &FTerminal->DoFinished);
FTerminal->OperationStart(Progress, foCalculateChecksum, osRemote, FileList->Count);
try
UnicodeString NormalizedAlg = FindIdent(FindIdent(Alg, FHashAlgs.get()), FChecksumAlgs.get());
if (UsingHashCommandChecksum(NormalizedAlg))
{
UnicodeString NormalizedAlg = FindIdent(FindIdent(Alg, FHashAlgs.get()), FChecksumAlgs.get());
bool UsingHashCommand = (FHashAlgs->IndexOf(NormalizedAlg) >= 0);
if (UsingHashCommand)
{
// The server should understand lowercase alg name by spec,
// but we should use uppercase anyway
SendCommand(FORMAT(L"OPTS %s %s", (HashCommand, UpperCase(NormalizedAlg))));
GotReply(WaitForCommandReply(), REPLY_2XX_CODE);
}
else if (FChecksumAlgs->IndexOf(NormalizedAlg) >= 0)
{
// will use algorithm-specific command
}
else
{
throw Exception(FMTLOAD(UNKNOWN_CHECKSUM, (Alg)));
}
DoCalculateFilesChecksum(UsingHashCommand, NormalizedAlg, FileList, Checksums, OnCalculatedChecksum,
&Progress, true);
// The server should understand lowercase alg name by spec,
// but we should use uppercase anyway
SendCommand(FORMAT(L"OPTS %s %s", (HashCommand, UpperCase(NormalizedAlg))));
GotReply(WaitForCommandReply(), REPLY_2XX_CODE);
}
__finally
else if (FChecksumAlgs->IndexOf(NormalizedAlg) >= 0)
{
FTerminal->OperationStop(Progress);
// will use algorithm-specific command
}
else
{
throw Exception(FMTLOAD(UNKNOWN_CHECKSUM, (Alg)));
}
return NormalizedAlg;
}
//---------------------------------------------------------------------------
bool TFTPFileSystem::UsingHashCommandChecksum(const UnicodeString & Alg)
{
return (FHashAlgs->IndexOf(Alg) >= 0);
}
//---------------------------------------------------------------------------
bool __fastcall TFTPFileSystem::ConfirmOverwrite(