Explorar o código

Bug 2227: Restored ability to duplicate remote folders using "cp" command in secondary shell session even when the SFTP server supports copy-file/copy-data extension

https://winscp.net/tracker/2227

Source commit: 9a0ccf0972df5275cdf7409a6e6d0d1e283a8210
Martin Prikryl %!s(int64=2) %!d(string=hai) anos
pai
achega
59393658a0

+ 10 - 0
source/core/RemoteFiles.cpp

@@ -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();

+ 1 - 0
source/core/RemoteFiles.h

@@ -223,6 +223,7 @@ public:
   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 };

+ 37 - 20
source/core/Terminal.cpp

@@ -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;
@@ -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;
   }
@@ -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)
     {

+ 1 - 0
source/core/Terminal.h

@@ -633,6 +633,7 @@ public:
   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);

+ 24 - 9
source/forms/CustomScpExplorer.cpp

@@ -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)
@@ -4531,8 +4539,18 @@ 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;
@@ -4540,7 +4558,7 @@ bool __fastcall TCustomScpExplorerForm::RemoteTransferDialog(TManagedTerminal *&
       else if (Terminal->IsCapable[fcSecondaryShell])
       {
         DebugAssert(DirectCopy);
-        AllowDirectCopy = drcConfirmCommandSession;
+        AllowDirectCopy = Terminal->IsCapable[fcRemoteCopy] ? drcConfirmCommandSessionDirs : drcConfirmCommandSession;
       }
       else
       {
@@ -4629,7 +4647,7 @@ bool __fastcall TCustomScpExplorerForm::RemoteTransferFiles(
           DebugAssert(DirectCopy);
           DebugAssert(Session == Terminal);
 
-          if (Terminal->IsCapable[fcRemoteCopy] ||
+          if (!NeedSecondarySessionForRemoteCopy(FileList) ||
               Terminal->CommandSessionOpened ||
               CommandSessionFallback())
           {
@@ -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;

+ 1 - 0
source/forms/CustomScpExplorer.h

@@ -757,6 +757,7 @@ protected:
   void PasteFiles();
   bool DoDirectoryExists(void * Session, const UnicodeString & Directory);
   void DoBrowseFile(TCustomDirView * DirView, const UnicodeString & FileName);
+  bool NeedSecondarySessionForRemoteCopy(TStrings * FileList);
 
 public:
   virtual __fastcall ~TCustomScpExplorerForm();

+ 5 - 3
source/forms/RemoteTransfer.cpp

@@ -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;

+ 3 - 2
source/resource/TextsWin.h

@@ -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

+ 2 - 1
source/resource/TextsWin1.rc

@@ -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"

+ 1 - 1
source/windows/WinInterface.h

@@ -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,