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); }
/// <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); }
/// <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; }
/// <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); }
public new void Dispose() { FtpTrace.WriteLine("Disposing FtpSocketStream..."); Close(); }