diff --git a/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj b/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj index 27fc6771..08890cce 100644 --- a/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj +++ b/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj @@ -131,7 +131,6 @@ - @@ -187,7 +186,6 @@ - diff --git a/Renci.SshClient/Renci.SshNet/Sftp/Messages/Attributes.cs b/Renci.SshClient/Renci.SshNet/Sftp/Messages/Attributes.cs deleted file mode 100644 index 6f2ee568..00000000 --- a/Renci.SshClient/Renci.SshNet/Sftp/Messages/Attributes.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Renci.SshNet.Sftp.Messages -{ - /// - /// Represents SFTP File attribute. - /// - public class SftpFileAttributes - { - /// - /// Gets or sets the size. - /// - /// - /// The size. - /// - public ulong? Size { get; set; } - - /// - /// Gets or sets the user id. - /// - /// - /// The user id. - /// - public uint? UserId { get; set; } - - /// - /// Gets or sets the group id. - /// - /// - /// The group id. - /// - public uint? GroupId { get; set; } - - /// - /// Gets or sets the permissions. - /// - /// - /// The permissions. - /// - public uint Permissions { get; set; } - - /// - /// Gets or sets the access time. - /// - /// - /// The access time. - /// - public DateTime? AccessTime { get; set; } - - /// - /// Gets or sets the modify time. - /// - /// - /// The modify time. - /// - public DateTime? ModifyTime { get; set; } - - /// - /// Gets or sets the extensions. - /// - /// - /// The extensions. - /// - public IDictionary Extensions { get; set; } - } -} diff --git a/Renci.SshClient/Renci.SshNet/Sftp/Messages/MkDirMessage.cs b/Renci.SshClient/Renci.SshNet/Sftp/Messages/MkDirMessage.cs index 447b0705..937458e2 100644 --- a/Renci.SshClient/Renci.SshNet/Sftp/Messages/MkDirMessage.cs +++ b/Renci.SshClient/Renci.SshNet/Sftp/Messages/MkDirMessage.cs @@ -13,14 +13,14 @@ public MkDirMessage() { - this.Attributes = new SftpFileAttributes(); + this.Attributes = SftpFileAttributes.Empty; } public MkDirMessage(uint requestId, string path) : base(requestId) { this.Path = path; - this.Attributes = new SftpFileAttributes(); + this.Attributes = SftpFileAttributes.Empty; } public MkDirMessage(uint requestId, string path, SftpFileAttributes attributes) diff --git a/Renci.SshClient/Renci.SshNet/Sftp/Messages/OpenMessage.cs b/Renci.SshClient/Renci.SshNet/Sftp/Messages/OpenMessage.cs index 719cf640..852e0bb5 100644 --- a/Renci.SshClient/Renci.SshNet/Sftp/Messages/OpenMessage.cs +++ b/Renci.SshClient/Renci.SshNet/Sftp/Messages/OpenMessage.cs @@ -25,7 +25,7 @@ namespace Renci.SshNet.Sftp.Messages { this.Filename = fileName; this.Flags = flags; - this.Attributes = new SftpFileAttributes(); + this.Attributes = SftpFileAttributes.Empty; } public OpenMessage(uint requestId, string fileName, Flags flags, SftpFileAttributes attributes) diff --git a/Renci.SshClient/Renci.SshNet/Sftp/Messages/SftpMessage.cs b/Renci.SshClient/Renci.SshNet/Sftp/Messages/SftpMessage.cs index f58c4a3a..7b82da9d 100644 --- a/Renci.SshClient/Renci.SshNet/Sftp/Messages/SftpMessage.cs +++ b/Renci.SshClient/Renci.SshNet/Sftp/Messages/SftpMessage.cs @@ -52,42 +52,48 @@ namespace Renci.SshNet.Sftp.Messages protected SftpFileAttributes ReadAttributes() { - var attributes = new SftpFileAttributes(); var flag = this.ReadUInt32(); + long size = -1; + int userId = -1; + int groupId = -1; + uint permissions = 0; + var accessTime = DateTime.MinValue; + var modifyTime = DateTime.MinValue; + IDictionary extensions = null; if ((flag & 0x00000001) == 0x00000001) // SSH_FILEXFER_ATTR_SIZE { - attributes.Size = this.ReadUInt64(); - + size = (long)this.ReadUInt64(); } if ((flag & 0x00000002) == 0x00000002) // SSH_FILEXFER_ATTR_UIDGID { - attributes.UserId = this.ReadUInt32(); + userId = (int)this.ReadUInt32(); - attributes.GroupId = this.ReadUInt32(); + groupId = (int)this.ReadUInt32(); } if ((flag & 0x00000004) == 0x00000004) // SSH_FILEXFER_ATTR_PERMISSIONS { - attributes.Permissions = this.ReadUInt32(); + permissions = this.ReadUInt32(); } if ((flag & 0x00000008) == 0x00000008) // SSH_FILEXFER_ATTR_ACMODTIME { var time = this.ReadUInt32(); - attributes.AccessTime = DateTime.FromFileTime((time + 11644473600) * 10000000); + accessTime = DateTime.FromFileTime((time + 11644473600) * 10000000); time = this.ReadUInt32(); - attributes.ModifyTime = DateTime.FromFileTime((time + 11644473600) * 10000000); + modifyTime = DateTime.FromFileTime((time + 11644473600) * 10000000); } if ((flag & 0x80000000) == 0x80000000) // SSH_FILEXFER_ATTR_ACMODTIME { var extendedCount = this.ReadUInt32(); - attributes.Extensions = this.ReadExtensionPair(); + extensions = this.ReadExtensionPair(); } + var attributes = new SftpFileAttributes(accessTime, modifyTime, size, userId, groupId, permissions, extensions); return attributes; } @@ -103,12 +109,12 @@ namespace Renci.SshNet.Sftp.Messages { UInt32 flag = 0; - if (attributes.Size.HasValue) + if (attributes.Size > -1) { flag |= 0x00000001; } - if (attributes.UserId.HasValue && attributes.GroupId.HasValue) + if (attributes.UserId > -1 && attributes.GroupId > -1) { flag |= 0x00000002; } @@ -118,7 +124,7 @@ namespace Renci.SshNet.Sftp.Messages flag |= 0x00000004; } - if (attributes.AccessTime.HasValue && attributes.ModifyTime.HasValue) + if (attributes.LastAccessTime > DateTime.MinValue && attributes.LastWriteTime > DateTime.MinValue) { flag |= 0x00000008; } @@ -130,15 +136,15 @@ namespace Renci.SshNet.Sftp.Messages this.Write(flag); - if (attributes.Size.HasValue) + if (attributes.Size > -1) { - this.Write(attributes.Size.Value); + this.Write((UInt64)attributes.Size); } - if (attributes.UserId.HasValue && attributes.GroupId.HasValue) + if (attributes.UserId > -1 && attributes.GroupId > -1) { - this.Write(attributes.UserId.Value); - this.Write(attributes.GroupId.Value); + this.Write((UInt32)attributes.UserId); + this.Write((UInt32)attributes.GroupId); } if (attributes.Permissions > 0) @@ -146,11 +152,11 @@ namespace Renci.SshNet.Sftp.Messages this.Write(attributes.Permissions); } - if (attributes.AccessTime.HasValue && attributes.ModifyTime.HasValue) + if (attributes.LastAccessTime > DateTime.MinValue && attributes.LastWriteTime > DateTime.MinValue) { - uint time = (uint)(attributes.AccessTime.Value.ToFileTime() / 10000000 - 11644473600); + uint time = (uint)(attributes.LastAccessTime.ToFileTime() / 10000000 - 11644473600); this.Write(time); - time = (uint)(attributes.ModifyTime.Value.ToFileTime() / 10000000 - 11644473600); + time = (uint)(attributes.LastWriteTime.ToFileTime() / 10000000 - 11644473600); this.Write(time); } diff --git a/Renci.SshClient/Renci.SshNet/Sftp/SetFileStatusCommand.cs b/Renci.SshClient/Renci.SshNet/Sftp/SetFileStatusCommand.cs deleted file mode 100644 index a0c1b1e1..00000000 --- a/Renci.SshClient/Renci.SshNet/Sftp/SetFileStatusCommand.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Renci.SshNet.Sftp.Messages; - -namespace Renci.SshNet.Sftp -{ - internal class SetFileStatusCommand : SftpCommand - { - private string _path; - - private SftpFileAttributes _attributes; - - public SftpFile SftpFile { get; private set; } - - public SetFileStatusCommand(SftpSession sftpSession, string path, SftpFileAttributes attributes) - : base(sftpSession) - { - this._path = path; - - this._attributes = attributes; - } - - protected override void OnExecute() - { - this.SendSetStatMessage(this._path, this._attributes); - } - - protected override void OnStatus(StatusCodes statusCode, string errorMessage, string language) - { - base.OnStatus(statusCode, errorMessage, language); - - if (statusCode == StatusCodes.Ok) - { - this.CompleteExecution(); - } - } - } -} diff --git a/Renci.SshClient/Renci.SshNet/Sftp/SftpFile.cs b/Renci.SshClient/Renci.SshNet/Sftp/SftpFile.cs index ad26f841..7e64a368 100644 --- a/Renci.SshClient/Renci.SshNet/Sftp/SftpFile.cs +++ b/Renci.SshClient/Renci.SshNet/Sftp/SftpFile.cs @@ -12,57 +12,10 @@ namespace Renci.SshNet.Sftp /// public class SftpFile { - #region Bitmask constats - - private static UInt32 S_IFMT = 0xF000; // bitmask for the file type bitfields - - private static UInt32 S_IFSOCK = 0xC000; // socket - - private static UInt32 S_IFLNK = 0xA000; // symbolic link - - private static UInt32 S_IFREG = 0x8000; // regular file - - private static UInt32 S_IFBLK = 0x6000; // block device - - private static UInt32 S_IFDIR = 0x4000; // directory - - private static UInt32 S_IFCHR = 0x2000; // character device - - private static UInt32 S_IFIFO = 0x1000; // FIFO - - private static UInt32 S_ISUID = 0x0800; // set UID bit - - private static UInt32 S_ISGID = 0x0400; // set-group-ID bit (see below) - - private static UInt32 S_ISVTX = 0x0200; // sticky bit (see below) - - private static UInt32 S_IRUSR = 0x0100; // owner has read permission - - private static UInt32 S_IWUSR = 0x0080; // owner has write permission - - private static UInt32 S_IXUSR = 0x0040; // owner has execute permission - - private static UInt32 S_IRGRP = 0x0020; // group has read permission - - private static UInt32 S_IWGRP = 0x0010; // group has write permission - - private static UInt32 S_IXGRP = 0x0008; // group has execute permission - - private static UInt32 S_IROTH = 0x0004; // others have read permission - - private static UInt32 S_IWOTH = 0x0002; // others have write permission - - private static UInt32 S_IXOTH = 0x0001; // others have execute permission - - #endregion - - private bool _isBitFiledsBitSet; - private bool _isUIDBitSet; - private bool _isGroupIDBitSet; - private bool _isStickyBitSet; - private SftpSession _sftpSession; + public SftpFileAttributes Attributes { get; private set; } + /// /// Initializes a new instance of the class. /// @@ -75,77 +28,11 @@ namespace Renci.SshNet.Sftp throw new ArgumentNullException("attributes"); this._sftpSession = sftpSession; + this.Attributes = attributes; this.Name = fullName.Substring(fullName.LastIndexOf('/') + 1); this.FullName = fullName; - - if (attributes.AccessTime.HasValue) - this.LastAccessTime = attributes.AccessTime.Value; - else - this.LastAccessTime = DateTime.MinValue; - - if (attributes.ModifyTime.HasValue) - this.LastWriteTime = attributes.ModifyTime.Value; - else - this.LastWriteTime = DateTime.MinValue; - - if (attributes.Size.HasValue) - this.Size = (long)attributes.Size.Value; - else - this.Size = -1; - - if (attributes.UserId.HasValue) - this.UserId = (int)attributes.UserId.Value; - else - this.UserId = -1; - - if (attributes.GroupId.HasValue) - this.GroupId = (int)attributes.GroupId.Value; - else - this.GroupId = -1; - - this._isBitFiledsBitSet = ((attributes.Permissions & S_IFMT) == S_IFMT); - - this.IsSocket = ((attributes.Permissions & S_IFSOCK) == S_IFSOCK); - - this.IsSymbolicLink = ((attributes.Permissions & S_IFLNK) == S_IFLNK); - - this.IsRegularFile = ((attributes.Permissions & S_IFREG) == S_IFREG); - - this.IsBlockDevice = ((attributes.Permissions & S_IFBLK) == S_IFBLK); - - this.IsDirectory = ((attributes.Permissions & S_IFDIR) == S_IFDIR); - - this.IsCharacterDevice = ((attributes.Permissions & S_IFCHR) == S_IFCHR); - - this.IsNamedPipe = ((attributes.Permissions & S_IFIFO) == S_IFIFO); - - this._isUIDBitSet = ((attributes.Permissions & S_ISUID) == S_ISUID); - - this._isGroupIDBitSet = ((attributes.Permissions & S_ISGID) == S_ISGID); - - this._isStickyBitSet = ((attributes.Permissions & S_ISVTX) == S_ISVTX); - - this.OwnerCanRead = ((attributes.Permissions & S_IRUSR) == S_IRUSR); - - this.OwnerCanWrite = ((attributes.Permissions & S_IWUSR) == S_IWUSR); - - this.OwnerCanExecute = ((attributes.Permissions & S_IXUSR) == S_IXUSR); - - this.GroupCanRead = ((attributes.Permissions & S_IRGRP) == S_IRGRP); - - this.GroupCanWrite = ((attributes.Permissions & S_IWGRP) == S_IWGRP); - - this.GroupCanExecute = ((attributes.Permissions & S_IXGRP) == S_IXGRP); - - this.OthersCanRead = ((attributes.Permissions & S_IROTH) == S_IROTH); - - this.OthersCanWrite = ((attributes.Permissions & S_IWOTH) == S_IWOTH); - - this.OthersCanExecute = ((attributes.Permissions & S_IXOTH) == S_IXOTH); - - this.Extensions = attributes.Extensions; } /// @@ -165,7 +52,13 @@ namespace Renci.SshNet.Sftp /// /// The time that the current file or directory was last accessed. /// - public DateTime LastAccessTime { get; private set; } + public DateTime LastAccessTime + { + get + { + return this.Attributes.LastAccessTime; + } + } /// /// Gets or sets the time when the current file or directory was last written to. @@ -173,7 +66,13 @@ namespace Renci.SshNet.Sftp /// /// The time the current file was last written. /// - public DateTime LastWriteTime { get; private set; } + public DateTime LastWriteTime + { + get + { + return this.Attributes.LastWriteTime; + } + } /// /// Gets or sets the size, in bytes, of the current file. @@ -181,7 +80,13 @@ namespace Renci.SshNet.Sftp /// /// The size of the current file in bytes. /// - public long Size { get; private set; } + public long Size + { + get + { + return this.Attributes.Size; + } + } /// /// Gets or sets file user id. @@ -189,7 +94,17 @@ namespace Renci.SshNet.Sftp /// /// File user id. /// - public int UserId { get; set; } + public int UserId + { + get + { + return this.Attributes.UserId; + } + set + { + this.Attributes.UserId = value; + } + } /// /// Gets or sets file group id. @@ -197,7 +112,17 @@ namespace Renci.SshNet.Sftp /// /// File group id. /// - public int GroupId { get; set; } + public int GroupId + { + get + { + return this.Attributes.GroupId; + } + set + { + this.Attributes.GroupId = value; + } + } /// /// Gets a value indicating whether file represents a socket. @@ -205,7 +130,13 @@ namespace Renci.SshNet.Sftp /// /// true if file represents a socket; otherwise, false. /// - public bool IsSocket { get; private set; } + public bool IsSocket + { + get + { + return this.Attributes.IsSocket; + } + } /// /// Gets a value indicating whether file represents a symbolic link. @@ -213,7 +144,13 @@ namespace Renci.SshNet.Sftp /// /// true if file represents a symbolic link; otherwise, false. /// - public bool IsSymbolicLink { get; private set; } + public bool IsSymbolicLink + { + get + { + return this.Attributes.IsSymbolicLink; + } + } /// /// Gets a value indicating whether file represents a regular file. @@ -221,7 +158,13 @@ namespace Renci.SshNet.Sftp /// /// true if file represents a regular file; otherwise, false. /// - public bool IsRegularFile { get; private set; } + public bool IsRegularFile + { + get + { + return this.Attributes.IsRegularFile; + } + } /// /// Gets a value indicating whether file represents a block device. @@ -229,7 +172,13 @@ namespace Renci.SshNet.Sftp /// /// true if file represents a block device; otherwise, false. /// - public bool IsBlockDevice { get; private set; } + public bool IsBlockDevice + { + get + { + return this.Attributes.IsBlockDevice; + } + } /// /// Gets a value indicating whether file represents a directory. @@ -237,7 +186,13 @@ namespace Renci.SshNet.Sftp /// /// true if file represents a directory; otherwise, false. /// - public bool IsDirectory { get; private set; } + public bool IsDirectory + { + get + { + return this.Attributes.IsDirectory; + } + } /// /// Gets a value indicating whether file represents a character device. @@ -245,7 +200,13 @@ namespace Renci.SshNet.Sftp /// /// true if file represents a character device; otherwise, false. /// - public bool IsCharacterDevice { get; private set; } + public bool IsCharacterDevice + { + get + { + return this.Attributes.IsCharacterDevice; + } + } /// /// Gets a value indicating whether file represents a named pipe. @@ -253,79 +214,175 @@ namespace Renci.SshNet.Sftp /// /// true if file represents a named pipe; otherwise, false. /// - public bool IsNamedPipe { get; private set; } + public bool IsNamedPipe + { + get + { + return this.Attributes.IsNamedPipe; + } + } /// - /// Gets a value indicating whether the owner can read from this file. + /// Gets or sets a value indicating whether the owner can read from this file. /// /// /// true if owner can read from this file; otherwise, false. /// - public bool OwnerCanRead { get; set; } + public bool OwnerCanRead + { + get + { + return this.Attributes.OwnerCanRead; + } + set + { + this.Attributes.OwnerCanRead = value; + } + } /// - /// Gets a value indicating whether the owner can write into this file. + /// Gets or sets a value indicating whether the owner can write into this file. /// /// /// true if owner can write into this file; otherwise, false. /// - public bool OwnerCanWrite { get; set; } + public bool OwnerCanWrite + { + get + { + return this.Attributes.OwnerCanWrite; + } + set + { + this.Attributes.OwnerCanWrite = value; + } + } /// - /// Gets a value indicating whether the owner can execute this file. + /// Gets or sets a value indicating whether the owner can execute this file. /// /// /// true if owner can execute this file; otherwise, false. /// - public bool OwnerCanExecute { get; set; } + public bool OwnerCanExecute + { + get + { + return this.Attributes.OwnerCanExecute; + } + set + { + this.Attributes.OwnerCanExecute = value; + } + } /// - /// Gets a value indicating whether the group members can read from this file. + /// Gets or sets a value indicating whether the group members can read from this file. /// /// /// true if group members can read from this file; otherwise, false. /// - public bool GroupCanRead { get; set; } + public bool GroupCanRead + { + get + { + return this.Attributes.GroupCanRead; + } + set + { + this.Attributes.GroupCanRead = value; + } + } /// - /// Gets a value indicating whether the group members can write into this file. + /// Gets or sets a value indicating whether the group members can write into this file. /// /// /// true if group members can write into this file; otherwise, false. /// - public bool GroupCanWrite { get; set; } + public bool GroupCanWrite + { + get + { + return this.Attributes.GroupCanWrite; + } + set + { + this.Attributes.GroupCanWrite = value; + } + } /// - /// Gets a value indicating whether the group members can execute this file. + /// Gets or sets a value indicating whether the group members can execute this file. /// /// /// true if group members can execute this file; otherwise, false. /// - public bool GroupCanExecute { get; set; } + public bool GroupCanExecute + { + get + { + return this.Attributes.GroupCanExecute; + } + set + { + this.Attributes.GroupCanExecute = value; + } + } /// - /// Gets a value indicating whether the others can read from this file. + /// Gets or sets a value indicating whether the others can read from this file. /// /// /// true if others can read from this file; otherwise, false. /// - public bool OthersCanRead { get; set; } + public bool OthersCanRead + { + get + { + return this.Attributes.OthersCanRead; + } + set + { + this.Attributes.OthersCanRead = value; + } + } /// - /// Gets a value indicating whether the others can write into this file. + /// Gets or sets a value indicating whether the others can write into this file. /// /// /// true if others can write into this file; otherwise, false. /// - public bool OthersCanWrite { get; set; } + public bool OthersCanWrite + { + get + { + return this.Attributes.OthersCanWrite; + } + set + { + this.Attributes.OthersCanWrite = value; + } + } /// - /// Gets a value indicating whether the others can execute this file. + /// Gets or sets a value indicating whether the others can execute this file. /// /// /// true if others can execute this file; otherwise, false. /// - public bool OthersCanExecute { get; set; } + public bool OthersCanExecute + { + get + { + return this.Attributes.OthersCanExecute; + } + set + { + this.Attributes.OthersCanExecute = value; + } + } /// /// Gets the extension part of the file. @@ -335,41 +392,13 @@ namespace Renci.SshNet.Sftp /// public IDictionary Extensions { get; private set; } - /// - /// Updates file status on the server. - /// - public void UpdateStatus() - { - using (var setCmd = new SetFileStatusCommand(this._sftpSession, this.FullName, this.GetAttributes())) - { - setCmd.CommandTimeout = TimeSpan.FromSeconds(30); - - setCmd.Execute(); - } - } - /// /// Sets file permissions. /// /// The mode. - public void SetPermissions(ushort mode) + public void SetPermissions(short mode) { - var modeBytes = mode.ToString(CultureInfo.InvariantCulture).ToArray(); - - var permission = (modeBytes[0] & 0x0F) * 8 * 8 + (modeBytes[1] & 0x0F) * 8 + (modeBytes[2] & 0x0F); - - - this.OwnerCanRead = (permission & S_IRUSR) == S_IRUSR; - this.OwnerCanWrite = (permission & S_IWUSR) == S_IWUSR; - this.OwnerCanExecute = (permission & S_IXUSR) == S_IXUSR; - - this.GroupCanRead = (permission & S_IRGRP) == S_IRGRP; - this.GroupCanWrite = (permission & S_IWGRP) == S_IWGRP; - this.GroupCanExecute = (permission & S_IXGRP) == S_IXGRP; - - this.OthersCanRead = (permission & S_IROTH) == S_IROTH; - this.OthersCanWrite = (permission & S_IWOTH) == S_IWOTH; - this.OthersCanExecute = (permission & S_IXOTH) == S_IXOTH; + this.Attributes.SetPermissions(mode); this.UpdateStatus(); } @@ -377,7 +406,6 @@ namespace Renci.SshNet.Sftp /// /// Permanently deletes a file on remote machine. /// - [SecuritySafeCritical] public void Delete() { SftpCommand cmd = null; @@ -409,7 +437,6 @@ namespace Renci.SshNet.Sftp /// Moves a specified file to a new location on remote machine, providing the option to specify a new file name. /// /// The path to move the file to, which can specify a different file name. - [SecuritySafeCritical] public void MoveTo(string destFileName) { using (var setCmd = new RenameFileCommand(this._sftpSession, this.FullName, destFileName)) @@ -421,99 +448,19 @@ namespace Renci.SshNet.Sftp } /// - /// Gets the file attributes. + /// Updates file status on the server. /// - /// - private SftpFileAttributes GetAttributes() + public void UpdateStatus() { - var attributes = new SftpFileAttributes(); - - // Populate only updateable attributes - if (this.UserId > -1) + using (var setCmd = new SetStatusCommand(this._sftpSession, this.FullName, this.Attributes)) { - attributes.UserId = new Nullable((uint)this.UserId); + setCmd.CommandTimeout = TimeSpan.FromSeconds(30); + + setCmd.Execute(); } - else - { - attributes.UserId = null; - } - - if (this.GroupId > -1) - { - attributes.GroupId = new Nullable((uint)this.GroupId); - } - else - { - attributes.GroupId = null; - } - - UInt32 permission = 0; - - if (this._isBitFiledsBitSet) - permission = permission | S_IFMT; - - if (this.IsSocket) - permission = permission | S_IFSOCK; - - if (this.IsSymbolicLink) - permission = permission | S_IFLNK; - - if (this.IsRegularFile) - permission = permission | S_IFREG; - - if (this.IsBlockDevice) - permission = permission | S_IFBLK; - - if (this.IsDirectory) - permission = permission | S_IFDIR; - - if (this.IsCharacterDevice) - permission = permission | S_IFCHR; - - if (this.IsNamedPipe) - permission = permission | S_IFIFO; - - if (this._isUIDBitSet) - permission = permission | S_ISUID; - - if (this._isGroupIDBitSet) - permission = permission | S_ISGID; - - if (this._isStickyBitSet) - permission = permission | S_ISVTX; - - if (this.OwnerCanRead) - permission = permission | S_IRUSR; - - if (this.OwnerCanWrite) - permission = permission | S_IWUSR; - - if (this.OwnerCanExecute) - permission = permission | S_IXUSR; - - if (this.GroupCanRead) - permission = permission | S_IRGRP; - - if (this.GroupCanWrite) - permission = permission | S_IWGRP; - - if (this.GroupCanExecute) - permission = permission | S_IXGRP; - - if (this.OthersCanRead) - permission = permission | S_IROTH; - - if (this.OthersCanWrite) - permission = permission | S_IWOTH; - - if (this.OthersCanExecute) - permission = permission | S_IXOTH; - - attributes.Permissions = permission; - - return attributes; } + /// /// Returns a that represents this instance. /// diff --git a/Renci.SshClient/Renci.SshNet/Sftp/SftpFileAttributes.cs b/Renci.SshClient/Renci.SshNet/Sftp/SftpFileAttributes.cs index f195c7e7..7568523c 100644 --- a/Renci.SshClient/Renci.SshNet/Sftp/SftpFileAttributes.cs +++ b/Renci.SshClient/Renci.SshNet/Sftp/SftpFileAttributes.cs @@ -2,10 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Globalization; namespace Renci.SshNet.Sftp { - public class SftpFileAttributes1 + public class SftpFileAttributes { #region Bitmask constats @@ -50,7 +51,7 @@ namespace Renci.SshNet.Sftp private static UInt32 S_IXOTH = 0x0001; // others have execute permission #endregion - + private bool _isBitFiledsBitSet; private bool _isUIDBitSet; private bool _isGroupIDBitSet; @@ -78,7 +79,7 @@ namespace Renci.SshNet.Sftp /// /// The size of the current file in bytes. /// - public long Size { get; private set; } + public long Size { get; set; } /// /// Gets or sets file user id. @@ -345,7 +346,19 @@ namespace Renci.SshNet.Sftp } } - internal SftpFileAttributes1(DateTime lastAccessTime, DateTime lastWriteTime, long size, int userId, int groupId, uint permissions) + private static SftpFileAttributes _empty = new SftpFileAttributes(DateTime.MinValue, DateTime.MinValue, -1, -1, -1, 0, null); + /// + /// Gets the empty SftpFileAttributes instance. + /// + public static SftpFileAttributes Empty + { + get + { + return SftpFileAttributes._empty; + } + } + + internal SftpFileAttributes(DateTime lastAccessTime, DateTime lastWriteTime, long size, int userId, int groupId, uint permissions, IDictionary extensions) { this.LastAccessTime = lastAccessTime; this.LastWriteTime = lastWriteTime; @@ -353,6 +366,31 @@ namespace Renci.SshNet.Sftp this.UserId = userId; this.GroupId = groupId; this.Permissions = permissions; + this.Extensions = extensions; + } + + public void SetPermissions(short mode) + { + if (mode < 0 || mode > 999) + { + throw new ArgumentOutOfRangeException("mode"); + } + + var modeBytes = mode.ToString(CultureInfo.InvariantCulture).PadLeft(3,'0').ToArray(); + + var permission = (modeBytes[0] & 0x0F) * 8 * 8 + (modeBytes[1] & 0x0F) * 8 + (modeBytes[2] & 0x0F); + + this.OwnerCanRead = (permission & S_IRUSR) == S_IRUSR; + this.OwnerCanWrite = (permission & S_IWUSR) == S_IWUSR; + this.OwnerCanExecute = (permission & S_IXUSR) == S_IXUSR; + + this.GroupCanRead = (permission & S_IRGRP) == S_IRGRP; + this.GroupCanWrite = (permission & S_IWGRP) == S_IWGRP; + this.GroupCanExecute = (permission & S_IXGRP) == S_IXGRP; + + this.OthersCanRead = (permission & S_IROTH) == S_IROTH; + this.OthersCanWrite = (permission & S_IWOTH) == S_IWOTH; + this.OthersCanExecute = (permission & S_IXOTH) == S_IXOTH; } } } diff --git a/Renci.SshClient/Renci.SshNet/Sftp/SftpFileStream.cs b/Renci.SshClient/Renci.SshNet/Sftp/SftpFileStream.cs index d7da96fa..3c896e84 100644 --- a/Renci.SshClient/Renci.SshNet/Sftp/SftpFileStream.cs +++ b/Renci.SshClient/Renci.SshNet/Sftp/SftpFileStream.cs @@ -109,10 +109,9 @@ namespace Renci.SshNet.Sftp // Update file attributes this._attributes = this._session.GetFileAttributes(this._handle); - if (this._attributes != null && this._attributes.Size.HasValue) + if (this._attributes != null && this._attributes.Size > -1) { - // TODO: Test file size that greater then long.Max - return (long)this._attributes.Size.Value; + return this._attributes.Size; } else { @@ -291,7 +290,7 @@ namespace Renci.SshNet.Sftp if (mode == FileMode.Append) { // TODO: Validate Size property value exists - this._position = (long)this._attributes.Size.Value; + this._position = this._attributes.Size; } } @@ -681,7 +680,7 @@ namespace Renci.SshNet.Sftp newPosn = this._position + offset; break; case SeekOrigin.End: - newPosn = ((long)this._attributes.Size.Value) - offset; + newPosn = this._attributes.Size - offset; break; default: break; @@ -726,7 +725,6 @@ namespace Renci.SshNet.Sftp this._bufferLen = 0; // Seek to the new position. - //newPosn = FileMethods.Seek(this._handle, offset, origin); switch (origin) { case SeekOrigin.Begin: @@ -736,16 +734,17 @@ namespace Renci.SshNet.Sftp newPosn = this._position + offset; break; case SeekOrigin.End: - newPosn = ((long)this._attributes.Size.Value) - offset; + newPosn = this._attributes.Size - offset; break; default: break; } - if (newPosn == -1) + if (newPosn < 0) { throw new EndOfStreamException(); } + this._position = newPosn; } return this._position; @@ -779,7 +778,7 @@ namespace Renci.SshNet.Sftp // Setup this object for writing. this.SetupWrite(); - this._attributes.Size = (ulong)value; + this._attributes.Size = value; this._session.SetFileAttributes(this._handle, this._attributes); } diff --git a/Renci.SshClient/Renci.SshNet/Sftp/SftpSession.cs b/Renci.SshClient/Renci.SshNet/Sftp/SftpSession.cs index 74ba2ac2..62520b1b 100644 --- a/Renci.SshClient/Renci.SshNet/Sftp/SftpSession.cs +++ b/Renci.SshClient/Renci.SshNet/Sftp/SftpSession.cs @@ -212,6 +212,18 @@ namespace Renci.SshNet.Sftp } } + public SftpFileAttributes GetFileAttributes(string path) + { + using (var cmd = new StatusCommand(this, path)) + { + cmd.CommandTimeout = this._operationTimeout; + + cmd.Execute(); + + return cmd.Attributes; + } + } + public void SetFileAttributes(byte[] handle, SftpFileAttributes attributes) { using (var cmd = new SetStatusCommand(this, handle, attributes)) @@ -222,6 +234,17 @@ namespace Renci.SshNet.Sftp } } + public void SetFileAttributes(string path, SftpFileAttributes attributes) + { + using (var cmd = new SetStatusCommand(this, path, attributes)) + { + cmd.CommandTimeout = this._operationTimeout; + + cmd.Execute(); + } + } + + internal void SendMessage(SftpMessage sftpMessage) { this._session.SendMessage(new SftpDataMessage(this._channel.RemoteChannelNumber, sftpMessage)); diff --git a/Renci.SshClient/Renci.SshNet/SftpClient.cs b/Renci.SshClient/Renci.SshNet/SftpClient.cs index 62ebe8a9..35e1e159 100644 --- a/Renci.SshClient/Renci.SshNet/SftpClient.cs +++ b/Renci.SshClient/Renci.SshNet/SftpClient.cs @@ -134,7 +134,7 @@ namespace Renci.SshNet /// /// File(s) path, may match multiple files. /// The mode. - public void ChangePermissions(string path, ushort mode) + public void ChangePermissions(string path, short mode) { if (path == null) throw new ArgumentNullException("path"); @@ -705,16 +705,6 @@ namespace Renci.SshNet return file != null; } - /// - /// Gets the System.IO.FileAttributes of the file on the path. - /// - /// The path to the file. - /// The System.IO.FileAttributes of the file on the path. - public FileAttributes GetAttributes(string path) - { - throw new NotImplementedException(); - } - /// /// Returns the date and time the specified file or directory was last accessed. /// @@ -1036,12 +1026,35 @@ namespace Renci.SshNet } } + /// + /// Gets the of the file on the path. + /// + /// The path to the file. + /// The of the file on the path. + public SftpFileAttributes GetAttributes(string path) + { + var fullPath = this._sftpSession.GetCanonicalPath(path); + + return this._sftpSession.GetFileAttributes(fullPath); + } + + /// + /// Sets the specified of the file on the specified path. + /// + /// The path to the file. + /// The desired . + public void SetAttributes(string path, SftpFileAttributes fileAttributes) + { + var fullPath = this._sftpSession.GetCanonicalPath(path); + + this._sftpSession.SetFileAttributes(fullPath, fileAttributes); + } + //public FileSecurity GetAccessControl(string path); //public FileSecurity GetAccessControl(string path, AccessControlSections includeSections); //public DateTime GetCreationTime(string path); //public DateTime GetCreationTimeUtc(string path); //public void SetAccessControl(string path, FileSecurity fileSecurity); - //public void SetAttributes(string path, FileAttributes fileAttributes); //public void SetCreationTime(string path, DateTime creationTime); //public void SetCreationTimeUtc(string path, DateTime creationTimeUtc);