SftpFileAttributes
Contains SFTP file attributes.
            
                using Renci.SshNet.Common;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace Renci.SshNet.Sftp
{
    public class SftpFileAttributes
    {
        private const uint S_IFMT = 61440;
        private const uint S_IFSOCK = 49152;
        private const uint S_IFLNK = 40960;
        private const uint S_IFREG = 32768;
        private const uint S_IFBLK = 24576;
        private const uint S_IFDIR = 16384;
        private const uint S_IFCHR = 8192;
        private const uint S_IFIFO = 4096;
        private const uint S_ISUID = 2048;
        private const uint S_ISGID = 1024;
        private const uint S_ISVTX = 512;
        private const uint S_IRUSR = 256;
        private const uint S_IWUSR = 128;
        private const uint S_IXUSR = 64;
        private const uint S_IRGRP = 32;
        private const uint S_IWGRP = 16;
        private const uint S_IXGRP = 8;
        private const uint S_IROTH = 4;
        private const uint S_IWOTH = 2;
        private const uint S_IXOTH = 1;
        private readonly DateTime _originalLastAccessTimeUtc;
        private readonly DateTime _originalLastWriteTimeUtc;
        private readonly long _originalSize;
        private readonly int _originalUserId;
        private readonly int _originalGroupId;
        private readonly uint _originalPermissions;
        private readonly IDictionary<string, string> _originalExtensions;
        private bool _isBitFiledsBitSet;
        private bool _isUIDBitSet;
        private bool _isGroupIDBitSet;
        private bool _isStickyBitSet;
        internal static readonly SftpFileAttributes Empty = new SftpFileAttributes();
        internal bool IsLastAccessTimeChanged => _originalLastAccessTimeUtc != LastAccessTimeUtc;
        internal bool IsLastWriteTimeChanged => _originalLastWriteTimeUtc != LastWriteTimeUtc;
        internal bool IsSizeChanged => _originalSize != Size;
        internal bool IsUserIdChanged => _originalUserId != UserId;
        internal bool IsGroupIdChanged => _originalGroupId != GroupId;
        internal bool IsPermissionsChanged => _originalPermissions != Permissions;
        internal bool IsExtensionsChanged {
            get {
                if (_originalExtensions != null && Extensions != null)
                    return !_originalExtensions.SequenceEqual(Extensions);
                return false;
            }
        }
        public DateTime LastAccessTime {
            get {
                return ToLocalTime(LastAccessTimeUtc);
            }
            set {
                LastAccessTimeUtc = ToUniversalTime(value);
            }
        }
        public DateTime LastWriteTime {
            get {
                return ToLocalTime(LastWriteTimeUtc);
            }
            set {
                LastWriteTimeUtc = ToUniversalTime(value);
            }
        }
        public DateTime LastAccessTimeUtc { get; set; }
        public DateTime LastWriteTimeUtc { get; set; }
        public long Size { get; set; }
        public int UserId { get; set; }
        public int GroupId { get; set; }
        public bool IsSocket { get; set; }
        public bool IsSymbolicLink { get; set; }
        public bool IsRegularFile { get; set; }
        public bool IsBlockDevice { get; set; }
        public bool IsDirectory { get; set; }
        public bool IsCharacterDevice { get; set; }
        public bool IsNamedPipe { get; set; }
        public bool OwnerCanRead { get; set; }
        public bool OwnerCanWrite { get; set; }
        public bool OwnerCanExecute { get; set; }
        public bool GroupCanRead { get; set; }
        public bool GroupCanWrite { get; set; }
        public bool GroupCanExecute { get; set; }
        public bool OthersCanRead { get; set; }
        public bool OthersCanWrite { get; set; }
        public bool OthersCanExecute { get; set; }
        public IDictionary<string, string> Extensions { get; set; }
        internal uint Permissions {
            get {
                uint num = 0;
                if (_isBitFiledsBitSet)
                    num |= 61440;
                if (IsSocket)
                    num |= 49152;
                if (IsSymbolicLink)
                    num |= 40960;
                if (IsRegularFile)
                    num |= 32768;
                if (IsBlockDevice)
                    num |= 24576;
                if (IsDirectory)
                    num |= 16384;
                if (IsCharacterDevice)
                    num |= 8192;
                if (IsNamedPipe)
                    num |= 4096;
                if (_isUIDBitSet)
                    num |= 2048;
                if (_isGroupIDBitSet)
                    num |= 1024;
                if (_isStickyBitSet)
                    num |= 512;
                if (OwnerCanRead)
                    num |= 256;
                if (OwnerCanWrite)
                    num |= 128;
                if (OwnerCanExecute)
                    num |= 64;
                if (GroupCanRead)
                    num |= 32;
                if (GroupCanWrite)
                    num |= 16;
                if (GroupCanExecute)
                    num |= 8;
                if (OthersCanRead)
                    num |= 4;
                if (OthersCanWrite)
                    num |= 2;
                if (OthersCanExecute)
                    num |= 1;
                return num;
            }
            private set {
                _isBitFiledsBitSet = ((value & 61440) == 61440);
                IsSocket = ((value & 49152) == 49152);
                IsSymbolicLink = ((value & 40960) == 40960);
                IsRegularFile = ((value & 32768) == 32768);
                IsBlockDevice = ((value & 24576) == 24576);
                IsDirectory = ((value & 16384) == 16384);
                IsCharacterDevice = ((value & 8192) == 8192);
                IsNamedPipe = ((value & 4096) == 4096);
                _isUIDBitSet = ((value & 2048) == 2048);
                _isGroupIDBitSet = ((value & 1024) == 1024);
                _isStickyBitSet = ((value & 512) == 512);
                OwnerCanRead = ((value & 256) == 256);
                OwnerCanWrite = ((value & 128) == 128);
                OwnerCanExecute = ((value & 64) == 64);
                GroupCanRead = ((value & 32) == 32);
                GroupCanWrite = ((value & 16) == 16);
                GroupCanExecute = ((value & 8) == 8);
                OthersCanRead = ((value & 4) == 4);
                OthersCanWrite = ((value & 2) == 2);
                OthersCanExecute = ((value & 1) == 1);
            }
        }
        private SftpFileAttributes()
        {
        }
        internal SftpFileAttributes(DateTime lastAccessTimeUtc, DateTime lastWriteTimeUtc, long size, int userId, int groupId, uint permissions, IDictionary<string, string> extensions)
        {
            LastAccessTimeUtc = (_originalLastAccessTimeUtc = lastAccessTimeUtc);
            LastWriteTimeUtc = (_originalLastWriteTimeUtc = lastWriteTimeUtc);
            Size = (_originalSize = size);
            UserId = (_originalUserId = userId);
            GroupId = (_originalGroupId = groupId);
            Permissions = (_originalPermissions = permissions);
            Extensions = (_originalExtensions = extensions);
        }
        public void SetPermissions(short mode)
        {
            if ((mode < 0 || mode > 999) ? true : false)
                throw new ArgumentOutOfRangeException("mode");
            char[] array = mode.ToString(CultureInfo.InvariantCulture).PadLeft(3, '0').ToCharArray();
            int num = (array[0] & 15) * 8 * 8 + (array[1] & 15) * 8 + (array[2] & 15);
            OwnerCanRead = (((long)num & 256) == 256);
            OwnerCanWrite = (((long)num & 128) == 128);
            OwnerCanExecute = (((long)num & 64) == 64);
            GroupCanRead = (((long)num & 32) == 32);
            GroupCanWrite = (((long)num & 16) == 16);
            GroupCanExecute = (((long)num & 8) == 8);
            OthersCanRead = (((long)num & 4) == 4);
            OthersCanWrite = (((long)num & 2) == 2);
            OthersCanExecute = (((long)num & 1) == 1);
        }
        public byte[] GetBytes()
        {
            SshDataStream sshDataStream = new SshDataStream(4);
            uint num = 0;
            if (IsSizeChanged && IsRegularFile)
                num |= 1;
            if (IsUserIdChanged || IsGroupIdChanged)
                num |= 2;
            if (IsPermissionsChanged)
                num |= 4;
            if (IsLastAccessTimeChanged || IsLastWriteTimeChanged)
                num |= 8;
            if (IsExtensionsChanged)
                num = (uint)((int)num | -2147483648);
            sshDataStream.Write(num);
            if (IsSizeChanged && IsRegularFile)
                sshDataStream.Write((ulong)Size);
            if (IsUserIdChanged || IsGroupIdChanged) {
                sshDataStream.Write((uint)UserId);
                sshDataStream.Write((uint)GroupId);
            }
            if (IsPermissionsChanged)
                sshDataStream.Write(Permissions);
            if (IsLastAccessTimeChanged || IsLastWriteTimeChanged) {
                DateTime dateTime = LastAccessTimeUtc;
                uint value = (uint)(dateTime.ToFileTimeUtc() / 10000000 - 11644473600);
                sshDataStream.Write(value);
                dateTime = LastWriteTimeUtc;
                value = (uint)(dateTime.ToFileTimeUtc() / 10000000 - 11644473600);
                sshDataStream.Write(value);
            }
            if (IsExtensionsChanged) {
                foreach (KeyValuePair<string, string> extension in Extensions) {
                    sshDataStream.Write(extension.Key, SshData.Ascii);
                    sshDataStream.Write(extension.Value, SshData.Ascii);
                }
            }
            return sshDataStream.ToArray();
        }
        internal static SftpFileAttributes FromBytes(SshDataStream stream)
        {
            uint num = stream.ReadUInt32();
            long size = -1;
            int userId = -1;
            int groupId = -1;
            uint permissions = 0;
            Dictionary<string, string> dictionary = null;
            if ((num & 1) == 1)
                size = (long)stream.ReadUInt64();
            if ((num & 2) == 2) {
                userId = (int)stream.ReadUInt32();
                groupId = (int)stream.ReadUInt32();
            }
            if ((num & 4) == 4)
                permissions = stream.ReadUInt32();
            DateTime lastAccessTimeUtc;
            DateTime lastWriteTimeUtc;
            if ((num & 8) == 8) {
                lastAccessTimeUtc = DateTime.FromFileTimeUtc((stream.ReadUInt32() + 11644473600) * 10000000);
                lastWriteTimeUtc = DateTime.FromFileTimeUtc((stream.ReadUInt32() + 11644473600) * 10000000);
            } else {
                lastAccessTimeUtc = DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc);
                lastWriteTimeUtc = DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc);
            }
            if (((int)num & -2147483648) == -2147483648) {
                int num2 = (int)stream.ReadUInt32();
                dictionary = new Dictionary<string, string>(num2);
                for (int i = 0; i < num2; i++) {
                    string key = stream.ReadString(SshData.Utf8);
                    string value = stream.ReadString(SshData.Utf8);
                    dictionary.Add(key, value);
                }
            }
            return new SftpFileAttributes(lastAccessTimeUtc, lastWriteTimeUtc, size, userId, groupId, permissions, dictionary);
        }
        internal static SftpFileAttributes FromBytes(byte[] buffer)
        {
            using (SshDataStream stream = new SshDataStream(buffer))
                return FromBytes(stream);
        }
        private static DateTime ToLocalTime(DateTime value)
        {
            if (!(value == DateTime.MinValue))
                return value.ToLocalTime();
            return DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Local);
        }
        private static DateTime ToUniversalTime(DateTime value)
        {
            if (!(value == DateTime.MinValue))
                return value.ToUniversalTime();
            return DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc);
        }
    }
}