System.Net.FtpClient.FtpListItem.ParseUnixList C# (CSharp) Method

ParseUnixList() static private method

Parses LIST format listings
static private ParseUnixList ( string buf, FtpCapability capabilities ) : FtpListItem
buf string A line from the listing
capabilities FtpCapability Server capabilities
return FtpListItem
        static FtpListItem ParseUnixList(string buf, FtpCapability capabilities)
        {
            string regex =
                @"(?<permissions>.+)\s+" +
                @"(?<objectcount>\d+)\s+" +
                @"(?<user>.+)\s+" +
                @"(?<group>.+)\s+" +
                @"(?<size>\d+)\s+" +
                @"(?<modify>\w+\s+\d+\s+\d+:\d+|\w+\s+\d+\s+\d+)\s" +
                @"(?<name>.*)$";
            FtpListItem item = new FtpListItem();
            Match m;

            if (!(m = Regex.Match(buf, regex, RegexOptions.IgnoreCase)).Success)
                return null;

            // if this field is missing we can't determine
            // what the object is.
            if (m.Groups["permissions"].Value.Length == 0)
                return null;

            switch (m.Groups["permissions"].Value[0]) {
                case 'd':
                    item.Type = FtpFileSystemObjectType.Directory;
                    break;
                case '-':
                case 's':
                    item.Type = FtpFileSystemObjectType.File;
                    break;
                case 'l':
                    item.Type = FtpFileSystemObjectType.Link;
                    break;
                default:
                    return null;
            }

            // if we can't determine a file name then
            // we are not considering this a successful parsing operation.
            if (m.Groups["name"].Value.Length < 1)
                return null;
            item.Name = m.Groups["name"].Value;

            switch (item.Type) {
                case FtpFileSystemObjectType.Directory:
                    // ignore these...
                    if (item.Name == "." || item.Name == "..")
                        return null;
                    break;
                case FtpFileSystemObjectType.Link:
                    if (!item.Name.Contains(" -> "))
                        return null;
                    item.LinkTarget = item.Name.Remove(0, item.Name.IndexOf("-> ") + 3);
                    item.Name = item.Name.Remove(item.Name.IndexOf(" -> "));
                    break;
            }

            ////
            // Ignore the Modify times sent in LIST format for files
            // when the server has support for the MDTM command
            // because they will never be as accurate as what can be had
            // by using the MDTM command. MDTM does not work on directories
            // so if a modify time was parsed from the listing we will try
            // to convert it to a DateTime object and use it for directories.
            ////
            if (((capabilities & FtpCapability.MDTM) != FtpCapability.MDTM || item.Type == FtpFileSystemObjectType.Directory) && m.Groups["modify"].Value.Length > 0)
                item.Modified = m.Groups["modify"].Value.GetFtpDate(DateTimeStyles.AssumeLocal);

            if (m.Groups["size"].Value.Length > 0) {
                long size;

                if (long.TryParse(m.Groups["size"].Value, out size))
                    item.Size = size;
            }

            if (m.Groups["permissions"].Value.Length > 0) {
                Match perms = Regex.Match(m.Groups["permissions"].Value,
                    @"[\w-]{1}(?<owner>[\w-]{3})(?<group>[\w-]{3})(?<others>[\w-]{3})",
                    RegexOptions.IgnoreCase);

                if (perms.Success) {
                    if (perms.Groups["owner"].Value.Length == 3) {
                        if (perms.Groups["owner"].Value[0] == 'r')
                            item.OwnerPermissions |= FtpPermission.Read;
                        if (perms.Groups["owner"].Value[1] == 'w')
                            item.OwnerPermissions |= FtpPermission.Write;
                        if (perms.Groups["owner"].Value[2] == 'x' || perms.Groups["owner"].Value[2] == 's')
                            item.OwnerPermissions |= FtpPermission.Execute;
                        if (perms.Groups["owner"].Value[2] == 's' || perms.Groups["owner"].Value[2] == 'S')
                            item.SpecialPermissions |= FtpSpecialPermissions.SetUserID;
                    }

                    if (perms.Groups["group"].Value.Length == 3) {
                        if (perms.Groups["group"].Value[0] == 'r')
                            item.GroupPermissions |= FtpPermission.Read;
                        if (perms.Groups["group"].Value[1] == 'w')
                            item.GroupPermissions |= FtpPermission.Write;
                        if (perms.Groups["group"].Value[2] == 'x' || perms.Groups["group"].Value[2] == 's')
                            item.GroupPermissions |= FtpPermission.Execute;
                        if (perms.Groups["group"].Value[2] == 's' || perms.Groups["group"].Value[2] == 'S')
                            item.SpecialPermissions |= FtpSpecialPermissions.SetGroupID;
                    }

                    if (perms.Groups["others"].Value.Length == 3) {
                        if (perms.Groups["others"].Value[0] == 'r')
                            item.OthersPermissions |= FtpPermission.Read;
                        if (perms.Groups["others"].Value[1] == 'w')
                            item.OthersPermissions |= FtpPermission.Write;
                        if (perms.Groups["others"].Value[2] == 'x' || perms.Groups["others"].Value[2] == 't')
                            item.OthersPermissions |= FtpPermission.Execute;
                        if (perms.Groups["others"].Value[2] == 't' || perms.Groups["others"].Value[2] == 'T')
                            item.SpecialPermissions |= FtpSpecialPermissions.Sticky;
                    }
                }
            }

            return item;
        }

Usage Example

 /// <summary>
 /// Gets the size of the file
 /// </summary>
 /// <param name="path">The full or relative path of the file</param>
 /// <returns>-1 if the command fails, otherwise the file size</returns>
 public override long GetFileSize(string path)
 {
     try
     {
         m_lock.WaitOne();
         Execute("TYPE I");
         // read in one line of raw file listing for the file - it's the only method to get file size
         try
         {
             using (FtpDataStream stream = OpenDataStream($"LIST {path.GetFtpPath()}", 0))
             {
                 string buf;
                 try
                 {
                     buf = stream.ReadLine(Encoding);
                     if (!string.IsNullOrWhiteSpace(buf))
                     {
                         FtpTrace.WriteLine(buf);
                         FtpListItem itemdata = FtpListItem.ParseUnixList(buf, FtpCapability.NONE);
                         return itemdata.Size;
                     }
                 }
                 finally
                 {
                     stream.Close();
                 }
             }
         }
         catch (FtpCommandException)
         {
             return 0;
         }
     }
     finally
     {
         m_lock.ReleaseMutex();
     }
     return -1;
 }