From 4e26ff3954624aa9625dcb2e7eeac38c173dc17b Mon Sep 17 00:00:00 2001 From: olegkap_cp Date: Fri, 10 Sep 2010 14:51:17 +0000 Subject: [PATCH] Fix SFTP TODO items and some bug while downloading file. --- .../Renci.SshClient/Channels/ChannelSftp.cs | 31 ++++++-- .../Renci.SshClient/Common/FtpFileInfo.cs | 14 ++-- .../Messages/Sftp/Attributes.cs | 14 ++-- .../Messages/Sftp/SftpMessage.cs | 79 +++++++++++-------- .../Messages/Sftp/StatusMessage.cs | 10 +-- 5 files changed, 86 insertions(+), 62 deletions(-) diff --git a/Renci.SshClient/Renci.SshClient/Channels/ChannelSftp.cs b/Renci.SshClient/Renci.SshClient/Channels/ChannelSftp.cs index f93e06e6..cfd530d9 100644 --- a/Renci.SshClient/Renci.SshClient/Channels/ChannelSftp.cs +++ b/Renci.SshClient/Renci.SshClient/Channels/ChannelSftp.cs @@ -62,7 +62,7 @@ namespace Renci.SshClient.Channels this.SendMessage(new InitMessage { - Version = 6, + Version = 3, }); var versionMessage = this.ReceiveMessage(); @@ -128,7 +128,7 @@ namespace Renci.SshClient.Channels while ((data = this.RemoteRead(handle, offset, bufferSize)) != null) { var fileData = data.GetSshBytes().ToArray(); - destination.Write(fileData, 0, (int)bufferSize); + destination.Write(fileData, 0, fileData.Length); destination.Flush(); offset += (ulong)fileData.Length; } @@ -216,6 +216,7 @@ namespace Renci.SshClient.Channels this._channelRequestSuccessWaitHandle.Set(); } + protected override void OnChannelData(string data) { base.OnChannelData(data); @@ -243,8 +244,15 @@ namespace Renci.SshClient.Channels this._packetData = null; - // TODO: Handle SSH_FXP_STATUS here - // TODO: Validate message request id is correct + if (sftpMessage.RequestId != null) + { + if (sftpMessage.RequestId != this._requestId) + { + throw new InvalidOperationException("Invalid request id."); + } + + this._requestId++; + } this._responseMessage = sftpMessage; @@ -302,7 +310,7 @@ namespace Renci.SshClient.Channels private void SendMessage(SftpMessage sftpMessage) { - sftpMessage.RequestId = this._requestId++; + sftpMessage.RequestId = this._requestId; var message = new SftpDataMessage { ChannelNumber = this.ServerChannelNumber, @@ -465,7 +473,18 @@ namespace Renci.SshClient.Channels }); var status = this.ReceiveMessage(); - // TODO: If close is fails wait a litle a try to close it again, in case server fluashed data into the file during close + var attempts = 0; + // If close is fails wait a litle a try to close it again, in case server flushed data into the file during close + while (status.StatusCode != StatusCodes.Ok && attempts++ < this.Session.ConnectionInfo.RetryAttempts) + { + Thread.Sleep(50); + status = this.ReceiveMessage(); + } + + if (status.StatusCode != StatusCodes.Ok) + { + throw new InvalidOperationException(string.Format("File handle cannot be closed after {0} attempts.", attempts)); + } } private Attributes GetRemoteFileAttributes(string filename) diff --git a/Renci.SshClient/Renci.SshClient/Common/FtpFileInfo.cs b/Renci.SshClient/Renci.SshClient/Common/FtpFileInfo.cs index 4296eb8a..7a479415 100644 --- a/Renci.SshClient/Renci.SshClient/Common/FtpFileInfo.cs +++ b/Renci.SshClient/Renci.SshClient/Common/FtpFileInfo.cs @@ -9,19 +9,19 @@ namespace Renci.SshClient.Common public string FullName { get; set; } - public DateTime CreationTime { get; set; } + public DateTime? CreationTime { get; set; } - public DateTime LastAccessTime { get; set; } + public DateTime? LastAccessTime { get; set; } - public DateTime LastModifyTime { get; set; } + public DateTime? LastModifyTime { get; set; } - public ulong Size { get; set; } + public ulong? Size { get; set; } - public uint UserId { get; set; } + public uint? UserId { get; set; } - public uint GroupId { get; set; } + public uint? GroupId { get; set; } - public uint Permissions { get; set; } + public uint? Permissions { get; set; } public IDictionary Extentions { get; set; } diff --git a/Renci.SshClient/Renci.SshClient/Messages/Sftp/Attributes.cs b/Renci.SshClient/Renci.SshClient/Messages/Sftp/Attributes.cs index cc53809e..7b9518f9 100644 --- a/Renci.SshClient/Renci.SshClient/Messages/Sftp/Attributes.cs +++ b/Renci.SshClient/Renci.SshClient/Messages/Sftp/Attributes.cs @@ -5,19 +5,17 @@ namespace Renci.SshClient.Messages.Sftp { internal class Attributes { - public UInt32 Flag { get; set; } + public ulong? Size { get; set; } - public ulong Size { get; set; } + public uint? UserId { get; set; } - public uint UserId { get; set; } + public uint? GroupId { get; set; } - public uint GroupId { get; set; } + public uint? Permissions { get; set; } - public uint Permissions { get; set; } + public DateTime? AccessTime { get; set; } - public DateTime AccessTime { get; set; } - - public DateTime ModifyTime { get; set; } + public DateTime? ModifyTime { get; set; } public IDictionary Extentions { get; set; } } diff --git a/Renci.SshClient/Renci.SshClient/Messages/Sftp/SftpMessage.cs b/Renci.SshClient/Renci.SshClient/Messages/Sftp/SftpMessage.cs index 43965b14..296da407 100644 --- a/Renci.SshClient/Renci.SshClient/Messages/Sftp/SftpMessage.cs +++ b/Renci.SshClient/Renci.SshClient/Messages/Sftp/SftpMessage.cs @@ -72,33 +72,27 @@ namespace Renci.SshClient.Messages.Sftp protected Attributes ReadAttributes() { var attributes = new Attributes(); - attributes.Flag = this.ReadUInt32(); - var isSize = (attributes.Flag & 0x00000001) == 0x00000001; //SSH_FILEXFER_ATTR_SIZE 0x00000001 - var isUidGid = (attributes.Flag & 0x00000002) == 0x00000002; //SSH_FILEXFER_ATTR_UIDGID 0x00000002 - var isPermissions = (attributes.Flag & 0x00000004) == 0x00000004; //SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004 - var isAccessModifyTime = (attributes.Flag & 0x00000008) == 0x00000008; //SSH_FILEXFER_ATTR_ACMODTIME 0x00000008 + var flag = this.ReadUInt32(); - var isExtended = (attributes.Flag & 0x80000000) == 0x80000000; //SSH_FILEXFER_ATTR_EXTENDED 0x80000000 - - if (isSize) + if ((flag & 0x00000001) == 0x00000001) // SSH_FILEXFER_ATTR_SIZE { attributes.Size = this.ReadUInt64(); } - if (isUidGid) + if ((flag & 0x00000002) == 0x00000002) // SSH_FILEXFER_ATTR_UIDGID { attributes.UserId = this.ReadUInt32(); attributes.GroupId = this.ReadUInt32(); } - if (isPermissions) + if ((flag & 0x00000004) == 0x00000004) // SSH_FILEXFER_ATTR_PERMISSIONS { attributes.Permissions = this.ReadUInt32(); } - if (isAccessModifyTime) + if ((flag & 0x00000008) == 0x00000008) // SSH_FILEXFER_ATTR_ACMODTIME { var time = this.ReadUInt32(); attributes.AccessTime = DateTime.FromFileTime((time + 11644473600) * 10000000); @@ -106,7 +100,7 @@ namespace Renci.SshClient.Messages.Sftp attributes.ModifyTime = DateTime.FromFileTime((time + 11644473600) * 10000000); } - if (isExtended) + if ((flag & 0x80000000) == 0x80000000) // SSH_FILEXFER_ATTR_ACMODTIME { var extendedCount = this.ReadUInt32(); attributes.Extentions = this.ReadExtensionPair(); @@ -117,7 +111,6 @@ namespace Renci.SshClient.Messages.Sftp protected void Write(Attributes attributes) { - // TODO: Complete attribute serialization, at this point we pass no attributes if (attributes == null) { this.Write((uint)0); @@ -125,42 +118,60 @@ namespace Renci.SshClient.Messages.Sftp } else { - // TODO: Need to be tested - throw new NotImplementedException(); + UInt32 flag = 0; - var isSize = (attributes.Flag & 0x00000001) == 0x00000001; //SSH_FILEXFER_ATTR_SIZE 0x00000001 - var isUidGid = (attributes.Flag & 0x00000002) == 0x00000002; //SSH_FILEXFER_ATTR_UIDGID 0x00000002 - var isPermissions = (attributes.Flag & 0x00000004) == 0x00000004; //SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004 - var isAccessModifyTime = (attributes.Flag & 0x00000008) == 0x00000008; //SSH_FILEXFER_ATTR_ACMODTIME 0x00000008 - - var isExtended = (attributes.Flag & 0x80000000) == 0x80000000; //SSH_FILEXFER_ATTR_EXTENDED 0x80000000 - - if (isSize) + if (attributes.Size.HasValue) { - this.Write(attributes.Size); + flag |= 0x00000001; } - if (isUidGid) + if (attributes.UserId.HasValue && attributes.GroupId.HasValue) { - this.Write(attributes.UserId); - - this.Write(attributes.GroupId); + flag |= 0x00000002; } - if (isPermissions) + if (attributes.Permissions.HasValue) { - this.Write(attributes.Permissions); + flag |= 0x00000004; } - if (isAccessModifyTime) + if (attributes.AccessTime.HasValue && attributes.ModifyTime.HasValue) { - uint time = (uint)(attributes.AccessTime.ToFileTime() - 11644473600) / 10000000; + flag |= 0x00000008; + } + + if (attributes.Extentions != null) + { + flag |= 0x80000000; + } + + this.Write(flag); + + if (attributes.Size.HasValue) + { + this.Write(attributes.Size.Value); + } + + if (attributes.UserId.HasValue && attributes.GroupId.HasValue) + { + this.Write(attributes.UserId.Value); + this.Write(attributes.GroupId.Value); + } + + if (attributes.Permissions.HasValue) + { + this.Write(attributes.Permissions.Value); + } + + if (attributes.AccessTime.HasValue && attributes.ModifyTime.HasValue) + { + uint time = (uint)(attributes.AccessTime.Value.ToFileTime() / 10000000 - 11644473600); this.Write(time); - time = (uint)(attributes.ModifyTime.ToFileTime() - 11644473600) / 10000000; + time = (uint)(attributes.ModifyTime.Value.ToFileTime() / 10000000 - 11644473600); this.Write(time); } - if (isExtended) + if (attributes.Extentions != null) { this.Write(attributes.Extentions); } diff --git a/Renci.SshClient/Renci.SshClient/Messages/Sftp/StatusMessage.cs b/Renci.SshClient/Renci.SshClient/Messages/Sftp/StatusMessage.cs index efef4180..846287d3 100644 --- a/Renci.SshClient/Renci.SshClient/Messages/Sftp/StatusMessage.cs +++ b/Renci.SshClient/Renci.SshClient/Messages/Sftp/StatusMessage.cs @@ -47,21 +47,17 @@ this.ErrorMessage = this.ReadString(); this.Language = this.ReadString(); } - // TODO: Load error specific data } protected override void SaveData() { base.SaveData(); this.Write((uint)this.StatusCode); - if (this.StatusCode == StatusCodes.Ok) + if (!string.IsNullOrEmpty(this.ErrorMessage)) { - // No more data need to be written - return; + this.Write(this.ErrorMessage); + this.Write(this.Language); } - this.Write(this.ErrorMessage); - this.Write(this.Language); - // TODO: Save error specific data } } }