浏览代码

Bug 2016: Failure when entering directory that contains file with a slash in its name

https://winscp.net/tracker/2016

Source commit: 3cab6dcd0bebd66d62bc8aa4ef37867b454b3d51
Martin Prikryl 4 年之前
父节点
当前提交
a4f5fdd521

+ 5 - 3
source/core/FtpFileSystem.cpp

@@ -4359,7 +4359,7 @@ bool __fastcall TFTPFileSystem::HandleListData(const wchar_t * Path,
     for (unsigned int Index = 0; Index < Count; Index++)
     {
       const TListDataEntry * Entry = &Entries[Index];
-      TRemoteFile * File = new TRemoteFile();
+      std::unique_ptr<TRemoteFile> File(new TRemoteFile());
       try
       {
         File->Terminal = FTerminal;
@@ -4432,7 +4432,6 @@ bool __fastcall TFTPFileSystem::HandleListData(const wchar_t * Path,
       }
       catch (Exception & E)
       {
-        delete File;
         UnicodeString EntryData =
           FORMAT(L"%s/%s/%s/%s/%s/%s/%s/%d/%d/%d/%d/%d/%d/%d/%d/%d/%d",
             (Entry->Name, Entry->Permissions, Entry->HumanPerm, Entry->Owner, Entry->Group, Entry->OwnerGroup, IntToStr(Entry->Size),
@@ -4442,7 +4441,10 @@ bool __fastcall TFTPFileSystem::HandleListData(const wchar_t * Path,
         throw ETerminal(&E, FMTLOAD(LIST_LINE_ERROR, (EntryData)), HELP_LIST_LINE_ERROR);
       }
 
-      FFileList->AddFile(File);
+      if (FTerminal->IsValidFile(File.get()))
+      {
+        FFileList->AddFile(File.release());
+      }
     }
     return true;
   }

+ 16 - 5
source/core/S3FileSystem.cpp

@@ -896,12 +896,16 @@ S3Status TS3FileSystem::LibS3ListServiceCallback(
   if (Data.FileName.IsEmpty() || (Data.FileName == FileName))
   {
     std::unique_ptr<TRemoteFile> File(new TRemoteFile(NULL));
-    File->Terminal = Data.FileSystem->FTerminal;
+    TTerminal * Terminal = Data.FileSystem->FTerminal;
+    File->Terminal = Terminal;
     File->FileName = StrFromS3(BucketName);
     File->Type = FILETYPE_DIRECTORY;
     File->Owner = Data.FileSystem->MakeRemoteToken(OwnerId, OwnerDisplayName);
     File->ModificationFmt = mfNone;
-    Data.FileList->AddFile(File.release());
+    if (Terminal->IsValidFile(File.get()))
+    {
+      Data.FileList->AddFile(File.release());
+    }
   }
 
   return S3StatusOK;
@@ -917,6 +921,7 @@ S3Status TS3FileSystem::LibS3ListBucketCallback(
   // This is being called in chunks, not once for all data in a response.
   Data.KeyCount += ContentsCount;
   Data.NextMarker = StrFromS3(NextMarker);
+  TTerminal * Terminal = Data.FileSystem->FTerminal;
 
   for (int Index = 0; Index < ContentsCount; Index++)
   {
@@ -926,7 +931,7 @@ S3Status TS3FileSystem::LibS3ListBucketCallback(
     if (!FileName.IsEmpty())
     {
       std::unique_ptr<TRemoteFile> File(new TRemoteFile(NULL));
-      File->Terminal = Data.FileSystem->FTerminal;
+      File->Terminal = Terminal;
       File->FileName = FileName;
       File->Type = FILETYPE_DEFAULT;
 
@@ -957,7 +962,10 @@ S3Status TS3FileSystem::LibS3ListBucketCallback(
 
       File->Size = Content->size;
       File->Owner = Data.FileSystem->MakeRemoteToken(Content->ownerId, Content->ownerDisplayName);
-      Data.FileList->AddFile(File.release());
+      if (Terminal->IsValidFile(File.get()))
+      {
+        Data.FileList->AddFile(File.release());
+      }
     }
   }
 
@@ -974,7 +982,10 @@ S3Status TS3FileSystem::LibS3ListBucketCallback(
       File->FileName = FileName;
       File->Type = FILETYPE_DIRECTORY;
       File->ModificationFmt = mfNone;
-      Data.FileList->AddFile(File.release());
+      if (Terminal->IsValidFile(File.get()))
+      {
+        Data.FileList->AddFile(File.release());
+      }
     }
   }
 

+ 6 - 4
source/core/ScpFileSystem.cpp

@@ -1009,8 +1009,6 @@ void __fastcall TSCPFileSystem::ReadDirectory(TRemoteFileList * FileList)
           Params);
       }
 
-      TRemoteFile * File;
-
       // If output is not empty, we have successfully got file listing,
       // otherwise there was an error, in case it was "permission denied"
       // we try to get at least parent directory (see "else" statement below)
@@ -1036,8 +1034,11 @@ void __fastcall TSCPFileSystem::ReadDirectory(TRemoteFileList * FileList)
             UnicodeString OutputLine = OutputCopy->Strings[Index];
             if (!OutputLine.IsEmpty())
             {
-              File = CreateRemoteFile(OutputCopy->Strings[Index]);
-              FileList->AddFile(File);
+              std::unique_ptr<TRemoteFile> File(CreateRemoteFile(OutputCopy->Strings[Index]));
+              if (FTerminal->IsValidFile(File.get()))
+              {
+                FileList->AddFile(File.release());
+              }
             }
           }
         }
@@ -1053,6 +1054,7 @@ void __fastcall TSCPFileSystem::ReadDirectory(TRemoteFileList * FileList)
         {
           // Empty file list -> probably "permission denied", we
           // at least get link to parent directory ("..")
+          TRemoteFile * File;
           FTerminal->ReadFile(
             UnixIncludeTrailingBackslash(FTerminal->FFiles->Directory) +
               PARENTDIRECTORY, File);

+ 33 - 29
source/core/SftpFileSystem.cpp

@@ -3479,40 +3479,44 @@ void __fastcall TSFTPFileSystem::ReadDirectory(TRemoteFileList * FileList)
         int ResolvedLinks = 0;
         for (unsigned long Index = 0; !isEOF && (Index < Count); Index++)
         {
-          File = LoadFile(&ListingPacket, NULL, L"", FileList);
-          FileList->AddFile(File);
-          if (FTerminal->IsEncryptingFiles() && // optimization
-              IsRealFile(File->FileName))
+          std::unique_ptr<TRemoteFile> AFile(LoadFile(&ListingPacket, NULL, L"", FileList));
+          TRemoteFile * File = AFile.get();
+          if (FTerminal->IsValidFile(File))
           {
-            UnicodeString FullFileName = UnixExcludeTrailingBackslash(File->FullFileName);
-            UnicodeString FileName = UnixExtractFileName(FTerminal->DecryptFileName(FullFileName, false, false));
-            if (File->FileName != FileName)
+            FileList->AddFile(AFile.release());
+            if (FTerminal->IsEncryptingFiles() && // optimization
+                IsRealFile(File->FileName))
             {
-              File->SetEncrypted();
+              UnicodeString FullFileName = UnixExcludeTrailingBackslash(File->FullFileName);
+              UnicodeString FileName = UnixExtractFileName(FTerminal->DecryptFileName(FullFileName, false, false));
+              if (File->FileName != FileName)
+              {
+                File->SetEncrypted();
+              }
+              File->FileName = FileName;
             }
-            File->FileName = FileName;
-          }
-          if (FTerminal->Configuration->ActualLogProtocol >= 1)
-          {
-            FTerminal->LogEvent(FORMAT(L"Read file '%s' from listing", (File->FileName)));
-          }
-          if (File->LinkedFile != NULL)
-          {
-            ResolvedLinks++;
-          }
-          if (File->IsParentDirectory)
-          {
-            HasParentDirectory = true;
-          }
-          Total++;
+            if (FTerminal->Configuration->ActualLogProtocol >= 1)
+            {
+              FTerminal->LogEvent(FORMAT(L"Read file '%s' from listing", (File->FileName)));
+            }
+            if (File->LinkedFile != NULL)
+            {
+              ResolvedLinks++;
+            }
+            if (File->IsParentDirectory)
+            {
+              HasParentDirectory = true;
+            }
+            Total++;
 
-          if (Total % 10 == 0)
-          {
-            FTerminal->DoReadDirectoryProgress(Total, ResolvedLinks, isEOF);
-            if (isEOF)
+            if (Total % 10 == 0)
             {
-              FTerminal->LogEvent(L"Listing directory cancelled.");
-              FTerminal->DoReadDirectoryProgress(-2, 0, isEOF);
+              FTerminal->DoReadDirectoryProgress(Total, ResolvedLinks, isEOF);
+              if (isEOF)
+              {
+                FTerminal->LogEvent(L"Listing directory cancelled.");
+                FTerminal->DoReadDirectoryProgress(-2, 0, isEOF);
+              }
             }
           }
         }

+ 7 - 0
source/core/Terminal.cpp

@@ -8307,6 +8307,13 @@ UnicodeString TTerminal::UploadPublicKey(const UnicodeString & FileName)
   return Result;
 }
 //---------------------------------------------------------------------------
+bool TTerminal::IsValidFile(TRemoteFile * File)
+{
+  return
+    !File->FileName.IsEmpty() &&
+    (IsUnixRootPath(File->FileName) || UnixExtractFileDir(File->FileName).IsEmpty());
+}
+//---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 __fastcall TSecondaryTerminal::TSecondaryTerminal(TTerminal * MainTerminal,
   TSessionData * ASessionData, TConfiguration * Configuration, const UnicodeString & Name) :

+ 1 - 0
source/core/Terminal.h

@@ -487,6 +487,7 @@ protected:
     const UnicodeString & DestFullName, const TRemoteFile * File, const TCopyParamType * CopyParam, int Attrs);
   void __fastcall UpdateTargetTime(HANDLE Handle, TDateTime Modification, TDSTMode DSTMode);
   TRemoteFile * CheckRights(const UnicodeString & EntryType, const UnicodeString & FileName, bool & WrongRights);
+  bool IsValidFile(TRemoteFile * File);
 
   UnicodeString __fastcall EncryptFileName(const UnicodeString & Path, bool EncryptNewFiles);
   UnicodeString __fastcall DecryptFileName(const UnicodeString & Path, bool DecryptFullPath, bool DontCache);