Exemplo n.º 1
0
        /// <summary>
        /// Retrieves a remote file from the FTP server and writes the data to a local file
        /// specfied in the localPath parameter.
        /// </summary>
        /// <remarks>
        /// Note that some FTP servers will not accept a full path.  On those systems you must navigate to
        /// the directory you wish to get the file using with the ChangeDirectory() or ChangeDirectoryMultiPath()
        /// method.
        /// </remarks>
        /// <param name="remotePath">A path and/or file name to the remote file.</param>
        /// <param name="localPath">A fully qualified local path to a file on the local machine.</param>
        /// <param name="action">The type of action to take.</param>
        /// <seealso cref="GetFileAsync(string, string, FileAction)"/>
        /// <seealso cref="PutFile(string, string, FileAction)"/>
        /// <seealso cref="PutFileAsync(string, string, FileAction)"/>
        /// <seealso cref="MoveFile"/>
        /// <seealso cref="FxpCopy"/>
        /// <seealso cref="FxpCopyAsync"/>
        public void GetFile(string remotePath, string localPath, FileAction action)
        {
            if (remotePath == null)
                throw new ArgumentNullException("remotePath");

            if (remotePath.Length == 0)
                throw new ArgumentException("must contain a value", "remotePath");

            if (localPath == null)
                throw new ArgumentNullException("localPath");

            if (localPath.Length == 0)
                throw new ArgumentException("must contain a value", "localPath");

            if (action == FileAction.None)
                throw new ArgumentOutOfRangeException("action", "must contain a value other than 'Unknown'");

            localPath = CorrectLocalPath(localPath);

            WriteToLog(String.Format("Action='GetFile';Status='TransferBegin';LocalPath='{0}';RemotePath='{1}';FileAction='{1}'", localPath, remotePath, action.ToString()));

            FtpRequest request = new FtpRequest(base.CharacterEncoding, FtpCmd.Retr, remotePath);

            try
            {
                switch (action)
                {
                    case FileAction.CreateNew:
                        // create a file stream to stream the file locally to disk that only creates the file if it does not already exist
                        using (Stream localFile = File.Open(localPath, FileMode.CreateNew))
                        {
                            base.TransferData(TransferDirection.ToClient, request, localFile);
                        }
                        break;

                    case FileAction.Create:
                        // create a file stream to stream the file locally to disk
                        using (Stream localFile = File.Open(localPath, FileMode.Create))
                        {
                            base.TransferData(TransferDirection.ToClient, request, localFile);
                        }
                        break;
                    case FileAction.CreateOrAppend:
                        // open the local file
                        using (Stream localFile = File.Open(localPath, FileMode.OpenOrCreate))
                        {
                            // set the file position to the end so that any new data will be appended
                            localFile.Position = localFile.Length;
                            base.TransferData(TransferDirection.ToClient, request, localFile);
                        }
                        break;
                    case FileAction.Resume:
                        using (Stream localFile = File.Open(localPath, FileMode.Open))
                        {
                            //  get the size of the file already on the server (in bytes)
                            long remoteSize = GetFileSize(remotePath);

                            // if the files are the same size then there is nothing to transfer
                            if (localFile.Length == remoteSize)
                                return;

                            base.TransferData(TransferDirection.ToClient, request, localFile, localFile.Length - 1);
                        }
                        break;
                    case FileAction.ResumeOrCreate:
                        if (File.Exists(localPath) && (new FileInfo(localPath)).Length > 0)
                            GetFile(remotePath, localPath, FileAction.Resume);
                        else
                            GetFile(remotePath, localPath, FileAction.Create);
                        break;
                }
            }
            catch (Exception ex)
            {
                WriteToLog(String.Format("Action='GetFile';Status='TransferError';LocalPath='{0}';RemotePath='{1}';FileAction='{1}';ErrorMessage='{2}", localPath, remotePath, action.ToString(), ex.Message));
                throw new FtpException(String.Format("An unexpected exception occurred while retrieving file '{0}'.", remotePath), base.LastResponse, ex);
            }

            WriteToLog(String.Format("Action='GetFile';Status='TransferSuccess';LocalPath='{0}';RemotePath='{1}';FileAction='{1}'", localPath, remotePath, action.ToString()));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Retrieves a remote file from the FTP server and writes the data to a local stream object
        /// specfied in the outStream parameter.
        /// </summary> 
        /// <param name="remotePath">A path and/or file name to the remote file.</param>
        /// <param name="outStream">An output stream object used to stream the remote file to the local machine.</param>
        /// <param name="restart">A true/false value to indicate if the file download needs to be restarted due to a previous partial download.</param>
        /// <remarks>
        /// If the remote path is a file name then the file is downloaded from the FTP server current working directory.  Otherwise a fully qualified
        /// path for the remote file may be specified.  The output stream must be writeable and can be any stream object.  Finally, the restart parameter
        /// is used to send a restart command to the FTP server.  The FTP server is instructed to restart the download process at the last position of
        /// of the output stream.  Not all FTP servers support the restart command.  If the FTP server does not support the restart (REST) command,
        /// an FtpException error is thrown.
        /// Note that some FTP servers will not accept a full path.  On those systems you must navigate to
        /// the directory you wish to get the file using with the ChangeDirectory() or ChangeDirectoryMultiPath()
        /// method.
        /// </remarks>
        /// <seealso cref="GetFileAsync(string, string, FileAction)"/>
        /// <seealso cref="PutFile(string, string, FileAction)"/>
        /// <seealso cref="PutFileAsync(string, string, FileAction)"/>
        /// <seealso cref="MoveFile"/>
        /// <seealso cref="FxpCopy"/>
        /// <seealso cref="FxpCopyAsync"/>
        public void GetFile(string remotePath, Stream outStream, bool restart)
        {
            if (remotePath == null)
                throw new ArgumentNullException("remotePath");

            if (remotePath.Length == 0)
                throw new ArgumentException("must contain a value", "remotePath");

            if (outStream == null)
                throw new ArgumentNullException("outStream");

            if (outStream.CanWrite == false)
                throw new ArgumentException("must be writable.  The CanWrite property must return the value 'true'.", "outStream");

            FtpRequest request = new FtpRequest(base.CharacterEncoding, FtpCmd.Retr, remotePath);

            if (restart)
            {
                //  get the size of the file already on the server (in bytes)
                long remoteSize = GetFileSize(remotePath);

                // if the files are the same size then there is nothing to transfer
                if (outStream.Length == remoteSize)
                    return;

                base.TransferData(TransferDirection.ToClient, request, outStream, outStream.Length - 1);
            }
            else
            {
                base.TransferData(TransferDirection.ToClient, request, outStream);
            }
        }
Exemplo n.º 3
0
 internal string TransferText(FtpRequest request)
 {
     Stream output = new MemoryStream();
     TransferData(TransferDirection.ToClient, request, output);
     output.Position = 0;
     StreamReader reader = new StreamReader(output, _encoding);
     return reader.ReadToEnd();
 }
Exemplo n.º 4
0
        private void DoIntegrityCheck(FtpRequest request, Stream stream, long restartPosition)
        {
            // get the file path from the request argument
            string path = request.Arguments[0];
            long startPos = restartPosition;
            long endPos = stream.Length;

            string streamHash = ComputeChecksum(_hashAlgorithm, stream, startPos);
            string serverHash = GetChecksum(_hashAlgorithm, path, startPos, endPos);

            // string compare the dataHash to the server hash value and see if they are the same
            if (String.Compare(streamHash, serverHash, StringComparison.InvariantCultureIgnoreCase) != 0)
                throw new FtpFileIntegrityException(String.Format("File integrity check failed.  The destination integrity value '{0}' for the file '{1}' did not match the data transfer integrity value '{2}'.", serverHash, path, streamHash));
        }
Exemplo n.º 5
0
        internal void TransferData(TransferDirection direction, FtpRequest request, Stream data, long restartPosition)
        {
            if (_commandConn == null || _commandConn.Connected == false)
                throw new FtpConnectionClosedException("Connection is closed.");

            if (request == null)
                throw new ArgumentNullException("request", "value is required");

            if (data == null)
                throw new ArgumentNullException("data", "value is required");

            switch (direction)
            {
                case TransferDirection.ToClient:
                    if (!data.CanWrite)
                        throw new FtpDataTransferException("Data transfer error.  Data conn does not allow write operation.");
                    break;
                case TransferDirection.ToServer:
                    if (!data.CanRead)
                        throw new FtpDataTransferException("Data transfer error.  Data conn does not allow read operation.");
                    break;
            }

            // if this is a restart then the data stream must support seeking
            if (restartPosition > 0 && !data.CanSeek)
                throw new FtpDataTransferException("Data transfer restart error.  Data conn does not allow seek operation.");

            try
            {
                // create a thread to begin the process of opening a data connection to the remote server
                OpenDataConn();

                //  check for a restart position
                if (restartPosition > 0)
                {
                    // instruct the server to restart file transfer at the same position where the output stream left off
                    SendRequest(new FtpRequest(_encoding, FtpCmd.Rest, restartPosition.ToString(CultureInfo.InvariantCulture)));

                    // set the data stream to the same position as the server
                    data.Position = restartPosition;
                }

                // send the data transfer command that requires a separate data connection to be established to transmit data
                SendRequest(request);

                // wait for the data connection thread to signal back that a connection has been established
                WaitForDataConn();

                // test to see if the data connection failed to be established sometime the active connection fails due to security settings on the ftp server
                if (_dataConn == null)
                    throw new FtpDataConnectionException("Unable to establish a data connection to the destination.  The destination may have refused the connection.");

                // create the data stream object - handles creation of SslStream and DeflateStream objects as well
                Stream conn = _dataConn.GetStream();

                // test to see if we need to enable ssl/tls explicit mode
                if (_securityProtocol != FtpSecurityProtocol.None)
                {
                    conn = CreateSslStream(conn);
                }

                // test to see if we need to enable compression by using the DeflateStream
                if (_isCompressionEnabled)
                {
                    conn = CreateZlibStream(direction, conn);
                }

                // based on the direction of the data transfer we need to handle the input and output streams
                switch (direction)
                {
                    case TransferDirection.ToClient:
                        TransferBytes(conn, data, _maxDownloadSpeed * 1024);
                        break;
                    case TransferDirection.ToServer:
                        TransferBytes(data, conn, _maxUploadSpeed * 1024);
                        break;
                }
            }
            finally
            {
                // attempt to close the data connection
                CloseDataConn();
            }

            // if no errors occurred and this is not a quoted command then we will wait for the server to send a closing connection message
            WaitForHappyCodes(FtpResponseCode.ClosingDataConnection);

            // integrity check
            if (_hashAlgorithm != HashingFunction.None && request.IsFileTransfer)
                DoIntegrityCheck(request, data, restartPosition);
        }
Exemplo n.º 6
0
 internal void TransferData(TransferDirection direction, FtpRequest request, Stream data)
 {
     TransferData(direction, request, data, 0);
 }
Exemplo n.º 7
0
        /// <summary>
        /// Send a FTP command request to the server.
        /// </summary>
        /// <param name="request"></param>
        internal void SendRequest(FtpRequest request)
        {
            if (_commandConn == null || _commandConn.Connected == false)
                throw new FtpConnectionClosedException("Connection is closed.");

            // clear out any responses that might have been pending from a previous
            // failed operation
            DontWaitForHappyCodes();

            if (ClientRequest != null)
                ClientRequest(this, new FtpRequestEventArgs(request));

            byte[] buffer = request.GetBytes();

            try
            {
                _commandStream.Write(buffer, 0, buffer.Length);
            }
            catch (IOException ex)
            {
                throw new FtpConnectionBrokenException("Connection is broken.  Failed to send command.", ex);
            }

            // most commands will have happy codes but the quote() command does not
            if (request.HasHappyCodes)
            {
                WaitForHappyCodes(request.GetHappyCodes());
            }
            else
            {
                // when there are no happy codes given the we have to give the server some time to response
                // since we really don't know what response is the correct one
                if (request.Command != FtpCmd.Quit)
                    Thread.Sleep(2000);
                DontWaitForHappyCodes();
            }
        }
Exemplo n.º 8
0
 /// <summary>
 /// Constructor for FtpRequestEventArgs.
 /// </summary>
 /// <param name="request">An FtpRequest object.</param>
 public FtpRequestEventArgs(FtpRequest request)
 {
     _request = request;
 }
Exemplo n.º 9
0
 /// <summary>
 /// Constructor for FtpRequestEventArgs.
 /// </summary>
 /// <param name="request">An FtpRequest object.</param>
 public FtpRequestEventArgs(FtpRequest request)
 {
     _request = request;
 }