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);
}
}
}