Ejemplo n.º 1
0
        /// <summary>
        /// Activates SSL on this stream using the specified protocols. Fires the ValidateCertificate event.
        /// If this event is not handled and there are SslPolicyErrors present, the certificate will
        /// not be accepted.
        /// </summary>
        /// <param name="targethost">The host to authenticate the certificate against</param>
        /// <param name="clientCerts">A collection of client certificates to use when authenticating the SSL stream</param>
        /// <param name="sslProtocols">A bitwise parameter for supported encryption protocols.</param>
        /// <exception cref="AuthenticationException">Thrown when authentication fails</exception>
        public void ActivateEncryption(string targethost, X509CertificateCollection clientCerts, SslProtocols sslProtocols)
        {
            if (!IsConnected)
            {
                throw new InvalidOperationException("The FtpSocketStream object is not connected.");
            }

            if (m_netStream == null)
            {
                throw new InvalidOperationException("The base network stream is null.");
            }

            if (m_sslStream != null)
            {
                throw new InvalidOperationException("SSL Encryption has already been enabled on this stream.");
            }

            try
            {
                DateTime auth_start;
                TimeSpan auth_time_total;

#if CORE
                m_sslStream = new SslStream(NetworkStream, true, new RemoteCertificateValidationCallback(
                                                delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
                    return(OnValidateCertificate(certificate, chain, sslPolicyErrors));
                }
                                                ));
#else
                m_sslStream = new FtpSslStream(NetworkStream, true, new RemoteCertificateValidationCallback(
                                                   delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
                {
                    return(OnValidateCertificate(certificate, chain, sslPolicyErrors));
                }
                                                   ));
#endif

                auth_start = DateTime.Now;
#if CORE
                m_sslStream.AuthenticateAsClientAsync(targethost, clientCerts, sslProtocols, true).Wait();
#else
                m_sslStream.AuthenticateAsClient(targethost, clientCerts, sslProtocols, true);
#endif

                auth_time_total = DateTime.Now.Subtract(auth_start);
                FtpTrace.WriteStatus(FtpTraceLevel.Info, "FTPS Authentication Successful");
                FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Time to activate encryption: " + auth_time_total.Hours + "h " + auth_time_total.Minutes + "m " + auth_time_total.Seconds + "s.  Total Seconds: " + auth_time_total.TotalSeconds + ".");
            }
            catch (AuthenticationException)
            {
                // authentication failed and in addition it left our
                // ssl stream in an unusable state so cleanup needs
                // to be done and the exception can be re-thrown for
                // handling down the chain. (Add logging?)
                Close();
                FtpTrace.WriteStatus(FtpTraceLevel.Error, "FTPS Authentication Failed");
                throw;
            }
        }
Ejemplo n.º 2
0
        public override void Close()
        {
#endif
            if (m_socket != null)
            {
                try {
                    if (m_socket.Connected)
                    {
                        ////
                        // Calling Shutdown() with mono causes an
                        // exception if the remote host closed first
                        //m_socket.Shutdown(SocketShutdown.Both);
#if CORE
                        m_socket.Dispose();
#else
                        m_socket.Close();
#endif
                    }

#if !NET2 && !NET35
                    m_socket.Dispose();
#endif
                }
                catch (SocketException ex) {
                    FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Caught and discarded a SocketException while cleaning up the Socket: " + ex.ToString());
                } finally {
                    m_socket = null;
                }
            }

            if (m_netStream != null)
            {
                try {
                    m_netStream.Dispose();
                } catch (IOException ex) {
                    FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Caught and discarded an IOException while cleaning up the NetworkStream: " + ex.ToString());
                } finally {
                    m_netStream = null;
                }
            }

#if !NO_SSL
            if (m_sslStream != null)
            {
                try {
                    m_sslStream.Dispose();
                } catch (IOException ex) {
                    FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Caught and discarded an IOException while cleaning up the SslStream: " + ex.ToString());
                } finally {
                    m_sslStream = null;
                }
            }
#endif

#if CORE
            base.Dispose();
#endif
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Gets the hash of an object on the server using the currently selected hash algorithm.
        /// </summary>
        /// <remarks>
        /// Supported algorithms, if any, are available in the <see cref="HashAlgorithms"/>
        /// property. You should confirm that it's not equal
        /// to <see cref="FtpHashAlgorithm.NONE"/> before calling this method
        /// otherwise the server trigger a <see cref="FtpCommandException"/>
        /// due to a lack of support for the HASH command. You can
        /// set the algorithm using the <see cref="SetHashAlgorithm"/> method and
        /// you can query the server for the current hash algorithm
        /// using the <see cref="GetHashAlgorithm"/> method.
        ///
        /// This feature is experimental and based on the following draft:
        /// http://tools.ietf.org/html/draft-bryan-ftpext-hash-02
        /// </remarks>
        /// <param name="path">Full or relative path of the object to compute the hash for.</param>
        /// <returns>The hash of the file.</returns>
        /// <exception cref="FtpCommandException">
        /// Thrown if the <see cref="HashAlgorithms"/> property is <see cref="FtpHashAlgorithm.NONE"/>,
        /// the remote path does not exist, or the command cannot be executed.
        /// </exception>
        /// <exception cref="ArgumentException">Path argument is null</exception>
        /// <exception cref="NotImplementedException">Thrown when an unknown hash algorithm type is returned by the server</exception>
        /// <example><code source="..\Examples\GetHash.cs" lang="cs" /></example>
        public FtpHash GetHash(string path)
        {
            FtpReply reply;
            FtpHash  hash = new FtpHash();
            Match    m;

            if (path == null)
            {
                throw new ArgumentException("GetHash(path) argument can't be null");
            }

#if !CORE14
            lock (m_lock) {
#endif
            if (!(reply = Execute("HASH " + path.GetFtpPath())).Success)
            {
                throw new FtpCommandException(reply);
            }
#if !CORE14
        }
#endif

            // Current draft says the server should return this:
            // SHA-256 0-49 169cd22282da7f147cb491e559e9dd filename.ext
            if (!(m = Regex.Match(reply.Message,
                                  @"(?<algorithm>.+)\s" +
                                  @"(?<bytestart>\d+)-(?<byteend>\d+)\s" +
                                  @"(?<hash>.+)\s" +
                                  @"(?<filename>.+)")).Success)
            {
                // Current version of FileZilla returns this:
                // SHA-1 21c2ca15cf570582949eb59fb78038b9c27ffcaf
                m = Regex.Match(reply.Message, @"(?<algorithm>.+)\s(?<hash>.+)\s");
            }

            if (m != null && m.Success)
            {
                switch (m.Groups["algorithm"].Value)
                {
                case "SHA-1":
                    hash.Algorithm = FtpHashAlgorithm.SHA1;
                    break;

                case "SHA-256":
                    hash.Algorithm = FtpHashAlgorithm.SHA256;
                    break;

                case "SHA-512":
                    hash.Algorithm = FtpHashAlgorithm.SHA512;
                    break;

                case "MD5":
                    hash.Algorithm = FtpHashAlgorithm.MD5;
                    break;

                default:
                    throw new NotImplementedException("Unknown hash algorithm: " + m.Groups["algorithm"].Value);
                }

                hash.Value = m.Groups["hash"].Value;
            }
            else
            {
                FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Failed to parse hash from: " + reply.Message);
            }

            return(hash);
        }
Ejemplo n.º 4
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 during the connection phase</param>
        public void Connect(string host, int port, FtpIpVersion ipVersions)
        {
#if CORE
            IPAddress[] addresses = Dns.GetHostAddressesAsync(host).Result;
#else
            IAsyncResult ar        = null;
            IPAddress[]  addresses = Dns.GetHostAddresses(host);
#endif

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

            for (int i = 0; i < addresses.Length; i++)
            {
                // 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.WriteStatus(FtpTraceLevel.Verbose, "Skipped IPV4 address : " + addresses[i].ToString());
#endif
                            continue;
                        }
                        break;

                    case AddressFamily.InterNetworkV6:
                        if ((ipVersions & FtpIpVersion.IPv6) != FtpIpVersion.IPv6)
                        {
#if DEBUG
                            FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Skipped IPV6 address : " + addresses[i].ToString());
#endif
                            continue;
                        }
                        break;
                    }
                }

                if (FtpTrace.LogIP)
                {
                    FtpTrace.WriteStatus(FtpTraceLevel.Info, "Connecting to " + addresses[i].ToString() + ":" + port);
                }
                else
                {
                    FtpTrace.WriteStatus(FtpTraceLevel.Info, "Connecting to ***:" + port);
                }

                m_socket = new Socket(addresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);
#if CORE
                m_socket.ConnectAsync(addresses[i], port).Wait();
#else
                ar = m_socket.BeginConnect(addresses[i], port, null, null);
                if (!ar.AsyncWaitHandle.WaitOne(m_connectTimeout, true))
                {
                    Close();

                    // check to see if we're out of addresses, and 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;
                }
#endif
            }

            // 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;
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Disposes the stream
 /// </summary>
 public new void Dispose()
 {
     FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Disposing FtpSocketStream...");
     Close();
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Gets a file listing from the server. Each <see cref="FtpListItem"/> object returned
        /// contains information about the file that was able to be retrieved.
        /// </summary>
        /// <remarks>
        /// If a <see cref="DateTime"/> property is equal to <see cref="DateTime.MinValue"/> then it means the
        /// date in question was not able to be retrieved. If the <see cref="FtpListItem.Size"/> property
        /// is equal to 0, then it means the size of the object could also not
        /// be retrieved.
        /// </remarks>
        /// <param name="path">The path of the directory to list</param>
        /// <param name="options">Options that dictacte how a list is performed and what information is gathered.</param>
        /// <returns>An array of FtpListItem objects</returns>
        /// <example><code source="..\Examples\GetListing.cs" lang="cs" /></example>
        public FtpListItem[] GetListing(string path, FtpListOption options)
        {
            FtpTrace.WriteFunc("GetListing", new object[] { path, options });

            FtpListItem        item       = null;
            List <FtpListItem> lst        = new List <FtpListItem>();
            List <string>      rawlisting = new List <string>();
            string             listcmd    = null;
            string             buf        = null;

            // read flags
            bool isIncludeSelf = (options & FtpListOption.IncludeSelfAndParent) == FtpListOption.IncludeSelfAndParent;
            bool isForceList   = (options & FtpListOption.ForceList) == FtpListOption.ForceList;
            bool isNoPath      = (options & FtpListOption.NoPath) == FtpListOption.NoPath;
            bool isNameList    = (options & FtpListOption.NameList) == FtpListOption.NameList;
            bool isUseLS       = (options & FtpListOption.UseLS) == FtpListOption.UseLS;
            bool isAllFiles    = (options & FtpListOption.AllFiles) == FtpListOption.AllFiles;
            bool isRecursive   = (options & FtpListOption.Recursive) == FtpListOption.Recursive && RecursiveList;
            bool isDerefLinks  = (options & FtpListOption.DerefLinks) == FtpListOption.DerefLinks;
            bool isGetModified = (options & FtpListOption.Modify) == FtpListOption.Modify;
            bool isGetSize     = (options & FtpListOption.Size) == FtpListOption.Size;

            // calc path to request
            path = GetAbsolutePath(path);

            // MLSD provides a machine readable format with 100% accurate information
            // so always prefer MLSD over LIST unless the caller of this method overrides it with the ForceList option
            bool machineList = false;

            if ((!isForceList || m_parser == FtpParser.Machine) && HasFeature(FtpCapability.MLSD))
            {
                listcmd     = "MLSD";
                machineList = true;
            }
            else
            {
                if (isUseLS)
                {
                    listcmd = "LS";
                }
                else if (isNameList)
                {
                    listcmd = "NLST";
                }
                else
                {
                    string listopts = "";

                    listcmd = "LIST";

                    if (isAllFiles)
                    {
                        listopts += "a";
                    }

                    if (isRecursive)
                    {
                        listopts += "R";
                    }

                    if (listopts.Length > 0)
                    {
                        listcmd += " -" + listopts;
                    }
                }
            }

            if (!isNoPath)
            {
                listcmd = (listcmd + " " + path.GetFtpPath());
            }

#if !CORE14
            lock (m_lock) {
#endif
            Execute("TYPE I");

            // read in raw file listing
            using (FtpDataStream stream = OpenDataStream(listcmd, 0)) {
                try {
                    FtpTrace.WriteLine(FtpTraceLevel.Verbose, "+---------------------------------------+");
                    while ((buf = stream.ReadLine(Encoding)) != null)
                    {
                        if (buf.Length > 0)
                        {
                            rawlisting.Add(buf);
                            FtpTrace.WriteLine(FtpTraceLevel.Verbose, "Listing:  " + buf);
                        }
                    }
                    FtpTrace.WriteLine(FtpTraceLevel.Verbose, "-----------------------------------------");
                } finally {
                    stream.Close();
                }
            }
#if !CORE14
        }
#endif

            for (int i = 0; i < rawlisting.Count; i++)
            {
                buf = rawlisting[i];

                if (isNameList)
                {
                    // if NLST was used we only have a file name so
                    // there is nothing to parse.
                    item = new FtpListItem()
                    {
                        FullName = buf
                    };

                    if (DirectoryExists(item.FullName))
                    {
                        item.Type = FtpFileSystemObjectType.Directory;
                    }
                    else
                    {
                        item.Type = FtpFileSystemObjectType.File;
                    }

                    lst.Add(item);
                }
                else
                {
                    // if this is a result of LIST -R then the path will be spit out
                    // before each block of objects
                    if (listcmd.StartsWith("LIST") && isRecursive)
                    {
                        if (buf.StartsWith("/") && buf.EndsWith(":"))
                        {
                            path = buf.TrimEnd(':');
                            continue;
                        }
                    }

                    // if the next line in the listing starts with spaces
                    // it is assumed to be a continuation of the current line
                    if (i + 1 < rawlisting.Count && (rawlisting[i + 1].StartsWith("\t") || rawlisting[i + 1].StartsWith(" ")))
                    {
                        buf += rawlisting[++i];
                    }

                    item = m_listParser.ParseSingleLine(path, buf, m_caps, machineList);

                    // FtpListItem.Parse() returns null if the line
                    // could not be parsed
                    if (item != null)
                    {
                        if (isIncludeSelf || !(item.Name == "." || item.Name == ".."))
                        {
                            lst.Add(item);
                        }
                        else
                        {
                            //FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Skipped self or parent item: " + item.Name);
                        }
                    }
                    else
                    {
                        FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Failed to parse file listing: " + buf);
                    }
                }

                // load extended information that wasn't available if the list options flags say to do so.
                if (item != null)
                {
                    // try to dereference symbolic links if the appropriate list
                    // option was passed
                    if (item.Type == FtpFileSystemObjectType.Link && isDerefLinks)
                    {
                        item.LinkObject = DereferenceLink(item);
                    }

                    // if need to get file modified date
                    if (isGetModified && HasFeature(FtpCapability.MDTM))
                    {
                        // if the modified date was not loaded or the modified date is more than a day in the future
                        // and the server supports the MDTM command, load the modified date.
                        // most servers do not support retrieving the modified date
                        // of a directory but we try any way.
                        if (item.Modified == DateTime.MinValue || listcmd.StartsWith("LIST"))
                        {
                            DateTime modify;

                            if (item.Type == FtpFileSystemObjectType.Directory)
                            {
                                FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Trying to retrieve modification time of a directory, some servers don't like this...");
                            }

                            if ((modify = GetModifiedTime(item.FullName)) != DateTime.MinValue)
                            {
                                item.Modified = modify;
                            }
                        }
                    }

                    // if need to get file size
                    if (isGetSize && HasFeature(FtpCapability.SIZE))
                    {
                        // if no size was parsed, the object is a file and the server
                        // supports the SIZE command, then load the file size
                        if (item.Size == -1)
                        {
                            if (item.Type != FtpFileSystemObjectType.Directory)
                            {
                                item.Size = GetFileSize(item.FullName);
                            }
                            else
                            {
                                item.Size = 0;
                            }
                        }
                    }
                }
            }

            return(lst.ToArray());
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Returns information about a file system object. Returns null if the server response can't
        /// be parsed or the server returns a failure completion code. The error for a failure
        /// is logged with FtpTrace. No exception is thrown on error because that would negate
        /// the usefulness of this method for checking for the existence of an object.
        /// </summary>
        /// <param name="path">The path of the file or folder</param>
        /// <param name="dateModified">Get the accurate modified date using another MDTM command</param>
        /// <returns>A FtpListItem object</returns>
        public FtpListItem GetObjectInfo(string path, bool dateModified = false)
        {
            FtpTrace.WriteFunc("GetObjectInfo", new object[] { path, dateModified });

            FtpReply reply;

            string[] res;

            bool supportsMachineList = (Capabilities & FtpCapability.MLSD) == FtpCapability.MLSD;

            FtpListItem result = null;

            if (supportsMachineList)
            {
                // USE MACHINE LISTING TO GET INFO FOR A SINGLE FILE

                if ((reply = Execute("MLST " + path)).Success)
                {
                    res = reply.InfoMessages.Split('\n');
                    if (res.Length > 1)
                    {
                        string info = "";

                        for (int i = 1; i < res.Length; i++)
                        {
                            info += res[i];
                        }

                        result = m_listParser.ParseSingleLine(null, info, m_caps, true);
                    }
                }
                else
                {
                    FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Failed to get object info for path " + path + " with error " + reply.ErrorMessage);
                }
            }
            else
            {
                // USE GETLISTING TO GET ALL FILES IN DIR .. SLOWER BUT AT LEAST IT WORKS

                string        dirPath  = path.GetFtpDirectoryName();
                FtpListItem[] dirItems = GetListing(dirPath);

                foreach (var dirItem in dirItems)
                {
                    if (dirItem.FullName == path)
                    {
                        result = dirItem;
                        break;
                    }
                }

                FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Failed to get object info for path " + path + " since MLST not supported and GetListing() fails to list file/folder.");
            }

            // Get the accurate date modified using another MDTM command
            if (result != null && dateModified && HasFeature(FtpCapability.MDTM))
            {
                result.Modified = GetModifiedTime(path);
            }

            return(result);
        }
Ejemplo n.º 8
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 during the connection phase</param>
        public async Task ConnectAsync(string host, int port, FtpIpVersion ipVersions)
        {
            IPAddress[] addresses = await Dns.GetHostAddressesAsync(host);

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

            for (int i = 0; i < addresses.Length; i++)
            {
                // 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.WriteStatus(FtpTraceLevel.Verbose, "Skipped IPV4 address : " + addresses[i].ToString());
#endif
                            continue;
                        }
                        break;

                    case AddressFamily.InterNetworkV6:
                        if ((ipVersions & FtpIpVersion.IPv6) != FtpIpVersion.IPv6)
                        {
#if DEBUG
                            FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Skipped IPV6 address : " + addresses[i].ToString());
#endif
                            continue;
                        }
                        break;
                    }
                }

                if (FtpTrace.LogIP)
                {
                    FtpTrace.WriteStatus(FtpTraceLevel.Info, "Connecting to " + addresses[i].ToString() + ":" + port);
                }
                else
                {
                    FtpTrace.WriteStatus(FtpTraceLevel.Info, "Connecting to ***:" + port);
                }

                m_socket = new Socket(addresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);

#if CORE
                await m_socket.ConnectAsync(addresses[i], port);

                break;
#else
                var connectResult = m_socket.BeginConnect(addresses[i], port, null, null);
                await Task.Factory.FromAsync(connectResult, m_socket.EndConnect);

                break;
#endif
            }

            // 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;
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Disconnects from server
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            FtpTrace.WriteStatus(FtpTraceLevel.Verbose, "Disposing FtpSocketStream...");

#if !NO_SSL
            if (m_bufStream != null)
            {
                // ensure the last of the buffered bytes are flushed
                // before we close the socket and network stream
                m_bufStream.Flush();
            }
#endif

            if (m_socket != null)
            {
                try {
                    if (m_socket.Connected)
                    {
                        ////
                        // Calling Shutdown() with mono causes an
                        // exception if the remote host closed first
                        //m_socket.Shutdown(SocketShutdown.Both);
#if CORE
                        m_socket.Dispose();
#else
                        m_socket.Close();
#endif
                    }

#if !NET20 && !NET35
                    m_socket.Dispose();
#endif
                } catch (SocketException ex) {
                    FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Caught and discarded a SocketException while cleaning up the Socket: " + ex.ToString());
                } finally {
                    m_socket = null;
                }
            }

            if (m_netStream != null)
            {
                try {
                    m_netStream.Dispose();
                } catch (IOException ex) {
                    FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Caught and discarded an IOException while cleaning up the NetworkStream: " + ex.ToString());
                } finally {
                    m_netStream = null;
                }
            }

#if !NO_SSL
            if (m_sslStream != null)
            {
                try {
                    m_sslStream.Dispose();
                } catch (IOException ex) {
                    FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Caught and discarded an IOException while cleaning up the SslStream: " + ex.ToString());
                } finally {
                    m_sslStream = null;
                }
            }

            if (m_bufStream != null)
            {
                try {
                    m_bufStream.Dispose();
                } catch (IOException ex) {
                    FtpTrace.WriteStatus(FtpTraceLevel.Warn, "Caught and discarded an IOException while cleaning up the BufferedStream: " + ex.ToString());
                } finally {
                    m_bufStream = null;
                }
            }
#endif
        }