Browse Source

Bug 1448: Handle directory listing entries with question marks

https://winscp.net/tracker/1448

Source commit: 80952d73425938e78b07dbf4c97f65267e5a13ca
Martin Prikryl 9 years ago
parent
commit
d7f01b9b4f
1 changed files with 132 additions and 112 deletions
  1. 132 112
      source/core/RemoteFiles.cpp

+ 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