Browse Source

Bug 1093: Detect symbolic link loops when finding files (improved to cover more complex symlink structures)

Source commit: 276a770a11ee8300f0e98df6e2b27f78e65e27ec
Martin Prikryl 9 years ago
parent
commit
c9a1e7a750
2 changed files with 23 additions and 20 deletions
  1. 22 19
      source/core/Terminal.cpp
  2. 1 1
      source/core/Terminal.h

+ 22 - 19
source/core/Terminal.cpp

@@ -40,7 +40,7 @@ class TLoopDetector
 public:
 public:
   __fastcall TLoopDetector();
   __fastcall TLoopDetector();
   void __fastcall RecordVisitedDirectory(const UnicodeString & Directory);
   void __fastcall RecordVisitedDirectory(const UnicodeString & Directory);
-  bool __fastcall IsUnvisitedDirectory(const TRemoteFile * File);
+  bool __fastcall IsUnvisitedDirectory(const UnicodeString & Directory);
 
 
 private:
 private:
   std::unique_ptr<TStringList> FVisitedDirectories;
   std::unique_ptr<TStringList> FVisitedDirectories;
@@ -57,21 +57,9 @@ void __fastcall TLoopDetector::RecordVisitedDirectory(const UnicodeString & Dire
   FVisitedDirectories->Add(VisitedDirectory);
   FVisitedDirectories->Add(VisitedDirectory);
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-bool __fastcall TLoopDetector::IsUnvisitedDirectory(const TRemoteFile * File)
+bool __fastcall TLoopDetector::IsUnvisitedDirectory(const UnicodeString & Directory)
 {
 {
-  DebugAssert(File->IsDirectory);
-  UnicodeString Directory = UnixExcludeTrailingBackslash(File->FullFileName);
   bool Result = (FVisitedDirectories->IndexOf(Directory) < 0);
   bool Result = (FVisitedDirectories->IndexOf(Directory) < 0);
-  if (Result)
-  {
-    if (File->IsSymLink)
-    {
-      UnicodeString BaseDirectory = UnixExtractFileDir(Directory);
-      UnicodeString SymlinkDirectory =
-        UnixExcludeTrailingBackslash(AbsolutePath(BaseDirectory, File->LinkTo));
-      Result = (FVisitedDirectories->IndexOf(SymlinkDirectory) < 0);
-    }
-  }
 
 
   if (Result)
   if (Result)
   {
   {
@@ -95,6 +83,7 @@ struct TFilesFindParams
   TFindingFileEvent OnFindingFile;
   TFindingFileEvent OnFindingFile;
   bool Cancel;
   bool Cancel;
   TLoopDetector LoopDetector;
   TLoopDetector LoopDetector;
+  UnicodeString RealDirectory;
 };
 };
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 TCalculateSizeStats::TCalculateSizeStats()
 TCalculateSizeStats::TCalculateSizeStats()
@@ -5373,21 +5362,32 @@ void __fastcall TTerminal::FileFind(UnicodeString FileName,
 
 
       if (File->IsDirectory)
       if (File->IsDirectory)
       {
       {
-        if (!AParams->LoopDetector.IsUnvisitedDirectory(File))
+        UnicodeString RealDirectory;
+        if (!File->IsSymLink || File->LinkTo.IsEmpty())
+        {
+          RealDirectory = UnixIncludeTrailingBackslash(AParams->RealDirectory) + File->FileName;
+        }
+        else
+        {
+          RealDirectory = ::AbsolutePath(AParams->RealDirectory, File->LinkTo);
+        }
+
+        if (!AParams->LoopDetector.IsUnvisitedDirectory(RealDirectory))
         {
         {
-          LogEvent(FORMAT(L"Already searched \"%s\" directory, link loop detected", (FullFileName)));
+          LogEvent(FORMAT(L"Already searched \"%s\" directory (real path \"%s\"), link loop detected", (FullFileName, RealDirectory)));
         }
         }
         else
         else
         {
         {
-          DoFilesFind(FullFileName, *AParams);
+          DoFilesFind(FullFileName, *AParams, RealDirectory);
         }
         }
       }
       }
     }
     }
   }
   }
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-void __fastcall TTerminal::DoFilesFind(UnicodeString Directory, TFilesFindParams & Params)
+void __fastcall TTerminal::DoFilesFind(UnicodeString Directory, TFilesFindParams & Params, UnicodeString RealDirectory)
 {
 {
+  LogEvent(FORMAT(L"Searching directory \"%s\" (real path \"%s\")", (Directory, RealDirectory)));
   Params.OnFindingFile(this, Directory, Params.Cancel);
   Params.OnFindingFile(this, Directory, Params.Cancel);
   if (!Params.Cancel)
   if (!Params.Cancel)
   {
   {
@@ -5396,12 +5396,15 @@ void __fastcall TTerminal::DoFilesFind(UnicodeString Directory, TFilesFindParams
     // of the directory listing, so we at least reset the handler in
     // of the directory listing, so we at least reset the handler in
     // FileFind
     // FileFind
     FOnFindingFile = Params.OnFindingFile;
     FOnFindingFile = Params.OnFindingFile;
+    UnicodeString PrevRealDirectory = Params.RealDirectory;
     try
     try
     {
     {
+      Params.RealDirectory = RealDirectory;
       ProcessDirectory(Directory, FileFind, &Params, false, true);
       ProcessDirectory(Directory, FileFind, &Params, false, true);
     }
     }
     __finally
     __finally
     {
     {
+      Params.RealDirectory = PrevRealDirectory;
       FOnFindingFile = NULL;
       FOnFindingFile = NULL;
     }
     }
   }
   }
@@ -5418,7 +5421,7 @@ void __fastcall TTerminal::FilesFind(UnicodeString Directory, const TFileMasks &
 
 
   Params.LoopDetector.RecordVisitedDirectory(Directory);
   Params.LoopDetector.RecordVisitedDirectory(Directory);
 
 
-  DoFilesFind(Directory, Params);
+  DoFilesFind(Directory, Params, Directory);
 }
 }
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 void __fastcall TTerminal::SpaceAvailable(const UnicodeString Path,
 void __fastcall TTerminal::SpaceAvailable(const UnicodeString Path,

+ 1 - 1
source/core/Terminal.h

@@ -338,7 +338,7 @@ protected:
     UnicodeString Name, UnicodeString Instructions, UnicodeString Prompt, bool Echo,
     UnicodeString Name, UnicodeString Instructions, UnicodeString Prompt, bool Echo,
     int MaxLen, UnicodeString & Result);
     int MaxLen, UnicodeString & Result);
   void __fastcall FileFind(UnicodeString FileName, const TRemoteFile * File, void * Param);
   void __fastcall FileFind(UnicodeString FileName, const TRemoteFile * File, void * Param);
-  void __fastcall DoFilesFind(UnicodeString Directory, TFilesFindParams & Params);
+  void __fastcall DoFilesFind(UnicodeString Directory, TFilesFindParams & Params, UnicodeString RealDirectory);
   bool __fastcall DoCreateLocalFile(const UnicodeString FileName,
   bool __fastcall DoCreateLocalFile(const UnicodeString FileName,
     TFileOperationProgressType * OperationProgress, HANDLE * AHandle,
     TFileOperationProgressType * OperationProgress, HANDLE * AHandle,
     bool NoConfirmation);
     bool NoConfirmation);