Browse Source

Bug 51: Optionally following symbolic links to directories during file operations

https://winscp.net/tracker/51

Source commit: 9d43be646abcee323df1afcceb9652a82899b5f6
Martin Prikryl 9 years ago
parent
commit
99498ac3e7

+ 4 - 4
source/core/FtpFileSystem.cpp

@@ -972,7 +972,7 @@ void __fastcall TFTPFileSystem::ChangeFileProperties(const UnicodeString AFileNa
         File = OwnedFile;
       }
 
-      if ((File != NULL) && File->IsDirectory && !File->IsSymLink && Properties->Recursive)
+      if ((File != NULL) && File->IsDirectory && FTerminal->CanRecurseToDirectory(File) && Properties->Recursive)
       {
         try
         {
@@ -1146,7 +1146,7 @@ void __fastcall TFTPFileSystem::DoCalculateFilesChecksum(bool UsingHashCommand,
 
     if (File->IsDirectory)
     {
-      if (!File->IsSymLink &&
+      if (FTerminal->CanRecurseToDirectory(File) &&
           !File->IsParentDirectory && !File->IsThisDirectory &&
           // recurse into subdirectories only if we have callback function
           (OnCalculatedChecksum != NULL))
@@ -1632,7 +1632,7 @@ void __fastcall TFTPFileSystem::Sink(const UnicodeString FileName,
   if (File->IsDirectory)
   {
     Action.Cancel();
-    if (!File->IsSymLink)
+    if (FTerminal->CanRecurseToDirectory(File))
     {
       FILE_OPERATION_LOOP_BEGIN
       {
@@ -2201,7 +2201,7 @@ void __fastcall TFTPFileSystem::DeleteFile(const UnicodeString AFileName,
   UnicodeString FileNameOnly = UnixExtractFileName(FileName);
   UnicodeString FilePath = UnixExtractFilePath(FileName);
 
-  bool Dir = (File != NULL) && File->IsDirectory && !File->IsSymLink;
+  bool Dir = (File != NULL) && File->IsDirectory && FTerminal->CanRecurseToDirectory(File);
 
   if (Dir && FLAGCLEAR(Params, dfNoRecursive))
   {

+ 1 - 1
source/core/ScpFileSystem.cpp

@@ -1289,7 +1289,7 @@ void __fastcall TSCPFileSystem::CustomCommandOnFile(const UnicodeString FileName
     TCaptureOutputEvent OutputEvent)
 {
   DebugAssert(File);
-  bool Dir = File->IsDirectory && !File->IsSymLink;
+  bool Dir = File->IsDirectory && FTerminal->CanRecurseToDirectory(File);
   if (Dir && (Params & ccRecursive))
   {
     TCustomCommandParams AParams;

+ 9 - 0
source/core/SessionData.cpp

@@ -168,6 +168,7 @@ void __fastcall TSessionData::Default()
   PreserveDirectoryChanges = true;
   LockInHome = false;
   ResolveSymlinks = true;
+  FollowDirectorySymlinks = false;
   DSTMode = dstmUnix;
   DeleteToRecycleBin = false;
   OverwrittenToRecycleBin = false;
@@ -294,6 +295,7 @@ void __fastcall TSessionData::NonPersistant()
   PROPERTY(PreserveDirectoryChanges); \
   \
   PROPERTY(ResolveSymlinks); \
+  PROPERTY(FollowDirectorySymlinks); \
   PROPERTY(DSTMode); \
   PROPERTY(LockInHome); \
   PROPERTY(Special); \
@@ -558,6 +560,7 @@ void __fastcall TSessionData::DoLoad(THierarchicalStorage * Storage, bool & Rewr
   PreserveDirectoryChanges = Storage->ReadBool(L"PreserveDirectoryChanges", PreserveDirectoryChanges);
 
   ResolveSymlinks = Storage->ReadBool(L"ResolveSymlinks", ResolveSymlinks);
+  FollowDirectorySymlinks = Storage->ReadBool(L"FollowDirectorySymlinks", FollowDirectorySymlinks);
   DSTMode = (TDSTMode)Storage->ReadInteger(L"ConsiderDST", DSTMode);
   LockInHome = Storage->ReadBool(L"LockInHome", LockInHome);
   Special = Storage->ReadBool(L"Special", Special);
@@ -869,6 +872,7 @@ void __fastcall TSessionData::DoSave(THierarchicalStorage * Storage,
     WRITE_DATA(Bool, PreserveDirectoryChanges);
 
     WRITE_DATA(Bool, ResolveSymlinks);
+    WRITE_DATA(Bool, FollowDirectorySymlinks);
     WRITE_DATA_EX(Integer, L"ConsiderDST", DSTMode, );
     WRITE_DATA(Bool, LockInHome);
     // Special is never stored (if it would, login dialog must be modified not to
@@ -2977,6 +2981,11 @@ void __fastcall TSessionData::SetResolveSymlinks(bool value)
 {
   SET_SESSION_PROPERTY(ResolveSymlinks);
 }
+//---------------------------------------------------------------------
+void __fastcall TSessionData::SetFollowDirectorySymlinks(bool value)
+{
+  SET_SESSION_PROPERTY(FollowDirectorySymlinks);
+}
 //---------------------------------------------------------------------------
 void __fastcall TSessionData::SetDSTMode(TDSTMode value)
 {

+ 3 - 0
source/core/SessionData.h

@@ -150,6 +150,7 @@ private:
   UnicodeString FCustomParam1;
   UnicodeString FCustomParam2;
   bool FResolveSymlinks;
+  bool FFollowDirectorySymlinks;
   TDateTime FTimeDifference;
   bool FTimeDifferenceAuto;
   int FSFTPDownloadQueue;
@@ -300,6 +301,7 @@ private:
   void __fastcall SetCustomParam1(UnicodeString value);
   void __fastcall SetCustomParam2(UnicodeString value);
   void __fastcall SetResolveSymlinks(bool value);
+  void __fastcall SetFollowDirectorySymlinks(bool value);
   void __fastcall SetSFTPDownloadQueue(int value);
   void __fastcall SetSFTPUploadQueue(int value);
   void __fastcall SetSFTPListingQueue(int value);
@@ -525,6 +527,7 @@ public:
   __property UnicodeString CustomParam2 = { read = FCustomParam2, write = SetCustomParam2 };
   __property UnicodeString SessionKey = { read = GetSessionKey };
   __property bool ResolveSymlinks = { read = FResolveSymlinks, write = SetResolveSymlinks };
+  __property bool FollowDirectorySymlinks = { read = FFollowDirectorySymlinks, write = SetFollowDirectorySymlinks };
   __property int SFTPDownloadQueue = { read = FSFTPDownloadQueue, write = SetSFTPDownloadQueue };
   __property int SFTPUploadQueue = { read = FSFTPUploadQueue, write = SetSFTPUploadQueue };
   __property int SFTPListingQueue = { read = FSFTPListingQueue, write = SetSFTPListingQueue };

+ 2 - 2
source/core/SessionInfo.cpp

@@ -1153,9 +1153,9 @@ void __fastcall TSessionLog::DoAddStartupInfo(TSessionData * Data)
            EnumName(Data->LookupUserGroups, AutoSwitchNames)));
         ADF(L"Shell: %s", ((Data->Shell.IsEmpty()? UnicodeString(L"default") : Data->Shell)));
         ADF(L"EOL: %s, UTF: %s", (EnumName(Data->EOLType, EOLTypeNames), EnumName(Data->NotUtf, NotAutoSwitchNames))); // NotUtf duplicated in FTP branch
-        ADF(L"Clear aliases: %s, Unset nat.vars: %s, Resolve symlinks: %s",
+        ADF(L"Clear aliases: %s, Unset nat.vars: %s, Resolve symlinks: %s; Follow directory symlinks: %s",
           (BooleanToEngStr(Data->ClearAliases), BooleanToEngStr(Data->UnsetNationalVars),
-           BooleanToEngStr(Data->ResolveSymlinks)));
+           BooleanToEngStr(Data->ResolveSymlinks), BooleanToEngStr(Data->FollowDirectorySymlinks)));
         ADF(L"LS: %s, Ign LS warn: %s, Scp1 Comp: %s",
           (Data->ListingCommand,
            BooleanToEngStr(Data->IgnoreLsWarnings),

+ 4 - 4
source/core/SftpFileSystem.cpp

@@ -3681,7 +3681,7 @@ void __fastcall TSFTPFileSystem::DeleteFile(const UnicodeString FileName,
   const TRemoteFile * File, int Params, TRmSessionAction & Action)
 {
   unsigned char Type;
-  if (File && File->IsDirectory && !File->IsSymLink)
+  if (File && File->IsDirectory && FTerminal->CanRecurseToDirectory(File))
   {
     if (FLAGCLEAR(Params, dfNoRecursive))
     {
@@ -3867,7 +3867,7 @@ void __fastcall TSFTPFileSystem::ChangeFileProperties(const UnicodeString FileNa
   {
     DebugAssert(File);
 
-    if (File->IsDirectory && !File->IsSymLink && AProperties->Recursive)
+    if (File->IsDirectory && FTerminal->CanRecurseToDirectory(File) && AProperties->Recursive)
     {
       try
       {
@@ -3978,7 +3978,7 @@ void __fastcall TSFTPFileSystem::DoCalculateFilesChecksum(
     {
       TRemoteFile * File = (TRemoteFile *)FileList->Objects[Index];
       DebugAssert(File != NULL);
-      if (File->IsDirectory && !File->IsSymLink &&
+      if (File->IsDirectory && FTerminal->CanRecurseToDirectory(File) &&
           !File->IsParentDirectory && !File->IsThisDirectory)
       {
         OperationProgress->SetFile(File->FileName);
@@ -5553,7 +5553,7 @@ void __fastcall TSFTPFileSystem::SFTPSink(const UnicodeString FileName,
   if (File->IsDirectory)
   {
     Action.Cancel();
-    if (!File->IsSymLink)
+    if (FTerminal->CanRecurseToDirectory(File))
     {
       FILE_OPERATION_LOOP_BEGIN
       {

+ 9 - 3
source/core/Terminal.cpp

@@ -3457,7 +3457,7 @@ void __fastcall TTerminal::CustomCommandOnFiles(UnicodeString Command,
     for (int i = 0; i < Files->Count; i++)
     {
       TRemoteFile * File = static_cast<TRemoteFile *>(Files->Objects[i]);
-      bool Dir = File->IsDirectory && !File->IsSymLink;
+      bool Dir = File->IsDirectory && CanRecurseToDirectory(File);
 
       if (!Dir || FLAGSET(Params, ccApplyToDirectories))
       {
@@ -3600,7 +3600,7 @@ void __fastcall TTerminal::CalculateFileSize(UnicodeString FileName,
   {
     if (File->IsDirectory)
     {
-      if (!File->IsSymLink)
+      if (CanRecurseToDirectory(File))
       {
         if (!AParams->AllowDirs)
         {
@@ -4916,7 +4916,7 @@ void __fastcall TTerminal::DoSynchronizeCollectFile(const UnicodeString FileName
 
       bool Modified = false;
       bool New = false;
-      if (File->IsDirectory && File->IsSymLink)
+      if (File->IsDirectory && !CanRecurseToDirectory(File))
       {
         LogEvent(FORMAT(L"Skipping symlink to directory \"%s\".", (File->FileName)));
       }
@@ -6034,6 +6034,12 @@ UnicodeString __fastcall TTerminal::ChangeFileName(const TCopyParamType * CopyPa
   return FileName;
 }
 //---------------------------------------------------------------------------
+bool __fastcall TTerminal::CanRecurseToDirectory(const TRemoteFile * File)
+{
+  return !File->IsSymLink || FSessionData->FollowDirectorySymlinks;
+}
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
 __fastcall TSecondaryTerminal::TSecondaryTerminal(TTerminal * MainTerminal,
   TSessionData * ASessionData, TConfiguration * Configuration, const UnicodeString & Name) :
   TTerminal(ASessionData, Configuration),

+ 1 - 0
source/core/Terminal.h

@@ -391,6 +391,7 @@ protected:
   void __fastcall StartOperationWithFile(
     const UnicodeString & FileName, TFileOperation Operation1, TFileOperation Operation2 = foNone);
   void __fastcall CommandSessionClose(TObject * Sender);
+  bool __fastcall CanRecurseToDirectory(const TRemoteFile * File);
 
   __property TFileOperationProgressType * OperationProgress = { read=FOperationProgress };
 

+ 1 - 1
source/core/WebDAVFileSystem.cpp

@@ -2021,7 +2021,7 @@ void __fastcall TWebDAVFileSystem::Sink(const UnicodeString FileName,
   if (File->IsDirectory)
   {
     Action.Cancel();
-    if (DebugAlwaysTrue(!File->IsSymLink))
+    if (DebugAlwaysTrue(FTerminal->CanRecurseToDirectory(File)))
     {
       FILE_OPERATION_LOOP_BEGIN
       {

+ 1 - 0
source/forms/Properties.cpp

@@ -214,6 +214,7 @@ void __fastcall TPropertiesDialog::LoadInfo()
     if (File->IsDirectory)
     {
       Stats.Directories++;
+      // we should use TTerminal::CanRecurseToDirectory instead
       if (!File->IsSymLink)
       {
         FAllowCalculateStats = true;

+ 2 - 0
source/forms/SiteAdvanced.cpp

@@ -120,6 +120,7 @@ void __fastcall TSiteAdvancedDialog::LoadSession()
     CacheDirectoryChangesCheck->Checked = FSessionData->CacheDirectoryChanges;
     PreserveDirectoryChangesCheck->Checked = FSessionData->PreserveDirectoryChanges;
     ResolveSymlinksCheck->Checked = FSessionData->ResolveSymlinks;
+    FollowDirectorySymlinksCheck->Checked = FSessionData->FollowDirectorySymlinks;
 
     // Environment page
     switch (FSessionData->DSTMode)
@@ -474,6 +475,7 @@ void __fastcall TSiteAdvancedDialog::SaveSession()
   FSessionData->CacheDirectoryChanges = CacheDirectoryChangesCheck->Checked;
   FSessionData->PreserveDirectoryChanges = PreserveDirectoryChangesCheck->Checked;
   FSessionData->ResolveSymlinks = ResolveSymlinksCheck->Checked;
+  FSessionData->FollowDirectorySymlinks = FollowDirectorySymlinksCheck->Checked;
 
   // Environment page
   if (DSTModeUnixCheck->Checked)

+ 13 - 4
source/forms/SiteAdvanced.dfm

@@ -302,16 +302,16 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
           end
         end
         object DirectoryOptionsGroup: TGroupBox
-          Left = 0
-          Top = 198
+          Left = 1
+          Top = 195
           Width = 393
-          Height = 93
+          Height = 116
           Anchors = [akLeft, akTop, akRight]
           Caption = 'Directory reading options'
           TabOrder = 1
           DesignSize = (
             393
-            93)
+            116)
           object CacheDirectoriesCheck: TCheckBox
             Left = 12
             Top = 19
@@ -350,6 +350,15 @@ object SiteAdvancedDialog: TSiteAdvancedDialog
             Caption = '&Permanent cache'
             TabOrder = 2
           end
+          object FollowDirectorySymlinksCheck: TCheckBox
+            Left = 12
+            Top = 88
+            Width = 369
+            Height = 17
+            Anchors = [akLeft, akTop, akRight]
+            Caption = '&Follow symbolic links to directories'
+            TabOrder = 4
+          end
         end
       end
       object RecycleBinSheet: TTabSheet

+ 1 - 0
source/forms/SiteAdvanced.h

@@ -253,6 +253,7 @@ __published:
   TFilenameEdit *TlsCertificateFileEdit;
   TCheckBox *TrimVMSVersionsCheck;
   TComboBox *SshProtCombo;
+  TCheckBox *FollowDirectorySymlinksCheck;
   void __fastcall DataChange(TObject *Sender);
   void __fastcall FormShow(TObject *Sender);
   void __fastcall PageControlChange(TObject *Sender);