Explorar o código

Bug 1747: Consider size of linked file when transferring/synchronizing symbolic link

https://winscp.net/tracker/1747

Source commit: e58dad331f8294c191d16fd8472cb7ad02809fa5
Martin Prikryl %!s(int64=6) %!d(string=hai) anos
pai
achega
8b0a158bb9

+ 11 - 10
source/core/RemoteFiles.cpp

@@ -970,21 +970,12 @@ void __fastcall TRemoteFile::SetType(wchar_t AType)
   FIsSymLink = ((wchar_t)towupper(FType) == FILETYPE_SYMLINK);
 }
 //---------------------------------------------------------------------------
-TRemoteFile * __fastcall TRemoteFile::GetLinkedFile()
+const TRemoteFile * __fastcall TRemoteFile::GetLinkedFile() const
 {
   // do not call FindLinkedFile as it would be called repeatedly for broken symlinks
   return FLinkedFile;
 }
 //---------------------------------------------------------------------------
-void __fastcall TRemoteFile::SetLinkedFile(TRemoteFile * value)
-{
-  if (FLinkedFile != value)
-  {
-    if (FLinkedFile) delete FLinkedFile;
-    FLinkedFile = value;
-  }
-}
-//---------------------------------------------------------------------------
 bool __fastcall TRemoteFile::GetBrokenLink()
 {
   DebugAssert(Terminal);
@@ -1412,6 +1403,16 @@ void __fastcall TRemoteFile::FindLinkedFile()
   }
 }
 //---------------------------------------------------------------------------
+const TRemoteFile * __fastcall TRemoteFile::Resolve() const
+{
+  const TRemoteFile * Result = this;
+  while (Result->LinkedFile != NULL)
+  {
+    Result = Result->LinkedFile;
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 UnicodeString __fastcall TRemoteFile::GetListingStr()
 {
   // note that ModificationStr is longer than 12 for mfFull

+ 3 - 3
source/core/RemoteFiles.h

@@ -107,8 +107,7 @@ private:
   int __fastcall GetAttr();
   bool __fastcall GetBrokenLink();
   bool __fastcall GetIsDirectory() const;
-  TRemoteFile * __fastcall GetLinkedFile();
-  void __fastcall SetLinkedFile(TRemoteFile * value);
+  const TRemoteFile * __fastcall GetLinkedFile() const;
   UnicodeString __fastcall GetModificationStr();
   void __fastcall SetModification(const TDateTime & value);
   void __fastcall SetListingStr(UnicodeString value);
@@ -144,6 +143,7 @@ public:
   bool __fastcall IsTimeShiftingApplicable();
   void __fastcall Complete();
   void __fastcall SetEncrypted();
+  const TRemoteFile * __fastcall Resolve() const;
 
   static bool __fastcall IsTimeShiftingApplicable(TModificationFmt ModificationFmt);
   static void __fastcall ShiftTimeInSeconds(TDateTime & DateTime, TModificationFmt ModificationFmt, __int64 Seconds);
@@ -165,7 +165,7 @@ public:
   __property TDateTime LastAccess = { read = FLastAccess, write = FLastAccess };
   __property bool IsSymLink = { read = FIsSymLink };
   __property bool IsDirectory = { read = GetIsDirectory };
-  __property TRemoteFile * LinkedFile = { read = GetLinkedFile, write = SetLinkedFile };
+  __property const TRemoteFile * LinkedFile = { read = GetLinkedFile };
   __property UnicodeString LinkTo = { read = FLinkTo, write = FLinkTo };
   __property UnicodeString ListingStr = { read = GetListingStr, write = SetListingStr };
   __property TRights * Rights = { read = FRights, write = SetRights };

+ 4 - 4
source/core/SftpFileSystem.cpp

@@ -4501,7 +4501,7 @@ void __fastcall TSFTPFileSystem::Source(
       if (DestFileExists)
       {
         FTerminal->LogEvent(FORMAT(L"File exists: %s", (FTerminal->GetRemoteFileInfo(File))));
-        OpenParams.DestFileSize = File->Size;
+        OpenParams.DestFileSize = File->Resolve()->Size;
         FileParams.DestSize = OpenParams.DestFileSize;
         FileParams.DestTimestamp = File->Modification;
         DestRights = *File->Rights;
@@ -4544,7 +4544,7 @@ void __fastcall TSFTPFileSystem::Source(
         FTerminal->LogEvent(L"Checking existence of partially transferred file.");
         if (RemoteFileExists(DestPartialFullName, &File))
         {
-          ResumeOffset = File->Size;
+          ResumeOffset = File->Resolve()->Size; // Though partial file should not be symlink
           delete File;
           File = NULL;
 
@@ -4983,7 +4983,7 @@ int __fastcall TSFTPFileSystem::SFTPOpenRemote(void * AOpenParams, void * /*Para
           UnicodeString RealFileName = LocalCanonify(OpenParams->RemoteFileName);
           ReadFile(RealFileName, File);
           DebugAssert(File);
-          OpenParams->DestFileSize = File->Size;
+          OpenParams->DestFileSize = File->Size; // Resolve symlinks?
           if (OpenParams->FileParams != NULL)
           {
             OpenParams->FileParams->DestTimestamp = File->Modification;
@@ -5380,7 +5380,7 @@ void __fastcall TSFTPFileSystem::Sink(
       {
         TSFTPPacket DataPacket;
 
-        int QueueLen = int(File->Size / DownloadBlockSize(OperationProgress)) + 1;
+        int QueueLen = int(OperationProgress->TransferSize / DownloadBlockSize(OperationProgress)) + 1;
         if ((QueueLen > FTerminal->SessionData->SFTPDownloadQueue) ||
             (QueueLen < 0))
         {

+ 23 - 16
source/core/Terminal.cpp

@@ -3294,23 +3294,29 @@ void __fastcall TTerminal::LogRemoteFile(TRemoteFile * File)
   }
 }
 //---------------------------------------------------------------------------
-UnicodeString __fastcall TTerminal::FormatFileDetailsForLog(const UnicodeString & FileName, TDateTime Modification, __int64 Size)
+UnicodeString __fastcall TTerminal::FormatFileDetailsForLog(
+  const UnicodeString & FileName, TDateTime Modification, __int64 Size, const TRemoteFile * LinkedFile)
 {
   UnicodeString Result;
   // optimization
   if (Log->Logging)
   {
     Result = FORMAT(L"'%s' [%s] [%s]", (FileName, (Modification != TDateTime() ? StandardTimestamp(Modification) : UnicodeString(L"n/a")), IntToStr(Size)));
+    if (LinkedFile != NULL)
+    {
+      LinkedFile = LinkedFile->Resolve(); // in case it's symlink to symlink
+      Result += FORMAT(L" - Link to: %s", (FormatFileDetailsForLog(LinkedFile->FileName, LinkedFile->Modification, LinkedFile->Size, NULL)));
+    }
   }
   return Result;
 }
 //---------------------------------------------------------------------------
-void __fastcall TTerminal::LogFileDetails(const UnicodeString & FileName, TDateTime Modification, __int64 Size)
+void __fastcall TTerminal::LogFileDetails(const UnicodeString & FileName, TDateTime Modification, __int64 Size, const TRemoteFile * LinkedFile)
 {
   // optimization
   if (Log->Logging)
   {
-    LogEvent(FORMAT("File: %s", (FormatFileDetailsForLog(FileName, Modification, Size))));
+    LogEvent(FORMAT("File: %s", (FormatFileDetailsForLog(FileName, Modification, Size, LinkedFile))));
   }
 }
 //---------------------------------------------------------------------------
@@ -3399,7 +3405,7 @@ TRemoteFileList * __fastcall TTerminal::ReadDirectoryListing(UnicodeString Direc
         {
           TRemoteFile * File = FileList->Files[Index];
           TFileMasks::TParams Params;
-          Params.Size = File->Size;
+          Params.Size = File->Resolve()->Size;
           Params.Modification = File->Modification;
           // Have to use UnicodeString(), instead of L"", as with that
           // overload with (UnicodeString, bool, bool, TParams*) wins
@@ -4317,7 +4323,7 @@ void __fastcall TTerminal::CalculateFileSize(UnicodeString FileName,
     }
     else
     {
-      AParams->Size += File->Size;
+      AParams->Size += File->Resolve()->Size;
 
       AParams->Stats->Files++;
     }
@@ -5167,7 +5173,7 @@ bool __fastcall TTerminal::DoAllowRemoteFileTransfer(
   const TRemoteFile * File, const TCopyParamType * CopyParam, bool DisallowTemporaryTransferFiles)
 {
   TFileMasks::TParams MaskParams;
-  MaskParams.Size = File->Size;
+  MaskParams.Size = File->Resolve()->Size;
   MaskParams.Modification = File->Modification;
   UnicodeString FullRemoteFileName = UnixExcludeTrailingBackslash(File->FullFileName);
   UnicodeString BaseFileName = GetBaseFileName(FullRemoteFileName);
@@ -5772,7 +5778,7 @@ void __fastcall TTerminal::DoSynchronizeCollectFile(const UnicodeString FileName
       ChecklistItem->Remote.Directory = Data->RemoteDirectory;
       ChecklistItem->Remote.Modification = File->Modification;
       ChecklistItem->Remote.ModificationFmt = File->ModificationFmt;
-      ChecklistItem->Remote.Size = File->Size;
+      ChecklistItem->Remote.Size = File->Resolve()->Size;
 
       bool Modified = false;
       bool New = false;
@@ -5863,13 +5869,13 @@ void __fastcall TTerminal::DoSynchronizeCollectFile(const UnicodeString FileName
                 (FormatFileDetailsForLog(LocalData->Info.Directory + LocalData->Info.FileName,
                    LocalData->Info.Modification, LocalData->Info.Size),
                  FormatFileDetailsForLog(FullRemoteFileName,
-                   File->Modification, File->Size))));
+                   File->Modification, File->Size, File->LinkedFile))));
             }
 
             if (Modified)
             {
               LogEvent(FORMAT(L"Remote file %s is modified comparing to local file %s",
-                (FormatFileDetailsForLog(FullRemoteFileName, File->Modification, File->Size),
+                (FormatFileDetailsForLog(FullRemoteFileName, File->Modification, File->Size, File->LinkedFile),
                  FormatFileDetailsForLog(LocalData->Info.Directory + LocalData->Info.FileName,
                    LocalData->Info.Modification, LocalData->Info.Size))));
             }
@@ -5888,7 +5894,7 @@ void __fastcall TTerminal::DoSynchronizeCollectFile(const UnicodeString FileName
         {
           ChecklistItem->Local.Directory = Data->LocalDirectory;
           LogEvent(FORMAT(L"Remote file %s is new",
-            (FormatFileDetailsForLog(FullRemoteFileName, File->Modification, File->Size))));
+            (FormatFileDetailsForLog(FullRemoteFileName, File->Modification, File->Size, File->LinkedFile))));
         }
       }
 
@@ -5937,7 +5943,7 @@ void __fastcall TTerminal::DoSynchronizeCollectFile(const UnicodeString FileName
   else
   {
     LogEvent(0, FORMAT(L"Remote file %s excluded from synchronization",
-      (FormatFileDetailsForLog(FullRemoteFileName, File->Modification, File->Size))));
+      (FormatFileDetailsForLog(FullRemoteFileName, File->Modification, File->Size, File->LinkedFile))));
   }
 }
 //---------------------------------------------------------------------------
@@ -6277,7 +6283,7 @@ void __fastcall TTerminal::FileFind(UnicodeString FileName,
     }
 
     TFileMasks::TParams MaskParams;
-    MaskParams.Size = File->Size;
+    MaskParams.Size = File->Resolve()->Size;
     MaskParams.Modification = File->Modification;
 
     UnicodeString FullFileName = UnixExcludeTrailingBackslash(File->FullFileName);
@@ -7361,11 +7367,11 @@ void __fastcall TTerminal::Sink(
 
   if (CopyParam->SkipTransfer(FileName, File->IsDirectory))
   {
-    OperationProgress->AddSkippedFileSize(File->Size);
+    OperationProgress->AddSkippedFileSize(File->Resolve()->Size);
     throw ESkipFile();
   }
 
-  LogFileDetails(FileName, File->Modification, File->Size);
+  LogFileDetails(FileName, File->Modification, File->Size, File->LinkedFile);
 
   OperationProgress->SetFile(FileName);
 
@@ -7428,14 +7434,15 @@ void __fastcall TTerminal::Sink(
 
     // Will we use ASCII or BINARY file transfer?
     UnicodeString BaseFileName = GetBaseFileName(FileName);
+    const TRemoteFile * UltimateFile = File->Resolve();
     TFileMasks::TParams MaskParams;
-    MaskParams.Size = File->Size;
+    MaskParams.Size = UltimateFile->Size;
     MaskParams.Modification = File->Modification;
     SelectTransferMode(BaseFileName, osRemote, CopyParam, MaskParams);
 
     // Suppose same data size to transfer as to write
     // (not true with ASCII transfer)
-    __int64 TransferSize = File->Size;
+    __int64 TransferSize = UltimateFile->Size;
     OperationProgress->SetLocalSize(TransferSize);
     if (IsFileEncrypted(FileName))
     {

+ 3 - 2
source/core/Terminal.h

@@ -419,8 +419,9 @@ protected:
   UnicodeString __fastcall DecryptPassword(const RawByteString & Password);
   UnicodeString __fastcall GetRemoteFileInfo(TRemoteFile * File);
   void __fastcall LogRemoteFile(TRemoteFile * File);
-  UnicodeString __fastcall FormatFileDetailsForLog(const UnicodeString & FileName, TDateTime Modification, __int64 Size);
-  void __fastcall LogFileDetails(const UnicodeString & FileName, TDateTime Modification, __int64 Size);
+  UnicodeString __fastcall FormatFileDetailsForLog(
+    const UnicodeString & FileName, TDateTime Modification, __int64 Size, const TRemoteFile * LinkedFile = NULL);
+  void __fastcall LogFileDetails(const UnicodeString & FileName, TDateTime Modification, __int64 Size, const TRemoteFile * LinkedFile = NULL);
   void __fastcall LogFileDone(TFileOperationProgressType * OperationProgress, const UnicodeString & DestFileName);
   void __fastcall LogTotalTransferDetails(
     const UnicodeString TargetDir, const TCopyParamType * CopyParam,