浏览代码

Merge branch 'master' into dev

Conflicts:
	source/WinSCP.cbproj

Source commit: bc9aa03eabf5fbbeb6d37fac9f5d377944b7331d
Martin Prikryl 9 年之前
父节点
当前提交
4f6e39b7f0
共有 4 个文件被更改,包括 183 次插入144 次删除
  1. 47 28
      dotnet/Session.cs
  2. 2 2
      dotnet/properties/AssemblyInfo.cs
  3. 2 2
      source/Console.cbproj
  4. 132 112
      source/core/RemoteFiles.cpp

+ 47 - 28
dotnet/Session.cs

@@ -422,7 +422,7 @@ namespace WinSCP
             }
         }
 
-        private IEnumerable<RemoteFileInfo> DoEnumerateRemoteFiles(string path, Regex regex, EnumerationOptions options)
+        private IEnumerable<RemoteFileInfo> DoEnumerateRemoteFiles(string path, Regex regex, EnumerationOptions options, bool throwReadErrors)
         {
             bool allDirectories = ((options & EnumerationOptions.AllDirectories) == EnumerationOptions.AllDirectories);
             bool matchDirectories = ((options & EnumerationOptions.MatchDirectories) == EnumerationOptions.MatchDirectories);
@@ -438,47 +438,66 @@ namespace WinSCP
                 throw new ArgumentException("Cannot combine enumeration option EnumerateDirectories with MatchDirectories");
             }
 
-            // Need to use guarded method for the listing, see a comment in EnumerateRemoteFiles
-            RemoteDirectoryInfo directoryInfo = ListDirectory(path);
+            RemoteDirectoryInfo directoryInfo;
 
-            foreach (RemoteFileInfo fileInfo in directoryInfo.Files)
+            try
             {
-                if (!fileInfo.IsThisDirectory && !fileInfo.IsParentDirectory)
+                // Need to use guarded method for the listing, see a comment in EnumerateRemoteFiles
+                directoryInfo = ListDirectory(path);
+            }
+            catch (SessionRemoteException e)
+            {
+                if (throwReadErrors)
+                {
+                    throw;
+                }
+                else
                 {
-                    bool matches = regex.IsMatch(fileInfo.Name);
+                    directoryInfo = null;
+                }
+            }
 
-                    bool enumerate;
-                    if (!fileInfo.IsDirectory)
-                    {
-                        enumerate = matches;
-                    }
-                    else
+            if (directoryInfo != null)
+            {
+                foreach (RemoteFileInfo fileInfo in directoryInfo.Files)
+                {
+                    if (!fileInfo.IsThisDirectory && !fileInfo.IsParentDirectory)
                     {
-                        if (enumerateDirectories)
-                        {
-                            enumerate = true;
-                        }
-                        else if (matchDirectories)
+                        bool matches = regex.IsMatch(fileInfo.Name);
+
+                        bool enumerate;
+                        if (!fileInfo.IsDirectory)
                         {
                             enumerate = matches;
                         }
                         else
                         {
-                            enumerate = false;
+                            if (enumerateDirectories)
+                            {
+                                enumerate = true;
+                            }
+                            else if (matchDirectories)
+                            {
+                                enumerate = matches;
+                            }
+                            else
+                            {
+                                enumerate = false;
+                            }
                         }
-                    }
 
-                    if (enumerate)
-                    {
-                        yield return fileInfo;
-                    }
+                        if (enumerate)
+                        {
+                            yield return fileInfo;
+                        }
 
 
-                    if (fileInfo.IsDirectory && allDirectories)
-                    {
-                        foreach (RemoteFileInfo fileInfo2 in DoEnumerateRemoteFiles(CombinePaths(path, fileInfo.Name), regex, options))
+                        if (fileInfo.IsDirectory && allDirectories)
                         {
-                            yield return fileInfo2;
+                            foreach (RemoteFileInfo fileInfo2 in DoEnumerateRemoteFiles(CombinePaths(path, fileInfo.Name), regex, options, false))
+                            {
+                                yield return fileInfo2;
+                            }
                         }
                     }
                 }
@@ -497,7 +516,7 @@ namespace WinSCP
 
                 Regex regex = MaskToRegex(mask);
 
-                return DoEnumerateRemoteFiles(path, regex, options);
+                return DoEnumerateRemoteFiles(path, regex, options, true);
             }
         }
 

+ 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.3.0")]
-[assembly: AssemblyFileVersion("1.3.3.0")]
+[assembly: AssemblyVersion("1.3.4.0")]
+[assembly: AssemblyFileVersion("1.3.4.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.2.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.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_Locale>1033</VerInfo_Locale>
 		<VerInfo_MajorVer>4</VerInfo_MajorVer>
-		<VerInfo_MinorVer>2</VerInfo_MinorVer>
+		<VerInfo_MinorVer>3</VerInfo_MinorVer>
 	</PropertyGroup>
 	<PropertyGroup Condition="'$(Cfg_1)'!=''">
 		<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>

+ 132 - 112
source/core/RemoteFiles.cpp

@@ -1113,13 +1113,22 @@ void __fastcall TRemoteFile::SetListingStr(UnicodeString value)
     {
       FGroup.Name = FGroup.Name + Col;
       GETCOL;
-      DebugAssert(!Col.IsEmpty());
-      // for devices etc.. there is additional column ending by comma, we ignore it
-      if (Col[Col.Length()] == L',') GETCOL;
-      ASize = StrToInt64Def(Col, -1);
-      // if it's not a number (file size) we take it as part of group name
-      // (at least on CygWin, there can be group with space in its name)
-      if (ASize < 0) Col = L" " + Col;
+      // SSH FS link like
+      // d????????? ? ? ? ? ? name
+      if ((FGroup.Name == L"?") && (Col == L"?"))
+      {
+        ASize = 0;
+      }
+      else
+      {
+        DebugAssert(!Col.IsEmpty());
+        // for devices etc.. there is additional column ending by comma, we ignore it
+        if (Col[Col.Length()] == L',') GETCOL;
+        ASize = StrToInt64Def(Col, -1);
+        // if it's not a number (file size) we take it as part of group name
+        // (at least on CygWin, there can be group with space in its name)
+        if (ASize < 0) Col = L" " + Col;
+      }
     }
     while (ASize < 0);
 
@@ -1133,142 +1142,153 @@ void __fastcall TRemoteFile::SetListingStr(UnicodeString value)
       Word Day, Month, Year, Hour, Min, Sec, P;
 
       GETCOL;
-      // format dd mmm or mmm dd ?
-      Day = (Word)StrToIntDef(Col, 0);
-      if (Day > 0)
+      // SSH FS link, see above
+      if (Col == L"?")
       {
-        DayMonthFormat = true;
         GETCOL;
+        FModificationFmt = mfNone;
+        FModification = 0;
+        FLastAccess = 0;
       }
-      Month = 0;
-      #define COL2MONTH \
-        for (Word IMonth = 0; IMonth < 12; IMonth++) \
-          if (!Col.CompareIC(EngShortMonthNames[IMonth])) { Month = IMonth; Month++; break; }
-      COL2MONTH;
-      // if the column is not known month name, it may have been "yyyy-mm-dd"
-      // for --full-time format
-      if ((Month == 0) && (Col.Length() == 10) && (Col[5] == L'-') && (Col[8] == L'-'))
+      else
       {
-        Year = (Word)Col.SubString(1, 4).ToInt();
-        Month = (Word)Col.SubString(6, 2).ToInt();
-        Day = (Word)Col.SubString(9, 2).ToInt();
-        GETCOL;
-        Hour = (Word)Col.SubString(1, 2).ToInt();
-        Min = (Word)Col.SubString(4, 2).ToInt();
-        if (Col.Length() >= 8)
-        {
-          Sec = (Word)StrToInt(Col.SubString(7, 2));
-        }
-        else
+        // format dd mmm or mmm dd ?
+        Day = (Word)StrToIntDef(Col, 0);
+        if (Day > 0)
         {
-          Sec = 0;
+          DayMonthFormat = true;
+          GETCOL;
         }
-        FModificationFmt = mfFull;
-        // skip TZ (TODO)
-        // do not trim leading space of filename
-        GETNCOL;
-      }
-      else
-      {
-        // or it may have been day name for another format of --full-time
-        if (Month == 0)
+        Month = 0;
+        #define COL2MONTH \
+          for (Word IMonth = 0; IMonth < 12; IMonth++) \
+            if (!Col.CompareIC(EngShortMonthNames[IMonth])) { Month = IMonth; Month++; break; }
+        COL2MONTH;
+        // if the column is not known month name, it may have been "yyyy-mm-dd"
+        // for --full-time format
+        if ((Month == 0) && (Col.Length() == 10) && (Col[5] == L'-') && (Col[8] == L'-'))
         {
+          Year = (Word)Col.SubString(1, 4).ToInt();
+          Month = (Word)Col.SubString(6, 2).ToInt();
+          Day = (Word)Col.SubString(9, 2).ToInt();
           GETCOL;
-          COL2MONTH;
-          // neither standard, not --full-time format
-          if (Month == 0)
+          Hour = (Word)Col.SubString(1, 2).ToInt();
+          Min = (Word)Col.SubString(4, 2).ToInt();
+          if (Col.Length() >= 8)
           {
-            Abort();
+            Sec = (Word)StrToInt(Col.SubString(7, 2));
           }
           else
           {
-            FullTime = true;
-          }
-        }
-        #undef COL2MONTH
-
-        if (Day == 0)
-        {
-          GETNCOL;
-          Day = (Word)StrToInt(Col);
-        }
-        if ((Day < 1) || (Day > 31)) Abort();
-
-        // second full-time format
-        // ddd mmm dd hh:nn:ss yyyy
-        if (FullTime)
-        {
-          GETCOL;
-          if (Col.Length() != 8)
-          {
-            Abort();
+            Sec = 0;
           }
-          Hour = (Word)StrToInt(Col.SubString(1, 2));
-          Min = (Word)StrToInt(Col.SubString(4, 2));
-          Sec = (Word)StrToInt(Col.SubString(7, 2));
           FModificationFmt = mfFull;
+          // skip TZ (TODO)
           // do not trim leading space of filename
           GETNCOL;
-          Year = (Word)StrToInt(Col);
         }
         else
         {
-          // for format dd mmm the below description seems not to be true,
-          // the year is not aligned to 5 characters
-          if (DayMonthFormat)
+          // or it may have been day name for another format of --full-time
+          if (Month == 0)
           {
             GETCOL;
+            COL2MONTH;
+            // neither standard, not --full-time format
+            if (Month == 0)
+            {
+              Abort();
+            }
+            else
+            {
+              FullTime = true;
+            }
           }
-          else
+          #undef COL2MONTH
+
+          if (Day == 0)
           {
-            // Time/Year indicator is always 5 characters long (???), on most
-            // systems year is aligned to right (_YYYY), but on some to left (YYYY_),
-            // we must ensure that trailing space is also deleted, so real
-            // separator space is not treated as part of file name
-            Col = Line.SubString(1, 6).Trim();
-            Line.Delete(1, 6);
+            GETNCOL;
+            Day = (Word)StrToInt(Col);
           }
-          // GETNCOL; // We don't want to trim input strings (name with space at beginning???)
-          // Check if we got time (contains :) or year
-          if ((P = (Word)Col.Pos(L':')) > 0)
+          if ((Day < 1) || (Day > 31)) Abort();
+
+          // second full-time format
+          // ddd mmm dd hh:nn:ss yyyy
+          if (FullTime)
           {
-            Word CurrMonth, CurrDay;
-            Hour = (Word)StrToInt(Col.SubString(1, P-1));
-            Min = (Word)StrToInt(Col.SubString(P+1, Col.Length() - P));
-            if (Hour > 23 || Min > 59) Abort();
-            // When we don't got year, we assume current year
-            // with exception that the date would be in future
-            // in this case we assume last year.
-            DecodeDate(Date(), Year, CurrMonth, CurrDay);
-            if ((Month > CurrMonth) ||
-                (Month == CurrMonth && Day > CurrDay)) Year--;
-            Sec = 0;
-            FModificationFmt = mfMDHM;
+            GETCOL;
+            if (Col.Length() != 8)
+            {
+              Abort();
+            }
+            Hour = (Word)StrToInt(Col.SubString(1, 2));
+            Min = (Word)StrToInt(Col.SubString(4, 2));
+            Sec = (Word)StrToInt(Col.SubString(7, 2));
+            FModificationFmt = mfFull;
+            // do not trim leading space of filename
+            GETNCOL;
+            Year = (Word)StrToInt(Col);
           }
-            else
+          else
           {
-            Year = (Word)StrToInt(Col);
-            if (Year > 10000) Abort();
-            // When we don't got time we assume midnight
-            Hour = 0; Min = 0; Sec = 0;
-            FModificationFmt = mfMDY;
+            // for format dd mmm the below description seems not to be true,
+            // the year is not aligned to 5 characters
+            if (DayMonthFormat)
+            {
+              GETCOL;
+            }
+            else
+            {
+              // Time/Year indicator is always 5 characters long (???), on most
+              // systems year is aligned to right (_YYYY), but on some to left (YYYY_),
+              // we must ensure that trailing space is also deleted, so real
+              // separator space is not treated as part of file name
+              Col = Line.SubString(1, 6).Trim();
+              Line.Delete(1, 6);
+            }
+            // GETNCOL; // We don't want to trim input strings (name with space at beginning???)
+            // Check if we got time (contains :) or year
+            if ((P = (Word)Col.Pos(L':')) > 0)
+            {
+              Word CurrMonth, CurrDay;
+              Hour = (Word)StrToInt(Col.SubString(1, P-1));
+              Min = (Word)StrToInt(Col.SubString(P+1, Col.Length() - P));
+              if (Hour > 23 || Min > 59) Abort();
+              // When we don't got year, we assume current year
+              // with exception that the date would be in future
+              // in this case we assume last year.
+              DecodeDate(Date(), Year, CurrMonth, CurrDay);
+              if ((Month > CurrMonth) ||
+                  (Month == CurrMonth && Day > CurrDay)) Year--;
+              Sec = 0;
+              FModificationFmt = mfMDHM;
+            }
+              else
+            {
+              Year = (Word)StrToInt(Col);
+              if (Year > 10000) Abort();
+              // When we don't got time we assume midnight
+              Hour = 0; Min = 0; Sec = 0;
+              FModificationFmt = mfMDY;
+            }
           }
         }
-      }
 
-      FModification = EncodeDateVerbose(Year, Month, Day) + EncodeTimeVerbose(Hour, Min, Sec, 0);
-      // adjust only when time is known,
-      // adjusting default "midnight" time makes no sense
-      if ((FModificationFmt == mfMDHM) || (FModificationFmt == mfFull))
-      {
-        DebugAssert(Terminal != NULL);
-        FModification = AdjustDateTimeFromUnix(FModification,
-          Terminal->SessionData->DSTMode);
-      }
+        FModification = EncodeDateVerbose(Year, Month, Day) + EncodeTimeVerbose(Hour, Min, Sec, 0);
+        // adjust only when time is known,
+        // adjusting default "midnight" time makes no sense
+        if ((FModificationFmt == mfMDHM) || (FModificationFmt == mfFull))
+        {
+          DebugAssert(Terminal != NULL);
+          FModification = AdjustDateTimeFromUnix(FModification,
+            Terminal->SessionData->DSTMode);
+        }
 
-      if (double(FLastAccess) == 0)
-      {
-        FLastAccess = FModification;
+        if (double(FLastAccess) == 0)
+        {
+          FLastAccess = FModification;
+        }
       }
 
       // separating space is already deleted, other spaces are treated as part of name