diff --git a/DearFTP/Connection/Commands/CommandsDispatcher.cs b/DearFTP/Connection/Commands/CommandsDispatcher.cs index 8f7e33d..fc130b5 100644 --- a/DearFTP/Connection/Commands/CommandsDispatcher.cs +++ b/DearFTP/Connection/Commands/CommandsDispatcher.cs @@ -25,6 +25,7 @@ namespace DearFTP.Connection.Commands new QuitCommand(), new RenameCommand(), new RetrieveCommand(), + new RestartCommand(), new SiteCommand(), new SizeCommand(), new StoreCommand(), diff --git a/DearFTP/Connection/Commands/RestartCommand.cs b/DearFTP/Connection/Commands/RestartCommand.cs new file mode 100644 index 0000000..8e753bb --- /dev/null +++ b/DearFTP/Connection/Commands/RestartCommand.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DearFTP.Connection.Commands +{ + class RestartCommand : ICommand + { + public string[] Aliases { get; } = new string[] + { + "REST" + }; + + public void Execute(Session session, FtpStream stream, string alias, string argument) + { + if (uint.TryParse(argument, out uint position)) + { + session.RestartPosition = (int)position; + stream.Send(ResponseCode.PendingFurtherInformation, $"Restart position set to {position}."); + } + else + { + stream.Send(ResponseCode.ArgumentsError, "Specified position is not a valid number."); + } + } + } +} diff --git a/DearFTP/Connection/Commands/RetrieveCommand.cs b/DearFTP/Connection/Commands/RetrieveCommand.cs index 6045d6d..955129b 100644 --- a/DearFTP/Connection/Commands/RetrieveCommand.cs +++ b/DearFTP/Connection/Commands/RetrieveCommand.cs @@ -40,28 +40,44 @@ namespace DearFTP.Connection.Commands stream.Send(ResponseCode.FileStatusOK, "File coming."); - SendFile(dataConnection.Stream, realPath); + int restartPosition = session.RestartPosition; + session.RestartPosition = 0; + + SendFile(dataConnection.Stream, realPath, restartPosition); dataConnection.Close(); stream.Send(ResponseCode.CloseDataConnection, "File sent."); } - private void SendFile(Stream stream, string path) + private void SendFile(Stream stream, string path, int offset) { using (var file = File.OpenRead(path)) { + if (offset != 0) + { + file.Seek(offset, SeekOrigin.Begin); + } + Span buffer = stackalloc byte[BufferSize]; long bytesToWrite = Math.Min(file.Length - file.Position, BufferSize); while (file.Read(buffer) > 0) { - if (bytesToWrite < BufferSize) + try { - stream.Write(buffer.Slice(0, (int)bytesToWrite)); - break; + if (bytesToWrite < BufferSize) + { + stream.Write(buffer.Slice(0, (int)bytesToWrite)); + break; + } + + stream.Write(buffer); + } + catch (Exception) + { + return; } - stream.Write(buffer); bytesToWrite = Math.Min(file.Length - file.Position, BufferSize); } diff --git a/DearFTP/Connection/Session.cs b/DearFTP/Connection/Session.cs index 682cbc0..ee42d77 100644 --- a/DearFTP/Connection/Session.cs +++ b/DearFTP/Connection/Session.cs @@ -19,11 +19,12 @@ namespace DearFTP.Connection public User User { get; set; } public Share[] Shares { get; set; } public Share[] WritablesShares { get; set; } - public FtpStream FtpStream { get; } public NavigablePath NavigablePath { get; set; } + public FtpStream FtpStream { get; } + public DataConnection DataConnection { get; set; } + public int RestartPosition { get; set; } public string CurrentWorkingDirectory => NavigablePath.CurrentDirectory; public string IP => ((IPEndPoint)_client.Client.LocalEndPoint).Address.ToString(); - public DataConnection DataConnection { get; set; } private TcpClient _client; private NetworkStream _networkStream; @@ -39,6 +40,7 @@ namespace DearFTP.Connection CommandsDispatcher = FtpServer.Instance.CommandsDispatcher; Logger = FtpServer.Instance.Logger; DataConnection = new DataConnection(); + RestartPosition = 0; } public void Start()