Skip to content

Commit

Permalink
Bug 2227: Restored ability to duplicate remote folders using "cp" com…
Browse files Browse the repository at this point in the history
…mand in secondary shell session even when the SFTP server supports copy-file/copy-data extension

https://winscp.net/tracker/2227

Source commit: 9a0ccf0972df5275cdf7409a6e6d0d1e283a8210
  • Loading branch information
martinprikryl committed Oct 3, 2023
1 parent b1447ff commit 5939365
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 36 deletions.
10 changes: 10 additions & 0 deletions source/core/RemoteFiles.cpp
Expand Up @@ -1584,6 +1584,16 @@ TStrings * __fastcall TRemoteFileList::CloneStrings(TStrings * List)
return Result.release();
}
//---------------------------------------------------------------------------
bool TRemoteFileList::AnyDirectory(TStrings * List)
{
bool Result = false;
for (int Index = 0; !Result && (Index < List->Count); Index++)
{
Result = static_cast<TRemoteFile *>(List->Objects[Index])->IsDirectory;
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TRemoteFileList::DuplicateTo(TRemoteFileList * Copy)
{
Copy->Reset();
Expand Down
1 change: 1 addition & 0 deletions source/core/RemoteFiles.h
Expand Up @@ -223,6 +223,7 @@ friend class TS3FileSystem;
virtual void __fastcall AddFile(TRemoteFile * File);

static TStrings * __fastcall CloneStrings(TStrings * List);
static bool AnyDirectory(TStrings * List);

__property UnicodeString Directory = { read = FDirectory, write = SetDirectory };
__property TRemoteFile * Files[Integer Index] = { read = GetFiles };
Expand Down
57 changes: 37 additions & 20 deletions source/core/Terminal.cpp
Expand Up @@ -4375,6 +4375,29 @@ void __fastcall TTerminal::CustomCommandOnFile(UnicodeString FileName,
ReactOnCommand(fsAnyCommand);
}
//---------------------------------------------------------------------------
void TTerminal::PrepareCommandSession(bool NeedCurrentDirectory)
{
DebugAssert(CommandSessionOpened);
DebugAssert(FCommandSession->FSProtocol == cfsSCP);
LogEvent(L"Performing operation on command session.");

if (FCommandSession->CurrentDirectory != CurrentDirectory)
{
FCommandSession->CurrentDirectory = CurrentDirectory;
// We are likely in transaction, so ReadCurrentDirectory won't get called
// until transaction ends. But we need to know CurrentDirectory to
// expand !/ pattern when in CustomCommandOnFiles.
// Doing this only, when current directory of the main and secondary shell differs,
// what would be the case before the first file in transaction.
// Otherwise we would be reading pwd before every time as the
// CustomCommandOnFile on its own sets FReadCurrentDirectoryPending
if (NeedCurrentDirectory && FCommandSession->FReadCurrentDirectoryPending)
{
FCommandSession->ReadCurrentDirectory();
}
}
}
//---------------------------------------------------------------------------
TCustomFileSystem * TTerminal::GetFileSystemForCapability(TFSCapability Capability, bool NeedCurrentDirectory)
{
TCustomFileSystem * Result;
Expand All @@ -4385,25 +4408,7 @@ TCustomFileSystem * TTerminal::GetFileSystemForCapability(TFSCapability Capabili
}
else
{
DebugAssert(CommandSessionOpened);
DebugAssert(FCommandSession->FSProtocol == cfsSCP);
LogEvent(L"Performing operation on command session.");

if (FCommandSession->CurrentDirectory != CurrentDirectory)
{
FCommandSession->CurrentDirectory = CurrentDirectory;
// We are likely in transaction, so ReadCurrentDirectory won't get called
// until transaction ends. But we need to know CurrentDirectory to
// expand !/ pattern when in CustomCommandOnFiles.
// Doing this only, when current directory of the main and secondary shell differs,
// what would be the case before the first file in transaction.
// Otherwise we would be reading pwd before every time as the
// CustomCommandOnFile on its own sets FReadCurrentDirectoryPending
if (NeedCurrentDirectory && FCommandSession->FReadCurrentDirectoryPending)
{
FCommandSession->ReadCurrentDirectory();
}
}
PrepareCommandSession(NeedCurrentDirectory);

Result = FCommandSession->FFileSystem;
}
Expand Down Expand Up @@ -5049,7 +5054,19 @@ void __fastcall TTerminal::DoCopyFile(const UnicodeString FileName, const TRemot
try
{
DebugAssert(FFileSystem);
GetFileSystemForCapability(fcRemoteCopy)->CopyFile(FileName, File, NewName);
bool CopyDirsOnSecondarySession = IsCapable[fcSecondaryShell];
TCustomFileSystem * FileSystem;
if (CopyDirsOnSecondarySession && File->IsDirectory &&
(FCommandSession != NULL)) // Won't be in scripting, there we let is fail later
{
PrepareCommandSession();
FileSystem = FCommandSession->FFileSystem;
}
else
{
FileSystem = GetFileSystemForCapability(fcRemoteCopy);
}
FileSystem->CopyFile(FileName, File, NewName);
}
catch(Exception & E)
{
Expand Down
1 change: 1 addition & 0 deletions source/core/Terminal.h
Expand Up @@ -633,6 +633,7 @@ friend class TParallelOperation;
void __fastcall UpdateSessionCredentials(TSessionData * Data);
UnicodeString UploadPublicKey(const UnicodeString & FileName);
TCustomFileSystem * GetFileSystemForCapability(TFSCapability Capability, bool NeedCurrentDirectory = false);
void PrepareCommandSession(bool NeedCurrentDirectory = false);

const TSessionInfo & __fastcall GetSessionInfo();
const TFileSystemInfo & __fastcall GetFileSystemInfo(bool Retrieve = false);
Expand Down
33 changes: 24 additions & 9 deletions source/forms/CustomScpExplorer.cpp
Expand Up @@ -4462,6 +4462,14 @@ bool TCustomScpExplorerForm::DoDirectoryExists(void * Session, const UnicodeStri
return Result;
}
//---------------------------------------------------------------------------
bool TCustomScpExplorerForm::NeedSecondarySessionForRemoteCopy(TStrings * FileList)
{
bool CopyDirsOnSecondarySession = Terminal->IsCapable[fcSecondaryShell];
return
!Terminal->IsCapable[fcRemoteCopy] ||
(CopyDirsOnSecondarySession && TRemoteFileList::AnyDirectory(FileList));
}
//---------------------------------------------------------------------------
bool __fastcall TCustomScpExplorerForm::RemoteTransferDialog(TManagedTerminal *& Session,
TStrings * FileList, UnicodeString & Target, UnicodeString & FileMask, bool & DirectCopy,
bool NoConfirmation, bool Move)
Expand Down Expand Up @@ -4531,16 +4539,26 @@ bool __fastcall TCustomScpExplorerForm::RemoteTransferDialog(TManagedTerminal *&
}
}

bool AnyDirectory = false;
bool CopyDirsOnSecondarySession = Terminal->IsCapable[fcSecondaryShell];
if (CopyDirsOnSecondarySession && !Terminal->CommandSessionOpened) // optimization
{
for (int Index = 0; !AnyDirectory && (Index < FileList->Count); Index++)
{
AnyDirectory = DebugNotNull(dynamic_cast<TRemoteFile *>(FileList->Objects[Index]))->IsDirectory;
}
}

TDirectRemoteCopy AllowDirectCopy;
if (Terminal->IsCapable[fcRemoteCopy] || Terminal->CommandSessionOpened)
if (Terminal->CommandSessionOpened || !NeedSecondarySessionForRemoteCopy(FileList))
{
DebugAssert(DirectCopy);
AllowDirectCopy = drcAllow;
}
else if (Terminal->IsCapable[fcSecondaryShell])
{
DebugAssert(DirectCopy);
AllowDirectCopy = drcConfirmCommandSession;
AllowDirectCopy = Terminal->IsCapable[fcRemoteCopy] ? drcConfirmCommandSessionDirs : drcConfirmCommandSession;
}
else
{
Expand Down Expand Up @@ -4629,7 +4647,7 @@ bool __fastcall TCustomScpExplorerForm::RemoteTransferFiles(
DebugAssert(DirectCopy);
DebugAssert(Session == Terminal);

if (Terminal->IsCapable[fcRemoteCopy] ||
if (!NeedSecondarySessionForRemoteCopy(FileList) ||
Terminal->CommandSessionOpened ||
CommandSessionFallback())
{
Expand Down Expand Up @@ -4833,13 +4851,10 @@ bool __fastcall TCustomScpExplorerForm::SetProperties(TOperationSide Side, TStri
CurrentProperties = TRemoteProperties::CommonProperties(FileList);

bool CapableAclChanging = Terminal->IsCapable[fcAclChangingFiles];
for (int Index = 0; (Index < FileList->Count) && CapableAclChanging; Index++)
if (CapableAclChanging && TRemoteFileList::AnyDirectory(FileList))
{
if (dynamic_cast<TRemoteFile *>(FileList->Objects[Index])->IsDirectory)
{
CapableAclChanging = false;
CurrentProperties.Valid = CurrentProperties.Valid >> vpRights;
}
CapableAclChanging = false;
CurrentProperties.Valid = CurrentProperties.Valid >> vpRights;
}

int Flags = 0;
Expand Down
1 change: 1 addition & 0 deletions source/forms/CustomScpExplorer.h
Expand Up @@ -757,6 +757,7 @@ friend class TEditorUploadQueueItem;
void PasteFiles();
bool DoDirectoryExists(void * Session, const UnicodeString & Directory);
void DoBrowseFile(TCustomDirView * DirView, const UnicodeString & FileName);
bool NeedSecondarySessionForRemoteCopy(TStrings * FileList);

public:
virtual __fastcall ~TCustomScpExplorerForm();
Expand Down
8 changes: 5 additions & 3 deletions source/forms/RemoteTransfer.cpp
Expand Up @@ -158,13 +158,15 @@ void __fastcall TRemoteTransferDialog::FormCloseQuery(TObject * /*Sender*/,
}

if (IsCurrentSessionSelected() &&
(FAllowDirectCopy == drcConfirmCommandSession) &&
((FAllowDirectCopy == drcConfirmCommandSession) || (FAllowDirectCopy == drcConfirmCommandSessionDirs)) &&
!NotDirectCopyCheck->Checked &&
GUIConfiguration->ConfirmCommandSession)
{
TMessageParams Params(mpNeverAskAgainCheck);
unsigned int Answer = MessageDialog(LoadStr(REMOTE_COPY_COMMAND_SESSION2),
qtConfirmation, qaOK | qaCancel, HelpKeyword, &Params);
int ObjectNamePart = (FAllowDirectCopy == drcConfirmCommandSession) ? 1 : 2;
UnicodeString ObjectName = LoadStrPart(REMOTE_COPY_COMMAND_SESSION_FILES_DIRECTORIES, ObjectNamePart);
UnicodeString Message = FMTLOAD(REMOTE_COPY_COMMAND_SESSION3, (ObjectName, ObjectName, ObjectName));
unsigned int Answer = MessageDialog(Message, qtConfirmation, qaOK | qaCancel, HelpKeyword, &Params);
if (Answer == qaNeverAskAgain)
{
GUIConfiguration->ConfirmCommandSession = false;
Expand Down
5 changes: 3 additions & 2 deletions source/resource/TextsWin.h
Expand Up @@ -463,8 +463,9 @@
#define LOGIN_NEW_SESSION_FOLDER_PROMPT 1813
#define ABOUT_REGISTRATION_LINK 1815
#define REMOTE_TRANSFER_PROMPT2 1816
#define REMOTE_COPY_COMMAND_SESSION2 1817
#define EDITOR_AD_HOC 1818
#define REMOTE_COPY_COMMAND_SESSION3 1817
#define REMOTE_COPY_COMMAND_SESSION_FILES_DIRECTORIES 1818
#define EDITOR_AD_HOC 1819
#define FILE_INFO_HIDDEN2 1820
#define FILE_INFO_FILTERED2 1821
#define FILTER_MASK_CAPTION 1822
Expand Down
3 changes: 2 additions & 1 deletion source/resource/TextsWin1.rc
Expand Up @@ -468,7 +468,8 @@ BEGIN
LOGIN_NEW_SESSION_FOLDER_CAPTION, "Create Site Folder"
LOGIN_NEW_SESSION_FOLDER_PROMPT, "New folder name:"
ABOUT_REGISTRATION_LINK, "How to purchase a license..."
REMOTE_COPY_COMMAND_SESSION2, "**Do you want to open a separate shell session to duplicate the file(s)?**\n \nCurrent session does not support direct duplication of remote files. A separate shell session may be opened to process the duplication. Alternatively you may duplicate the file(s) via local temporary copy."
REMOTE_COPY_COMMAND_SESSION3, "**Do you want to open a separate shell session to duplicate the %s?**\n \nCurrent session does not support direct duplication of remote %s. A separate shell session may be opened to process the duplication. Alternatively you may duplicate the %s via local temporary copy."
REMOTE_COPY_COMMAND_SESSION_FILES_DIRECTORIES, "file(s)|directory(ies)"
EDITOR_AD_HOC, "Editor"
FILE_INFO_HIDDEN2, "%s hidden"
FILE_INFO_FILTERED2, "%s filtered"
Expand Down
2 changes: 1 addition & 1 deletion source/windows/WinInterface.h
Expand Up @@ -330,7 +330,7 @@ bool __fastcall DoPropertiesDialog(TStrings * FileList,
typedef bool (__closure * TDirectoryExistsEvent)(void * Session, const UnicodeString & Directory);
bool __fastcall DoRemoteMoveDialog(
bool Multi, UnicodeString & Target, UnicodeString & FileMask, TDirectoryExistsEvent OnDirectoryExists);
enum TDirectRemoteCopy { drcDisallow, drcAllow, drcConfirmCommandSession };
enum TDirectRemoteCopy { drcDisallow, drcAllow, drcConfirmCommandSession, drcConfirmCommandSessionDirs };
bool __fastcall DoRemoteCopyDialog(
TStrings * Sessions, TStrings * Directories,
TDirectRemoteCopy AllowDirectCopy, bool Multi, void *& Session, UnicodeString & Target, UnicodeString & FileMask,
Expand Down

0 comments on commit 5939365

Please sign in to comment.