home

about

license

support

K/Base

Indy
HomeContactsSite Map


Fix for WIndows NT FTP Service Directory List parser

Earlier this morning, Jeff Easton, has posted about a problem with the Windows NT IIS FTP Service list parser class. The parser could not detect that it could handle a file size greater than 9 digits. I confirmed the bug myself and I checked in a fix for it. The fix is a minor reworking for the parser detection routine to be more liberal about numbers in specific string positions.

At the same time, I changed things so the parser would be less tolorant of spaces to the right side of a number. I did that because FTP list parsing is always a mess since there are many formats and if I'm not careful, I can easily do a fix that introduces other problems.

If you are interested, just replace the TIdFTPLPWindowsNT.CheckListing class procedure in the IdFTPListParseWindowsNT unit with this one:

class function TIdFTPLPWindowsNT.CheckListing(AListing: TIdStrings;
  const ASysDescript: String; const ADetails: Boolean): boolean;
var SDir, sSize : String;
  i : Integer;
  SData : String;
begin

  //maybe, we are dealing with this pattern
  //2002-09-02  18:48       <DIR>          DOS dir 2
  //
  //or
  //2002-09-02  19:06                9,730 DOS file 2
  //
  //Those were obtained from soem comments in some FileZilla source-code.
  //FtpListResult.cpp
  //Note that none of that GNU source-code was used.
  //
  //I personally came accross the following when on Microsoft IIS
  //FTP Service on WIndowsXP Pro when I enabled the "FtpDirBrowseShowLongDate"
  //metadata property.
  //
  //02-16-2005  04:16AM       <DIR>          pub

  Result := False;
  for i := 0 to AListing.Count - 1 do
  begin
    if (AListing[i]<>'') and
      (IsSubDirContentsBanner(AListing[i])=False) then
    begin
      SData := Sys.UpperCase(AListing[i]);
      sDir := Copy(SData, 25, 5);
      //maybe this is two spacs off.  We don't use TrimLeft at this point
      //because we can't assume that this is a valid WIndows FTP Service listing.

      if sDir = '  <DI' then    {do not localize}
      begin
        sDir := Copy(SData, 27, 5);
      end;
      sDir := Sys.TrimLeft(sDir);
      //This is a workaround for large file sizes such as:

      //09-08-05  10:22AM            628551680 Test.txt
      //09-08-05  10:23AM            628623360 Test2.txt

      if IsNumeric(Sys.TrimLeft(sDir)) then
      begin
        sDir := '';
      end;
      sSize := Sys.StringReplace(Sys.TrimLeft(Copy(SData, 20, 19)), ',', '');    {Do not Localize}
      //VM/BFS does share the date/time format as MS-DOS for the first two columns
  //    if ((CharIsInSet(SData, 3, ['/', '-'])) and (CharIsInSet(SData, 6, ['/', '-']))) then
      if IsMMDDYY(Copy(SData,1,8),'-') or IsMMDDYY(Copy(SData,1,8),'/') then
      begin
        if (sDir = '<DIR>') then  {do not localize}
        begin
          Result := IsVMBFS(SData)=False;
        end
        else
        begin
          //may be a file - see if we can get the size if sDir is empty
          if ((sDir = '') and    {Do not Localize}
            (Sys.StrToInt64(sSize, -1) <> -1)) then
          begin
            Result := IsVMBFS(SData)=False;
          end;
        end;
      end
      else
      begin

        if IsYYYYMMDD(SData) then
        begin
          if (sDir = '<DIR>') then  {do not localize}
          begin
            Result := IsVMBFS(SData)=False;
          end
          else
          begin
            //may be a file - see if we can get the size if sDir is empty
            if ((sDir = '') and    {Do not Localize}
              (Sys.StrToInt64(sSize, -1) <> -1)) then
            begin
              Result := IsVMBFS(SData)=False;
            end;
          end;
        end
        else
        begin
          if IsMMDDYY(SData,'-') then
          begin
          {
It might be like this:
02-16-2005  04:16AM       <DIR>          pub
02-14-2005  07:22AM              9112103 ethereal-setup-0.10.9.exe

          }
            if (sDir = '<DIR>') then  {do not localize}
            begin
              Result := IsVMBFS(SData)=False;
            end
            else
            begin
              if ((sDir = '') and    {Do not Localize}
               (Sys.StrToInt64(sSize, -1) <> -1)) then
              begin
                Result := IsVMBFS(SData)=False;
              end;
            end;
          end;
        end;
      end;
    end;
  end;
end;

It goes without saying that the ultimate fix to these parsing problems is if all servers and clients support the MLSD/MLST commands.


Corporate Sponsors

Atozed







home

about

license

support

K/Base

site map

links

Copyright © 1993 - 2008 Chad Z. Hower (Kudzu) and the Indy Pit Crew.          Website design by RuInternet.ru