| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 | using System;using System.Buffers.Binary;using Microsoft.VisualStudio.TestTools.UnitTesting;using Renci.SshNet.Common;using Renci.SshNet.Sftp;namespace Renci.SshNet.Tests.Classes.Sftp{    [TestClass]    public class SftpFileAttributesTest    {        [TestMethod]        [DataRow(0xC000u, true, false, false, false, false, false, false)] // Socket        [DataRow(0xA000u, false, true, false, false, false, false, false)] // Symbolic link        [DataRow(0x8000u, false, false, true, false, false, false, false)] // Regular file        [DataRow(0x6000u, false, false, false, true, false, false, false)] // Block device        [DataRow(0x4000u, false, false, false, false, true, false, false)] // Directory        [DataRow(0x2000u, false, false, false, false, false, true, false)] // Character device        [DataRow(0x1000u, false, false, false, false, false, false, true)] // Named pipe        public void FileTypePropertiesAreMutuallyExclusive(            uint permissions,            bool isSocket,            bool isSymbolicLink,            bool isRegularFile,            bool isBlockDevice,            bool isDirectory,            bool isCharacterDevice,            bool isNamedPipe)        {            var attributeBytes = new byte[8];            attributeBytes[3] = 0x4; // SSH_FILEXFER_ATTR_PERMISSIONS            BinaryPrimitives.WriteUInt32BigEndian(attributeBytes.AsSpan(4), permissions);            var attributes = SftpFileAttributes.FromBytes(attributeBytes);            Assert.AreEqual(isSocket, attributes.IsSocket);            Assert.AreEqual(isSymbolicLink, attributes.IsSymbolicLink);            Assert.AreEqual(isRegularFile, attributes.IsRegularFile);            Assert.AreEqual(isBlockDevice, attributes.IsBlockDevice);            Assert.AreEqual(isDirectory, attributes.IsDirectory);            Assert.AreEqual(isCharacterDevice, attributes.IsCharacterDevice);            Assert.AreEqual(isNamedPipe, attributes.IsNamedPipe);        }        [TestMethod]        public void FromBytesGetBytes()        {            // 81a4 in hex = 100644 in octal            var attributes = SftpFileAttributes.FromBytes([0, 0, 0, 0x4, 0, 0, 0x81, 0xa4]);            Assert.IsTrue(attributes.IsRegularFile);            Assert.IsFalse(attributes.IsUIDBitSet);            Assert.IsFalse(attributes.IsGroupIDBitSet);            Assert.IsFalse(attributes.IsStickyBitSet);            Assert.IsTrue(attributes.OwnerCanRead);            Assert.IsTrue(attributes.OwnerCanWrite);            Assert.IsFalse(attributes.OwnerCanExecute);            Assert.IsTrue(attributes.GroupCanRead);            Assert.IsFalse(attributes.GroupCanWrite);            Assert.IsFalse(attributes.GroupCanExecute);            Assert.IsTrue(attributes.OthersCanRead);            Assert.IsFalse(attributes.OthersCanWrite);            Assert.IsFalse(attributes.OthersCanExecute);            Assert.AreEqual(-1, attributes.Size); // Erm, OK?            Assert.AreEqual(-1, attributes.UserId);            Assert.AreEqual(-1, attributes.GroupId);            Assert.AreEqual(default, attributes.LastAccessTimeUtc);            Assert.AreEqual(DateTimeKind.Utc, attributes.LastAccessTimeUtc.Kind);            Assert.AreEqual(default, attributes.LastWriteTimeUtc);            Assert.AreEqual(DateTimeKind.Utc, attributes.LastWriteTimeUtc.Kind);            Assert.AreEqual("-rw-r--r--", attributes.ToString());            // No changes            CollectionAssert.AreEqual(                new byte[] { 0, 0, 0, 0 },                attributes.GetBytes());            // Permissions change            attributes.IsUIDBitSet = true;            attributes.OwnerCanExecute = true;            CollectionAssert.AreEqual(                new byte[] { 0, 0, 0, 0x4, 0, 0, 0x89, 0xe4 },                attributes.GetBytes());            Assert.AreEqual("-rwsr--r--", attributes.ToString());            // Size change            attributes.Size = 123;            CollectionAssert.AreEqual(                new byte[] {                    0, 0, 0, 0x1 | 0x4,                    0, 0, 0, 0, 0, 0, 0, 123,                    0, 0, 0x89, 0xe4 },                attributes.GetBytes());            Assert.IsTrue(attributes.ToString().StartsWith("-rwsr--r-- Size: ", StringComparison.Ordinal));            // Uid/gid change            attributes.UserId = 99;            attributes.GroupId = 66;            CollectionAssert.AreEqual(                new byte[] {                    0, 0, 0, 0x1 | 0x2 | 0x4,                    0, 0, 0, 0, 0, 0, 0, 123,                    0, 0, 0, 99, 0, 0, 0, 66,                    0, 0, 0x89, 0xe4 },                attributes.GetBytes());            // Access/mod time change            attributes.LastAccessTimeUtc = new DateTime(2025, 08, 10, 17, 51, 37, DateTimeKind.Unspecified);            attributes.LastWriteTime = new DateTimeOffset(2016, 12, 02, 13, 18, 20, TimeSpan.FromHours(3)).LocalDateTime;            var expectedTimeBytes = new byte[8];            BinaryPrimitives.WriteUInt32BigEndian(expectedTimeBytes, 1754848297);            BinaryPrimitives.WriteUInt32BigEndian(expectedTimeBytes.AsSpan(4), 1480673900);            CollectionAssert.AreEqual(                new byte[] {                    0, 0, 0, 0x1 | 0x2 | 0x4 | 0x8,                    0, 0, 0, 0, 0, 0, 0, 123,                    0, 0, 0, 99, 0, 0, 0, 66,                    0, 0, 0x89, 0xe4                }.Concat(expectedTimeBytes),                attributes.GetBytes());            Assert.AreEqual(new DateTime(2016, 12, 02, 10, 18, 20, DateTimeKind.Utc), attributes.LastWriteTimeUtc);            Assert.AreEqual(DateTimeKind.Utc, attributes.LastWriteTimeUtc.Kind);            var attributesString = attributes.ToString();            Assert.IsTrue(attributesString.StartsWith("-rwsr--r-- Size: ", StringComparison.Ordinal));            Assert.Contains(" LastWriteTime: ", attributesString, StringComparison.CurrentCulture);        }        [TestMethod]        [DataRow((short)8888)]        [DataRow((short)10000)]        [DataRow((short)8000)]        [DataRow((short)0080)]        [DataRow((short)0008)]        [DataRow((short)1797)]        [DataRow((short)-1)]        [DataRow(short.MaxValue)]        public void SetPermissions_InvalidMode_ThrowsArgumentOutOfRangeException(short mode)        {            var attributes = SftpFileAttributes.FromBytes([0, 0, 0, 0]);            var ex = Assert.Throws<ArgumentOutOfRangeException>(() => attributes.SetPermissions(mode));            Assert.AreEqual("mode", ex.ParamName);        }        [TestMethod]        [DataRow((short)0777, false, false, false, true, true, true, true, true, true, true, true, true)]        [DataRow((short)0755, false, false, false, true, true, true, true, false, true, true, false, true)]        [DataRow((short)0644, false, false, false, true, true, false, true, false, false, true, false, false)]        [DataRow((short)0444, false, false, false, true, false, false, true, false, false, true, false, false)]        [DataRow((short)0000, false, false, false, false, false, false, false, false, false, false, false, false)]        [DataRow((short)4700, true, false, false, true, true, true, false, false, false, false, false, false)]        [DataRow((short)3001, false, true, true, false, false, false, false, false, false, false, false, true)]        [DataRow((short)7777, true, true, true, true, true, true, true, true, true, true, true, true)]        public void SetPermissions_ValidMode(            short mode,            bool setUid, bool setGid, bool sticky,            bool ownerRead, bool ownerWrite, bool ownerExec,            bool groupRead, bool groupWrite, bool groupExec,            bool othersRead, bool othersWrite, bool othersExec)        {            var attributes = SftpFileAttributes.FromBytes([0, 0, 0, 0]);            attributes.SetPermissions(mode);            Assert.AreEqual(setUid, attributes.IsUIDBitSet);            Assert.AreEqual(setGid, attributes.IsGroupIDBitSet);            Assert.AreEqual(sticky, attributes.IsStickyBitSet);            Assert.AreEqual(ownerRead, attributes.OwnerCanRead);            Assert.AreEqual(ownerWrite, attributes.OwnerCanWrite);            Assert.AreEqual(ownerExec, attributes.OwnerCanExecute);            Assert.AreEqual(groupRead, attributes.GroupCanRead);            Assert.AreEqual(groupWrite, attributes.GroupCanWrite);            Assert.AreEqual(groupExec, attributes.GroupCanExecute);            Assert.AreEqual(othersRead, attributes.OthersCanRead);            Assert.AreEqual(othersWrite, attributes.OthersCanWrite);            Assert.AreEqual(othersExec, attributes.OthersCanExecute);        }        [TestMethod]        [DataRow(0xC000u, (short)1770, "srwxrwx--T")] // Socket        [DataRow(0xA000u, (short)2707, "lrwx--Srwx")] // Symbolic link        [DataRow(0x8000u, (short)4755, "-rwsr-xr-x")] // Regular file        [DataRow(0x8000u, (short)4644, "-rwSr--r--")] // Regular file        [DataRow(0x6000u, (short)2711, "brwx--s--x")] // Block device        [DataRow(0x4000u, (short)1777, "drwxrwxrwt")] // Directory        [DataRow(0x4000u, (short)1776, "drwxrwxrwT")] // Directory        [DataRow(0x2000u, (short)0660, "crw-rw----")] // Character device        [DataRow(0x1000u, (short)0022, "p----w--w-")] // Named pipe        public void ToStringWithPermissions(            uint fileType,            short permissions,            string expected)        {            var attributeBytes = new byte[8];            attributeBytes[3] = 0x4; // SSH_FILEXFER_ATTR_PERMISSIONS            BinaryPrimitives.WriteUInt32BigEndian(attributeBytes.AsSpan(4), fileType);            var attributes = SftpFileAttributes.FromBytes(attributeBytes);            attributes.SetPermissions(permissions);            Assert.AreEqual(expected, attributes.ToString());        }    }}
 |