<PackageReference Include="SSH.NET" Version="2025.1.0" />

SftpFileAttributes

public sealed class SftpFileAttributes
Contains SFTP file attributes.
using Renci.SshNet.Common; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; using System.Text; namespace Renci.SshNet.Sftp { [NullableContext(1)] [Nullable(0)] public sealed 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; [Nullable(new byte[] { 2, 1, 1 })] private readonly Dictionary<string, string> _originalExtensions; 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 { [MemberNotNullWhen(true, "Extensions")] 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 => (Permissions & 61440) == 49152; public bool IsSymbolicLink => (Permissions & 61440) == 40960; public bool IsRegularFile => (Permissions & 61440) == 32768; public bool IsBlockDevice => (Permissions & 61440) == 24576; public bool IsDirectory => (Permissions & 61440) == 16384; public bool IsCharacterDevice => (Permissions & 61440) == 8192; public bool IsNamedPipe => (Permissions & 61440) == 4096; public bool IsUIDBitSet { get { return (Permissions & 2048) == 2048; } set { if (value) Permissions |= 2048; else Permissions &= 4294965247; } } public bool IsGroupIDBitSet { get { return (Permissions & 1024) == 1024; } set { if (value) Permissions |= 1024; else Permissions &= 4294966271; } } public bool IsStickyBitSet { get { return (Permissions & 512) == 512; } set { if (value) Permissions |= 512; else Permissions &= 4294966783; } } public bool OwnerCanRead { get { return (Permissions & 256) == 256; } set { if (value) Permissions |= 256; else Permissions &= 4294967039; } } public bool OwnerCanWrite { get { return (Permissions & 128) == 128; } set { if (value) Permissions |= 128; else Permissions &= 4294967167; } } public bool OwnerCanExecute { get { return (Permissions & 64) == 64; } set { if (value) Permissions |= 64; else Permissions &= 4294967231; } } public bool GroupCanRead { get { return (Permissions & 32) == 32; } set { if (value) Permissions |= 32; else Permissions &= 4294967263; } } public bool GroupCanWrite { get { return (Permissions & 16) == 16; } set { if (value) Permissions |= 16; else Permissions &= 4294967279; } } public bool GroupCanExecute { get { return (Permissions & 8) == 8; } set { if (value) Permissions |= 8; else Permissions &= 4294967287; } } public bool OthersCanRead { get { return (Permissions & 4) == 4; } set { if (value) Permissions |= 4; else Permissions &= 4294967291; } } public bool OthersCanWrite { get { return (Permissions & 2) == 2; } set { if (value) Permissions |= 2; else Permissions &= 4294967293; } } public bool OthersCanExecute { get { return (Permissions & 1) == 1; } set { if (value) Permissions |= 1; else Permissions &= 4294967294; } } [Nullable(new byte[] { 2, 1, 1 })] [field: Nullable(new byte[] { 2, 1, 1 })] public IDictionary<string, string> Extensions { [return: Nullable(new byte[] { 2, 1, 1 })] get; } internal uint Permissions { get; set; } internal SftpFileAttributes(DateTime lastAccessTimeUtc, DateTime lastWriteTimeUtc, long size, int userId, int groupId, uint permissions, [Nullable(new byte[] { 2, 1, 1 })] Dictionary<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) { int result; uint num = (uint)Math.DivRem(mode, 1000, out result); int result2; uint num2 = (uint)Math.DivRem(result, 100, out result2); int result3; uint num3 = (uint)Math.DivRem(result2, 10, out result3); uint num4 = (uint)result3; if (((int)num & -8) != 0 || ((int)num2 & -8) != 0 || ((int)num3 & -8) != 0 || ((int)num4 & -8) != 0) throw new ArgumentOutOfRangeException("mode"); Permissions = (uint)(((int)Permissions & -4096) | (int)(num << 9) | (int)(num2 << 6) | (int)(num3 << 3) | (int)num4); } [NullableContext(2)] public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); if (Permissions != 0) { AppendPermissionsString(stringBuilder); stringBuilder.Append(' '); } if (Size != -1) stringBuilder.AppendFormat("Size: {0} ", Size); if (LastWriteTime != default(DateTime)) stringBuilder.AppendFormat("LastWriteTime: {0:s} ", LastWriteTime); if (stringBuilder.Length > 0) { if (stringBuilder[stringBuilder.Length - 1] == ' ') stringBuilder.Length--; return stringBuilder.ToString(); } return base.ToString(); } private void AppendPermissionsString(StringBuilder sb) { sb.Append(IsRegularFile ? '-' : (IsDirectory ? 'd' : (IsSymbolicLink ? 'l' : (IsNamedPipe ? 'p' : (IsSocket ? 's' : (IsCharacterDevice ? 'c' : (IsBlockDevice ? 'b' : '-'))))))); sb.Append(OwnerCanRead ? 'r' : '-'); sb.Append(OwnerCanWrite ? 'w' : '-'); if (OwnerCanExecute) sb.Append(IsUIDBitSet ? 's' : 'x'); else sb.Append(IsUIDBitSet ? 'S' : '-'); sb.Append(GroupCanRead ? 'r' : '-'); sb.Append(GroupCanWrite ? 'w' : '-'); if (GroupCanExecute) sb.Append(IsGroupIDBitSet ? 's' : 'x'); else sb.Append(IsGroupIDBitSet ? 'S' : '-'); sb.Append(OthersCanRead ? 'r' : '-'); sb.Append(OthersCanWrite ? 'w' : '-'); if (OthersCanExecute) sb.Append(IsStickyBitSet ? 't' : 'x'); else sb.Append(IsStickyBitSet ? 'T' : '-'); } public byte[] GetBytes() { using (SshDataStream sshDataStream = new SshDataStream(4)) { uint num = 0; if (IsSizeChanged) 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) sshDataStream.Write((ulong)Size); if (IsUserIdChanged || IsGroupIdChanged) { sshDataStream.Write((uint)UserId); sshDataStream.Write((uint)GroupId); } if (IsPermissionsChanged) sshDataStream.Write(Permissions); if (IsLastAccessTimeChanged || IsLastWriteTimeChanged) { DateTimeOffset dateTimeOffset = DateTime.SpecifyKind(LastAccessTimeUtc, DateTimeKind.Utc); uint value = (uint)dateTimeOffset.ToUnixTimeSeconds(); sshDataStream.Write(value); dateTimeOffset = DateTime.SpecifyKind(LastWriteTimeUtc, DateTimeKind.Utc); value = (uint)dateTimeOffset.ToUnixTimeSeconds(); sshDataStream.Write(value); } if (IsExtensionsChanged) { foreach (KeyValuePair<string, string> extension in Extensions) { sshDataStream.Write(extension.Key, Encoding.UTF8); sshDataStream.Write(extension.Value, Encoding.UTF8); } } 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) { DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(stream.ReadUInt32()); lastAccessTimeUtc = dateTimeOffset.UtcDateTime; dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(stream.ReadUInt32()); lastWriteTimeUtc = dateTimeOffset.UtcDateTime; } 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(Encoding.UTF8); string value = stream.ReadString(Encoding.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); } } }