Browse Source

Merge branch 'master' into dev

Conflicts:
	source/WinSCP.cbproj

Source commit: 5bff9a13cd78cc85fbb31c5580b58e8582bb2240
Martin Prikryl 9 years ago
parent
commit
bfc9a27fa4

+ 2 - 2
deployment/winscpsetup.iss

@@ -485,12 +485,12 @@ begin
       // but it will be useful, if downgrading from future version with a different major version.
       if InstalledMajor <> ExistingMajor then
       begin
-        Log('Installed extension has different major version, allowing installation, and will require restart, if it is locked.')
+        Log('Existing extension has different major version, allowing installation, and will require restart, if it is locked.')
       end
         else
       begin
         // 1.1 uses Ansi encoding, and is incompatible with 1.2 and newer which uses Unicode
-        Log('Installed extension is 1.1 or older, allowing installation, and will require restart, if it is locked.');
+        Log('Existing extension is 1.1 or older, allowing installation, and will require restart, if it is locked.');
       end;
 
       Result := True;

+ 21 - 10
dotnet/Session.cs

@@ -218,19 +218,13 @@ namespace WinSCP
                         {
                             if (_error.Count > 0)
                             {
-                                string[] error = new string[_error.Count];
-                                _error.CopyTo(error, 0);
-                                logExplanation =
-                                    string.Format(
-                                        CultureInfo.CurrentCulture, "Error output was \"{0}\". ", string.Join(Environment.NewLine, error));
+                                logExplanation = GetErrorOutputMessage();
                             }
                             else if (Output.Count > 0)
                             {
-                                string[] output = new string[Output.Count];
-                                Output.CopyTo(output, 0);
                                 logExplanation =
                                     string.Format(
-                                        CultureInfo.CurrentCulture, "Output was \"{0}\". ", string.Join(Environment.NewLine, output));
+                                        CultureInfo.CurrentCulture, "Output was \"{0}\". ", ListToString(Output));
                             }
                             else
                             {
@@ -296,7 +290,7 @@ namespace WinSCP
                     }
 
                 }
-                catch(Exception e)
+                catch (Exception e)
                 {
                     Logger.WriteLine("Exception: {0}", e);
                     Cleanup();
@@ -305,6 +299,24 @@ namespace WinSCP
             }
         }
 
+        internal string GetErrorOutputMessage()
+        {
+            string result = null;
+            if (_error.Count > 0)
+            {
+                result = string.Format(CultureInfo.CurrentCulture, "Error output was \"{0}\". ", ListToString(_error));
+            }
+            return result;
+        }
+
+        private static string ListToString(StringCollection list)
+        {
+            string[] error = new string[list.Count];
+            list.CopyTo(error, 0);
+            string s = string.Join(Environment.NewLine, error);
+            return s;
+        }
+
         public string ScanFingerprint(SessionOptions sessionOptions)
         {
             using (Logger.CreateCallstackAndLock())
@@ -341,7 +353,6 @@ namespace WinSCP
                         CheckForTimeout();
                     }
 
-
                     string output = string.Join(Environment.NewLine, new List<string>(Output).ToArray());
                     if (_process.ExitCode == 0)
                     {

+ 1 - 0
dotnet/internal/ExeSessionProcess.cs

@@ -267,6 +267,7 @@ namespace WinSCP
                 while (!AbortedOrExited())
                 {
                     _logger.WriteLineLevel(1, "Waiting for request event");
+                    // Keep in sync with a delay in SessionLogReader.DoRead
                     if (_requestEvent.WaitOne(100, false))
                     {
                         _logger.WriteLineLevel(1, "Got request event");

+ 12 - 2
dotnet/internal/SessionLogReader.cs

@@ -3,6 +3,7 @@ using System.Diagnostics;
 using System.IO;
 using System.Xml;
 using System.Text;
+using System.Threading;
 
 namespace WinSCP
 {
@@ -122,7 +123,7 @@ namespace WinSCP
 
                     // We hope this code is not needed anymore.
                     // keeping it just in case the XmlLogReader by passes
-                    // our override of PatientFileStream.Read uing other read method.
+                    // our override of PatientFileStream.Read using other read method.
 #if !DEBUG
                     if (!_closed)
                     {
@@ -138,7 +139,16 @@ namespace WinSCP
                         // check if the the root cause was session abort
                         Session.CheckForTimeout();
                         LogContents();
-                        throw new SessionLocalException(Session, "Error parsing session log file", e);
+                        string message = "Error parsing session log file";
+                        // This is possibly a race condition, as we may not have processed the event with the error yet
+                        // The ExeSessionProcess loops every 100ms
+                        Thread.Sleep(200);
+                        string s = Session.GetErrorOutputMessage();
+                        if (!string.IsNullOrEmpty(s))
+                        {
+                            message += " - " + s;
+                        }
+                        throw new SessionLocalException(Session, message, e);
                     }
                 }
 

+ 2 - 2
dotnet/properties/AssemblyInfo.cs

@@ -19,8 +19,8 @@ using System.Runtime.InteropServices;
 // The following GUID is for the ID of the typelib if this project is exposed to COM
 [assembly: Guid("a0b93468-d98a-4845-a234-8076229ad93f")]
 
-[assembly: AssemblyVersion("1.3.4.0")]
-[assembly: AssemblyFileVersion("1.3.4.0")]
+[assembly: AssemblyVersion("1.3.5.0")]
+[assembly: AssemblyFileVersion("1.3.5.0")]
 [assembly: AssemblyInformationalVersionAttribute("5.10.0.0")]
 
 [assembly: CLSCompliant(true)]

+ 2 - 2
source/Console.cbproj

@@ -43,10 +43,10 @@
 		<ProjectType>CppConsoleApplication</ProjectType>
 		<SanitizedProjectName>Console</SanitizedProjectName>
 		<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
-		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=4.3.0.0;InternalName=console;LegalCopyright=(c) 2000-2018 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.10.0.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
+		<VerInfo_Keys>CompanyName=Martin Prikryl;FileDescription=Console interface for WinSCP;FileVersion=4.4.0.0;InternalName=console;LegalCopyright=(c) 2000-2018 Martin Prikryl;LegalTrademarks=;OriginalFilename=winscp.com;ProductName=WinSCP;ProductVersion=5.10.0.0;ReleaseType=stable;WWW=https://winscp.net/</VerInfo_Keys>
 		<VerInfo_Locale>1033</VerInfo_Locale>
 		<VerInfo_MajorVer>4</VerInfo_MajorVer>
-		<VerInfo_MinorVer>3</VerInfo_MinorVer>
+		<VerInfo_MinorVer>4</VerInfo_MinorVer>
 	</PropertyGroup>
 	<PropertyGroup Condition="'$(Cfg_1)'!=''">
 		<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>

+ 32 - 14
source/core/SessionInfo.cpp

@@ -1339,6 +1339,7 @@ void __fastcall TActionLog::Init(TSessionUI * UI, TSessionData * SessionData,
   FCurrentFileName = L"";
   FLogging = false;
   FClosed = false;
+  FFailed = false;
   FPendingActions = new TList();
   FIndent = L"  ";
   FInGroup = false;
@@ -1371,30 +1372,47 @@ void __fastcall TActionLog::Add(const UnicodeString & Line)
       try
       {
         UTF8String UtfLine = UTF8String(Line);
-        fwrite(UtfLine.c_str(), 1, UtfLine.Length(), (FILE *)FFile);
-        fwrite("\n", 1, 1, (FILE *)FFile);
+        size_t Written =
+          fwrite(UtfLine.c_str(), 1, UtfLine.Length(), (FILE *)FFile);
+        if (Written != static_cast<size_t>(UtfLine.Length()))
+        {
+          throw ECRTExtException(L"");
+        }
+        #ifdef _DEBUG
+        #endif
+        Written =
+          fwrite("\n", 1, 1, (FILE *)FFile);
+        if (Written != 1)
+        {
+          throw ECRTExtException(L"");
+        }
       }
       catch (Exception &E)
       {
         FCriticalSection->Release();
 
-        // We failed logging, turn it off and notify user.
-        FConfiguration->LogActions = false;
-        if (FConfiguration->LogActionsRequired)
-        {
-          throw EFatal(&E, LoadStr(LOG_FATAL_ERROR));
-        }
-        else
+        // avoid endless loop when trying to close tags when closing log, when logging has failed
+        if (!FFailed)
         {
-          try
+          FFailed = true;
+          // We failed logging, turn it off and notify user.
+          FConfiguration->LogActions = false;
+          if (FConfiguration->LogActionsRequired)
           {
-            throw ExtException(&E, LoadStr(LOG_GEN_ERROR));
+            throw EFatal(&E, LoadStr(LOG_FATAL_ERROR));
           }
-          catch (Exception &E)
+          else
           {
-            if (FUI != NULL)
+            try
+            {
+              throw ExtException(&E, LoadStr(LOG_GEN_ERROR));
+            }
+            catch (Exception &E)
             {
-              FUI->HandleExtendedException(&E);
+              if (FUI != NULL)
+              {
+                FUI->HandleExtendedException(&E);
+              }
             }
           }
         }

+ 1 - 0
source/core/SessionInfo.h

@@ -331,6 +331,7 @@ private:
   TSessionUI * FUI;
   TSessionData * FSessionData;
   TList * FPendingActions;
+  bool FFailed;
   bool FClosed;
   bool FInGroup;
   UnicodeString FIndent;

+ 50 - 2
source/packages/filemng/DirView.pas

@@ -1610,6 +1610,36 @@ begin
   end;
 end; {GetAttrString}
 
+type
+  TSHGetFileInfoThread = class(TCompThread)
+  private
+    FPIDL: PItemIDList;
+    FFileAttributes: DWORD;
+    FFlags: UINT;
+    FFileInfo: TSHFileInfo;
+
+  protected
+    procedure Execute; override;
+
+  public
+    constructor Create(PIDL: PItemIDList; FileAttributes: DWORD; Flags: UINT);
+
+    property FileInfo: TSHFileInfo read FFileInfo;
+  end;
+
+constructor TSHGetFileInfoThread.Create(PIDL: PItemIDList; FileAttributes: DWORD; Flags: UINT);
+begin
+  inherited Create(True);
+  FPIDL := PIDL;
+  FFileAttributes := FileAttributes;
+  FFlags := Flags;
+end;
+
+procedure TSHGetFileInfoThread.Execute;
+begin
+  SHGetFileInfo(PChar(FPIDL), FFileAttributes, FFileInfo, SizeOf(FFileInfo), FFlags);
+end;
+
 procedure TDirView.GetDisplayData(Item: TListItem; FetchIcon: Boolean);
 var
   FileInfo: TShFileInfo;
@@ -1621,6 +1651,7 @@ var
   Eaten: ULONG;
   shAttr: ULONG;
   FileIconForName, FullName: string;
+  Thread: TSHGetFileInfoThread;
 begin
   Assert(Assigned(Item) and Assigned(Item.Data));
   with PFileRec(Item.Data)^ do
@@ -1726,8 +1757,25 @@ begin
             end;
             if (not ForceByName) and Assigned(PIDL) then
             begin
-              SHGetFileInfo(PChar(PIDL), FILE_ATTRIBUTE_NORMAL, FileInfo, SizeOf(FileInfo),
-                SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX or SHGFI_PIDL)
+              // Files with PIDL are typically .exe files.
+              // It may take long to retrieve an icon from exe file.
+              Thread :=
+                TSHGetFileInfoThread.Create(
+                  PIDL, FILE_ATTRIBUTE_NORMAL, SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX or SHGFI_PIDL);
+              Thread.Resume;
+              if Thread.WaitFor(MSecsPerSec div 4) then
+              begin
+                FileInfo := Thread.FileInfo;
+                Thread.Free;
+              end
+                else
+              begin
+                // There's a chance for memory leak, if thread is terminated
+                // between WaitFor() and this line
+                Thread.FreeOnTerminate := True;
+                FileInfo.szTypeName[0] := #0;
+                FileInfo.iIcon := DefaultExeIcon;
+              end;
             end
               else
             begin

+ 1 - 1
source/packages/filemng/DriveView.pas

@@ -570,7 +570,7 @@ begin
        ((wParam = {DBT_CONFIGCHANGED} $0018) or (wParam = {DBT_DEVICEARRIVAL} $8000) or
           (wParam = {DBT_DEVICEREMOVECOMPLETE} $8004)) then
     begin
-      // Delay refresing drives for a sec.
+      // Delay refreshing drives for a sec.
       // Particularly with CD/DVD drives, if we query display name
       // immediately after receiving DBT_DEVICEARRIVAL, we do not get media label.
       // Actually one sec does not help usually, but we do not want to wait any longer,