Пример #1
0
 /// <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;
 }
Пример #2
0
        private static FtpListItem ParseUnixList(string buf, FtpCapability capabilities)
        {
            Match       match;
            long        num;
            string      pattern = @"(?<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();

            if ((match = Regex.Match(buf, pattern, RegexOptions.IgnoreCase)).Success)
            {
                if (match.Groups["permissions"].Value.Length == 0)
                {
                    return(null);
                }
                switch (match.Groups["permissions"].Value[0])
                {
                case 'l':
                    item.Type = FtpFileSystemObjectType.Link;
                    goto Label_0099;

                case 's':
                case '-':
                    item.Type = FtpFileSystemObjectType.File;
                    goto Label_0099;

                case 'd':
                    item.Type = FtpFileSystemObjectType.Directory;
                    goto Label_0099;
                }
            }
            return(null);

Label_0099:
            if (match.Groups["name"].Value.Length < 1)
            {
                return(null);
            }
            item.Name = match.Groups["name"].Value;
            switch (item.Type)
            {
            case FtpFileSystemObjectType.Directory:
                if (!(item.Name == ".") && !(item.Name == ".."))
                {
                    break;
                }
                return(null);

            case FtpFileSystemObjectType.Link:
                if (item.Name.Contains(" -> "))
                {
                    item.LinkTarget = item.Name.Remove(0, item.Name.IndexOf("-> ") + 3);
                    item.Name       = item.Name.Remove(item.Name.IndexOf(" -> "));
                    break;
                }
                return(null);
            }
            if ((((capabilities & FtpCapability.MDTM) != FtpCapability.MDTM) || (item.Type == FtpFileSystemObjectType.Directory)) && (match.Groups["modify"].Value.Length > 0))
            {
                item.Modified = match.Groups["modify"].Value.GetFtpDate(DateTimeStyles.AssumeLocal);
                if (item.Modified == DateTime.MinValue)
                {
                    FtpTrace.WriteLine("GetFtpDate() failed on {0}", new object[] { match.Groups["modify"].Value });
                }
            }
            else if (match.Groups["modify"].Value.Length == 0)
            {
                FtpTrace.WriteLine("RegEx failed to parse modified date from {0}.", new object[] { buf });
            }
            else if (item.Type == FtpFileSystemObjectType.Directory)
            {
                FtpTrace.WriteLine("Modified times of directories are ignored in UNIX long listings.");
            }
            else if ((capabilities & FtpCapability.MDTM) == FtpCapability.MDTM)
            {
                FtpTrace.WriteLine("Ignoring modified date because MDTM feature is present. If you aren't already, pass FtpListOption.Modify or FtpListOption.SizeModify to GetListing() to retrieve the modification time.");
            }
            if ((match.Groups["size"].Value.Length > 0) && long.TryParse(match.Groups["size"].Value, out num))
            {
                item.Size = num;
            }
            if (match.Groups["permissions"].Value.Length > 0)
            {
                Match match2 = Regex.Match(match.Groups["permissions"].Value, @"[\w-]{1}(?<owner>[\w-]{3})(?<group>[\w-]{3})(?<others>[\w-]{3})", RegexOptions.IgnoreCase);
                if (!match2.Success)
                {
                    return(item);
                }
                if (match2.Groups["owner"].Value.Length == 3)
                {
                    if (match2.Groups["owner"].Value[0] == 'r')
                    {
                        item.OwnerPermissions |= FtpPermission.None | FtpPermission.Read;
                    }
                    if (match2.Groups["owner"].Value[1] == 'w')
                    {
                        item.OwnerPermissions |= FtpPermission.None | FtpPermission.Write;
                    }
                    if ((match2.Groups["owner"].Value[2] == 'x') || (match2.Groups["owner"].Value[2] == 's'))
                    {
                        item.OwnerPermissions |= FtpPermission.Execute;
                    }
                    if ((match2.Groups["owner"].Value[2] == 's') || (match2.Groups["owner"].Value[2] == 'S'))
                    {
                        item.SpecialPermissions |= FtpSpecialPermissions.SetUserID;
                    }
                }
                if (match2.Groups["group"].Value.Length == 3)
                {
                    if (match2.Groups["group"].Value[0] == 'r')
                    {
                        item.GroupPermissions |= FtpPermission.None | FtpPermission.Read;
                    }
                    if (match2.Groups["group"].Value[1] == 'w')
                    {
                        item.GroupPermissions |= FtpPermission.None | FtpPermission.Write;
                    }
                    if ((match2.Groups["group"].Value[2] == 'x') || (match2.Groups["group"].Value[2] == 's'))
                    {
                        item.GroupPermissions |= FtpPermission.Execute;
                    }
                    if ((match2.Groups["group"].Value[2] == 's') || (match2.Groups["group"].Value[2] == 'S'))
                    {
                        item.SpecialPermissions |= FtpSpecialPermissions.SetGroupID;
                    }
                }
                if (match2.Groups["others"].Value.Length == 3)
                {
                    if (match2.Groups["others"].Value[0] == 'r')
                    {
                        item.OthersPermissions |= FtpPermission.None | FtpPermission.Read;
                    }
                    if (match2.Groups["others"].Value[1] == 'w')
                    {
                        item.OthersPermissions |= FtpPermission.None | FtpPermission.Write;
                    }
                    if ((match2.Groups["others"].Value[2] == 'x') || (match2.Groups["others"].Value[2] == 't'))
                    {
                        item.OthersPermissions |= FtpPermission.Execute;
                    }
                    if ((match2.Groups["others"].Value[2] != 't') && (match2.Groups["others"].Value[2] != 'T'))
                    {
                        return(item);
                    }
                    item.SpecialPermissions |= FtpSpecialPermissions.Sticky;
                }
            }
            return(item);
        }
Пример #3
0
        /// <summary>
        /// Parses LIST format listings
        /// </summary>
        /// <param name="buf">A line from the listing</param>
        /// <param name="capabilities">Server capabilities</param>
        /// <returns>FtpListItem if the item is able to be parsed</returns>
        internal 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>.*)$";
            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);
            }

            FtpListItem item = new FtpListItem();

            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;
            }

            // for date parser testing only
            //capabilities = ~(capabilities & FtpCapability.MDTM);

            ////
            // 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 (item.Modified == DateTime.MinValue)
                {
                    FtpTrace.WriteLine("GetFtpDate() failed on {0}", m.Groups["modify"].Value);
                }
            }
            else
            {
                if (m.Groups["modify"].Value.Length == 0)
                {
                    FtpTrace.WriteLine("RegEx failed to parse modified date from {0}.", buf);
                }
                else if (item.Type == FtpFileSystemObjectType.Directory)
                {
                    FtpTrace.WriteLine("Modified times of directories are ignored in UNIX long listings.");
                }
                else if ((capabilities & FtpCapability.MDTM) == FtpCapability.MDTM)
                {
                    FtpTrace.WriteLine("Ignoring modified date because MDTM feature is present. If you aren't already, pass FtpListOption.Modify or FtpListOption.SizeModify to GetListing() to retrieve the modification time.");
                }
            }

            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);
        }
Пример #4
0
        /// <summary>
        /// Parses a line from a file listing using the first successful match in the Parsers collection.
        /// </summary>
        /// <param name="path">The source path of the file listing</param>
        /// <param name="buf">A line from the file listing</param>
        /// <param name="capabilities">Server capabilities</param>
        /// <returns>A FtpListItem object representing the parsed line, null if the line was
        /// unable to be parsed. If you have encountered an unsupported list type add a parser
        /// to the public static Parsers collection of FtpListItem.</returns>
        public static FtpListItem Parse(string path, string buf, FtpCapability capabilities)
        {
            if (buf != null && buf.Length > 0)
            {
                FtpListItem item;

                foreach (Parser parser in Parsers)
                {
                    if ((item = parser(buf, capabilities)) != null)
                    {
                        // if this is a vax/openvms file listing
                        // there are no slashes in the path name
                        if (parser == (new Parser(ParseVaxList)))
                        {
                            item.FullName = path + item.Name;
                        }
                        else
                        {
                            FtpTrace.WriteLine(item.Name);

                            // remove globbing/wildcard from path
                            if (path.GetFtpFileName().Contains("*"))
                            {
                                path = path.GetFtpDirectoryName();
                            }

                            if (item.Name != null)
                            {
                                // absolute path? then ignore the path input to this method.
                                if (item.Name.StartsWith("/") || item.Name.StartsWith("./") || item.Name.StartsWith("../"))
                                {
                                    item.FullName = item.Name;
                                    item.Name     = item.Name.GetFtpFileName();
                                }
                                else if (path != null)
                                {
                                    item.FullName = path.GetFtpPath(item.Name); //.GetFtpPathWithoutGlob();
                                }
                                else
                                {
                                    FtpTrace.WriteLine("Couldn't determine the full path of this object:{0}{1}",
                                                       Environment.NewLine, item.ToString());
                                }
                            }


                            // if a link target is set and it doesn't include an absolute path
                            // then try to resolve it.
                            if (item.LinkTarget != null && !item.LinkTarget.StartsWith("/"))
                            {
                                if (item.LinkTarget.StartsWith("./"))
                                {
                                    item.LinkTarget = path.GetFtpPath(item.LinkTarget.Remove(0, 2));
                                }
                                else
                                {
                                    item.LinkTarget = path.GetFtpPath(item.LinkTarget);
                                }
                            }
                        }

                        item.Input = buf;
                        return(item);
                    }
                }
            }

            return(null);
        }
Пример #5
0
        /// <summary>
        /// Connect to the specified host
        /// </summary>
        /// <param name="host">The host to connect to</param>
        /// <param name="port">The port to connect to</param>
        /// <param name="ipVersions">Internet Protocol versions to support durring the connection phase</param>
        public void Connect(string host, int port, FtpIpVersion ipVersions)
        {
            IAsyncResult ar = null;

            IPAddress[] addresses = Dns.GetHostAddresses(host);

            if (ipVersions == 0)
            {
                throw new ArgumentException("The ipVersions parameter must contain at least 1 flag.");
            }

            for (int i = 0; i < addresses.Length; i++)
            {
#if DEBUG
                FtpTrace.WriteLine("{0}: {1}", addresses[i].AddressFamily.ToString(), addresses[i].ToString());
#endif
                // we don't need to do this check unless
                // a particular version of IP has been
                // omitted so we won't.
                if (ipVersions != FtpIpVersion.ANY)
                {
                    switch (addresses[i].AddressFamily)
                    {
                    case AddressFamily.InterNetwork:
                        if ((ipVersions & FtpIpVersion.IPv4) != FtpIpVersion.IPv4)
                        {
#if DEBUG
                            FtpTrace.WriteLine("SKIPPED!");
#endif
                            continue;
                        }
                        break;

                    case AddressFamily.InterNetworkV6:
                        if ((ipVersions & FtpIpVersion.IPv6) != FtpIpVersion.IPv6)
                        {
#if DEBUG
                            FtpTrace.WriteLine("SKIPPED!");
#endif
                            continue;
                        }
                        break;
                    }
                }

                m_socket = new Socket(addresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                ar       = m_socket.BeginConnect(addresses[i], port, null, null);
                if (addresses[i].ToString() != "::1") // 21Nov2014 Added by Lemu
                {
                    if (!ar.AsyncWaitHandle.WaitOne(m_connectTimeout, true))
                    {
                        Close();

                        // check to see if we're out of addresses
                        // and if we are throw a TimeoutException
                        if (i + 1 == addresses.Length)
                        {
                            throw new TimeoutException("Timed out trying to connect!");
                        }
                    }
                    else
                    {
                        m_socket.EndConnect(ar);
                        // we got a connection, break out
                        // of the loop.
                        break;
                    }
                }
            }

            // make sure that we actually connected to
            // one of the addresses returned from GetHostAddresses()
            if (m_socket == null || !m_socket.Connected)
            {
                Close();
                throw new IOException("Failed to connect to host.");
            }

            m_netStream    = new NetworkStream(m_socket);
            m_lastActivity = DateTime.Now;
        }
Пример #6
0
 public new void Dispose()
 {
     FtpTrace.WriteLine("Disposing FtpSocketStream...");
     Close();
 }