You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2021/11/20 06:36:02 UTC

[mina-sshd] branch master updated (06fe2de -> 3e382d7)

This is an automated email from the ASF dual-hosted git repository.

lgoldstein pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git.


    from 06fe2de  Clean-up: move longname calculation for chained SFTP file systems
     new a708d45  Excluded failing MINA test
     new e10fbc4  More robust NULL handling in GenericMapPopulator
     new 2c65114  [SSHD-1226] Using literal constants for SFTP attributes key names
     new 83a0684  [SSHD-1226] Removed ServerSession argument from SftpFileSystemAccessor invocations since it can be retrieved from the provided SftpSubsystemProxy instance
     new 3e382d7  [SSHD-1226] Added SFTP server-side capability to provide file/folder custom extension attributes

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 CHANGES.md                                         |   4 +
 docs/sftp.md                                       |  57 ++++-
 .../org/apache/sshd/common/util/MapEntryUtils.java |   9 +-
 .../org/apache/sshd/common/util/io/IoUtils.java    |  20 ++
 sshd-mina/pom.xml                                  |   1 +
 .../java/org/apache/sshd/scp/server/ScpShell.java  |  22 +-
 .../sftp/client/fs/SftpAclFileAttributeView.java   |   3 +-
 .../sftp/client/fs/SftpFileSystemProvider.java     | 126 +++++-----
 .../sftp/client/fs/SftpPosixFileAttributeView.java |   7 +-
 .../org/apache/sshd/sftp/common/SftpHelper.java    | 102 +++++----
 .../sftp/server/AbstractSftpSubsystemHelper.java   | 255 ++++++++++-----------
 .../apache/sshd/sftp/server/DirectoryHandle.java   |   8 +-
 .../org/apache/sshd/sftp/server/FileHandle.java    |  16 +-
 .../sshd/sftp/server/SftpFileSystemAccessor.java   | 161 +++++++------
 .../org/apache/sshd/sftp/server/SftpSubsystem.java |  19 +-
 .../java/org/apache/sshd/sftp/client/SftpTest.java |   9 +-
 .../apache/sshd/sftp/client/SftpVersionsTest.java  |  15 +-
 .../sftp/client/extensions/SftpExtensionsTest.java | 147 ++++++++++++
 .../extensions/UnsupportedExtensionTest.java       |  62 -----
 .../client/fs/AbstractSftpFilesSystemSupport.java  |   5 +-
 20 files changed, 611 insertions(+), 437 deletions(-)
 create mode 100644 sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/SftpExtensionsTest.java
 delete mode 100644 sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/UnsupportedExtensionTest.java

[mina-sshd] 02/05: More robust NULL handling in GenericMapPopulator

Posted by lg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit e10fbc42a5be6bd99d5e33447380323874f0f846
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Fri Nov 19 10:13:45 2021 +0200

    More robust NULL handling in GenericMapPopulator
---
 .../src/main/java/org/apache/sshd/common/util/MapEntryUtils.java | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/MapEntryUtils.java b/sshd-common/src/main/java/org/apache/sshd/common/util/MapEntryUtils.java
index 0258332..e2882ad 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/MapEntryUtils.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/MapEntryUtils.java
@@ -72,7 +72,10 @@ public final class MapEntryUtils {
         }
 
         public GenericMapPopulator<K, V, M> put(K k, V v) {
-            map.put(k, v);
+            if (v == null) {
+                return remove(k);
+            }
+            map.put(Objects.requireNonNull(k, "No key provided"), v);
             return this;
         }
 
@@ -82,7 +85,9 @@ public final class MapEntryUtils {
         }
 
         public GenericMapPopulator<K, V, M> putAll(Map<? extends K, ? extends V> other) {
-            map.putAll(other);
+            if (isNotEmpty(other)) {
+                other.forEach(this::put);
+            }
             return this;
         }
 

[mina-sshd] 03/05: [SSHD-1226] Using literal constants for SFTP attributes key names

Posted by lg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit 2c65114610d5e01e62452f9fdb666496c764e938
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Fri Nov 19 05:35:19 2021 +0200

    [SSHD-1226] Using literal constants for SFTP attributes key names
---
 CHANGES.md                                         |   1 +
 .../org/apache/sshd/common/util/io/IoUtils.java    |  20 ++++
 .../java/org/apache/sshd/scp/server/ScpShell.java  |  22 ++--
 .../sftp/client/fs/SftpAclFileAttributeView.java   |   3 +-
 .../sftp/client/fs/SftpFileSystemProvider.java     | 126 ++++++++++++---------
 .../sftp/client/fs/SftpPosixFileAttributeView.java |   7 +-
 .../org/apache/sshd/sftp/common/SftpHelper.java    | 102 +++++++++--------
 .../sftp/server/AbstractSftpSubsystemHelper.java   | 109 +++++++++---------
 .../org/apache/sshd/sftp/server/FileHandle.java    |   4 +-
 .../sshd/sftp/server/SftpFileSystemAccessor.java   |  12 +-
 .../apache/sshd/sftp/client/SftpVersionsTest.java  |  15 ++-
 .../client/fs/AbstractSftpFilesSystemSupport.java  |   5 +-
 12 files changed, 239 insertions(+), 187 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 5efe967..de364fb 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -22,6 +22,7 @@
 
 * [SSHD-1193](https://issues.apache.org/jira/browse/SSHD-1193) Provide a more user-friendly text in case disconnecting due to timeout(s).
 * [SSHD-1196](https://issues.apache.org/jira/browse/SSHD-1196) Provide configurable support for SFTP output stream chunking behavior.
+* [SSHD-1226](https://issues.apache.org/jira/browse/SSHD-1226) Using literal constants for SFTP attributes key names
 
 ## Behavioral changes and enhancements
 
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/io/IoUtils.java b/sshd-common/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
index bba17b2..ccac669 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
@@ -70,6 +70,26 @@ public final class IoUtils {
     public static final List<String> WINDOWS_EXECUTABLE_EXTENSIONS
             = Collections.unmodifiableList(Arrays.asList(".bat", ".exe", ".cmd"));
 
+    /* File view attributes names */
+    public static final String REGFILE_VIEW_ATTR = "isRegularFile";
+    public static final String DIRECTORY_VIEW_ATTR = "isDirectory";
+    public static final String SYMLINK_VIEW_ATTR = "isSymbolicLink";
+    public static final String NUMLINKS_VIEW_ATTR = "nlink";
+    public static final String OTHERFILE_VIEW_ATTR = "isOther";
+    public static final String EXECUTABLE_VIEW_ATTR = "isExecutable";
+    public static final String SIZE_VIEW_ATTR = "size";
+    public static final String OWNER_VIEW_ATTR = "owner";
+    public static final String GROUP_VIEW_ATTR = "group";
+    public static final String USERID_VIEW_ATTR = "uid";
+    public static final String GROUPID_VIEW_ATTR = "gid";
+    public static final String PERMISSIONS_VIEW_ATTR = "permissions";
+    public static final String ACL_VIEW_ATTR = "acl";
+    public static final String FILEKEY_VIEW_ATTR = "fileKey";
+    public static final String CREATE_TIME_VIEW_ATTR = "creationTime";
+    public static final String LASTMOD_TIME_VIEW_ATTR = "lastModifiedTime";
+    public static final String LASTACC_TIME_VIEW_ATTR = "lastAccessTime";
+    public static final String EXTENDED_VIEW_ATTR = "extended";
+
     /**
      * Size of preferred work buffer when reading / writing data to / from streams
      */
diff --git a/sshd-scp/src/main/java/org/apache/sshd/scp/server/ScpShell.java b/sshd-scp/src/main/java/org/apache/sshd/scp/server/ScpShell.java
index 232a4b0..0ed3119 100644
--- a/sshd-scp/src/main/java/org/apache/sshd/scp/server/ScpShell.java
+++ b/sshd-scp/src/main/java/org/apache/sshd/scp/server/ScpShell.java
@@ -727,36 +727,36 @@ public class ScpShell extends AbstractFileSystemCommand implements ServerChannel
             }
 
             StringBuilder sb = new StringBuilder(abbrev.length() + 64);
-            if (is("isDirectory")) {
+            if (is(IoUtils.DIRECTORY_VIEW_ATTR)) {
                 sb.append('d');
-            } else if (is("isSymbolicLink")) {
+            } else if (is(IoUtils.SYMLINK_VIEW_ATTR)) {
                 sb.append('l');
-            } else if (is("isOther")) {
+            } else if (is(IoUtils.OTHERFILE_VIEW_ATTR)) {
                 sb.append('o');
             } else {
                 sb.append('-');
             }
 
             @SuppressWarnings("unchecked")
-            Set<PosixFilePermission> perms = (Set<PosixFilePermission>) attributes.get("permissions");
+            Set<PosixFilePermission> perms = (Set<PosixFilePermission>) attributes.get(IoUtils.PERMISSIONS_VIEW_ATTR);
             if (perms == null) {
                 perms = EnumSet.noneOf(PosixFilePermission.class);
             }
             sb.append(PosixFilePermissions.toString(perms));
 
-            Object nlinkValue = attributes.get("nlink");
+            Object nlinkValue = attributes.get(IoUtils.NUMLINKS_VIEW_ATTR);
             sb.append(' ').append(String.format("%3s", (nlinkValue != null) ? nlinkValue : "1"));
 
-            appendOwnerInformation(sb, "owner", "owner");
-            appendOwnerInformation(sb, "group", "group");
+            appendOwnerInformation(sb, IoUtils.OWNER_VIEW_ATTR, "owner");
+            appendOwnerInformation(sb, IoUtils.GROUP_VIEW_ATTR, "group");
 
-            Number length = (Number) attributes.get("size");
+            Number length = (Number) attributes.get(IoUtils.SIZE_VIEW_ATTR);
             if (length == null) {
                 length = 0L;
             }
             sb.append(' ').append(String.format("%1$8s", length));
 
-            String timeValue = toString((FileTime) attributes.get("lastModifiedTime"), optFullTime);
+            String timeValue = toString((FileTime) attributes.get(IoUtils.LASTMOD_TIME_VIEW_ATTR), optFullTime);
             sb.append(' ').append(timeValue);
 
             sb.append(' ').append(abbrev);
@@ -830,8 +830,8 @@ public class ScpShell extends AbstractFileSystemCommand implements ServerChannel
                 }
             }
             if (!attrs.isEmpty()) {
-                attrs.computeIfAbsent("isExecutable", s -> Files.isExecutable(path));
-                attrs.computeIfAbsent("permissions", s -> IoUtils.getPermissionsFromFile(path.toFile()));
+                attrs.computeIfAbsent(IoUtils.EXECUTABLE_VIEW_ATTR, s -> Files.isExecutable(path));
+                attrs.computeIfAbsent(IoUtils.PERMISSIONS_VIEW_ATTR, s -> IoUtils.getPermissionsFromFile(path.toFile()));
             }
             return attrs;
         }
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpAclFileAttributeView.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpAclFileAttributeView.java
index 9afde45..c8333b0 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpAclFileAttributeView.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpAclFileAttributeView.java
@@ -28,6 +28,7 @@ import java.nio.file.attribute.PosixFileAttributes;
 import java.nio.file.attribute.UserPrincipal;
 import java.util.List;
 
+import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.sftp.client.SftpClient;
 import org.apache.sshd.sftp.client.impl.AbstractSftpFileAttributeView;
 
@@ -47,7 +48,7 @@ public class SftpAclFileAttributeView extends AbstractSftpFileAttributeView impl
 
     @Override
     public void setOwner(UserPrincipal owner) throws IOException {
-        provider.setAttribute(path, "posix", "owner", owner, options);
+        provider.setAttribute(path, "posix", IoUtils.OWNER_VIEW_ATTR, owner, options);
     }
 
     @Override
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpFileSystemProvider.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpFileSystemProvider.java
index 9d78e8f..0cda4e8 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpFileSystemProvider.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpFileSystemProvider.java
@@ -937,18 +937,20 @@ public class SftpFileSystemProvider extends FileSystemProvider {
         boolean traceEnabled = log.isTraceEnabled();
         for (String attr : attrValues) {
             switch (attr) {
-                case "acl":
+                case IoUtils.ACL_VIEW_ATTR: {
                     List<AclEntry> acl = attributes.getAcl();
                     if (acl != null) {
                         map.put(attr, acl);
                     }
                     break;
-                case "owner":
+                }
+                case IoUtils.OWNER_VIEW_ATTR: {
                     String owner = attributes.getOwner();
                     if (GenericUtils.length(owner) > 0) {
                         map.put(attr, new SftpFileSystem.DefaultUserPrincipal(owner));
                     }
                     break;
+                }
                 default:
                     if (traceEnabled) {
                         log.trace("readAclViewAttributes({})[{}] unknown attribute: {}", fs, attrs, attr);
@@ -964,35 +966,37 @@ public class SftpFileSystemProvider extends FileSystemProvider {
         // SftpPathImpl.withAttributeCache() invocation. So we ensure here that if we are already within a caching
         // scope, we do use the cached attributes, but if we are not, we clear any possibly cached attributes and
         // do actually read them from the remote.
-        return SftpPathImpl.withAttributeCache(path, p -> {
-            SftpClient.Attributes attributes = path.getAttributes();
-            if (attributes != null) {
-                return attributes;
+        return SftpPathImpl.withAttributeCache(path, p -> resolveRemoteFileAttributes(path, options));
+    }
+
+    protected SftpClient.Attributes resolveRemoteFileAttributes(SftpPath path, LinkOption... options) throws IOException {
+        SftpClient.Attributes attributes = path.getAttributes();
+        if (attributes != null) {
+            return attributes;
+        }
+        SftpFileSystem fs = path.getFileSystem();
+        try (SftpClient client = fs.getClient()) {
+            SftpClient.Attributes attrs;
+            if (IoUtils.followLinks(options)) {
+                attrs = client.stat(path.toString());
+            } else {
+                attrs = client.lstat(path.toString());
             }
-            SftpFileSystem fs = path.getFileSystem();
-            try (SftpClient client = fs.getClient()) {
-                SftpClient.Attributes attrs;
-                if (IoUtils.followLinks(options)) {
-                    attrs = client.stat(path.toString());
-                } else {
-                    attrs = client.lstat(path.toString());
-                }
-                if (log.isTraceEnabled()) {
-                    log.trace("readRemoteAttributes({})[{}]: {}", fs, path, attrs);
-                }
-                if (path instanceof SftpPathImpl) {
-                    ((SftpPathImpl) path).cacheAttributes(attrs);
-                }
-                return attrs;
-            } catch (SftpException e) {
-                if (e.getStatus() == SftpConstants.SSH_FX_NO_SUCH_FILE) {
-                    NoSuchFileException toThrow = new NoSuchFileException(path.toString());
-                    toThrow.initCause(e);
-                    throw toThrow;
-                }
-                throw e;
+            if (log.isTraceEnabled()) {
+                log.trace("resolveRemoteFileAttributes({})[{}]: {}", fs, path, attrs);
+            }
+            if (path instanceof SftpPathImpl) {
+                ((SftpPathImpl) path).cacheAttributes(attrs);
             }
-        });
+            return attrs;
+        } catch (SftpException e) {
+            if (e.getStatus() == SftpConstants.SSH_FX_NO_SUCH_FILE) {
+                NoSuchFileException toThrow = new NoSuchFileException(path.toString());
+                toThrow.initCause(e);
+                throw toThrow;
+            }
+            throw e;
+        }
     }
 
     protected NavigableMap<String, Object> readPosixViewAttributes(
@@ -1000,7 +1004,19 @@ public class SftpFileSystemProvider extends FileSystemProvider {
             throws IOException {
         PosixFileAttributes v = readAttributes(path, PosixFileAttributes.class, options);
         if ("*".equals(attrs)) {
-            attrs = "lastModifiedTime,lastAccessTime,creationTime,size,isRegularFile,isDirectory,isSymbolicLink,isOther,fileKey,owner,permissions,group";
+            attrs = IoUtils.LASTMOD_TIME_VIEW_ATTR
+                    + "," + IoUtils.LASTACC_TIME_VIEW_ATTR
+                    + "," + IoUtils.CREATE_TIME_VIEW_ATTR
+                    + "," + IoUtils.SIZE_VIEW_ATTR
+                    + "," + IoUtils.REGFILE_VIEW_ATTR
+                    + "," + IoUtils.DIRECTORY_VIEW_ATTR
+                    + "," + IoUtils.SYMLINK_VIEW_ATTR
+                    + "," + IoUtils.OTHERFILE_VIEW_ATTR
+                    + "," + IoUtils.FILEKEY_VIEW_ATTR
+                    + "," + IoUtils.OWNER_VIEW_ATTR
+                    + "," + IoUtils.GROUP_VIEW_ATTR
+                    + "," + IoUtils.PERMISSIONS_VIEW_ATTR
+                    + "," + IoUtils.FILEKEY_VIEW_ATTR;
         }
 
         NavigableMap<String, Object> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
@@ -1008,40 +1024,40 @@ public class SftpFileSystemProvider extends FileSystemProvider {
         String[] attrValues = GenericUtils.split(attrs, ',');
         for (String attr : attrValues) {
             switch (attr) {
-                case "lastModifiedTime":
+                case IoUtils.LASTMOD_TIME_VIEW_ATTR:
                     map.put(attr, v.lastModifiedTime());
                     break;
-                case "lastAccessTime":
+                case IoUtils.LASTACC_TIME_VIEW_ATTR:
                     map.put(attr, v.lastAccessTime());
                     break;
-                case "creationTime":
+                case IoUtils.CREATE_TIME_VIEW_ATTR:
                     map.put(attr, v.creationTime());
                     break;
-                case "size":
+                case IoUtils.SIZE_VIEW_ATTR:
                     map.put(attr, v.size());
                     break;
-                case "isRegularFile":
+                case IoUtils.REGFILE_VIEW_ATTR:
                     map.put(attr, v.isRegularFile());
                     break;
-                case "isDirectory":
+                case IoUtils.DIRECTORY_VIEW_ATTR:
                     map.put(attr, v.isDirectory());
                     break;
-                case "isSymbolicLink":
+                case IoUtils.SYMLINK_VIEW_ATTR:
                     map.put(attr, v.isSymbolicLink());
                     break;
-                case "isOther":
+                case IoUtils.OTHERFILE_VIEW_ATTR:
                     map.put(attr, v.isOther());
                     break;
-                case "fileKey":
+                case IoUtils.FILEKEY_VIEW_ATTR:
                     map.put(attr, v.fileKey());
                     break;
-                case "owner":
+                case IoUtils.OWNER_VIEW_ATTR:
                     map.put(attr, v.owner());
                     break;
-                case "permissions":
+                case IoUtils.PERMISSIONS_VIEW_ATTR:
                     map.put(attr, v.permissions());
                     break;
-                case "group":
+                case IoUtils.GROUP_VIEW_ATTR:
                     map.put(attr, v.group());
                     break;
                 default:
@@ -1081,42 +1097,42 @@ public class SftpFileSystemProvider extends FileSystemProvider {
 
         SftpClient.Attributes attributes = new SftpClient.Attributes();
         switch (attr) {
-            case "lastModifiedTime":
+            case IoUtils.LASTMOD_TIME_VIEW_ATTR:
                 attributes.modifyTime((int) ((FileTime) value).to(TimeUnit.SECONDS));
                 break;
-            case "lastAccessTime":
+            case IoUtils.LASTACC_TIME_VIEW_ATTR:
                 attributes.accessTime((int) ((FileTime) value).to(TimeUnit.SECONDS));
                 break;
-            case "creationTime":
+            case IoUtils.CREATE_TIME_VIEW_ATTR:
                 attributes.createTime((int) ((FileTime) value).to(TimeUnit.SECONDS));
                 break;
-            case "size":
+            case IoUtils.SIZE_VIEW_ATTR:
                 attributes.size(((Number) value).longValue());
                 break;
-            case "permissions": {
+            case IoUtils.PERMISSIONS_VIEW_ATTR: {
                 @SuppressWarnings("unchecked")
                 Set<PosixFilePermission> attrSet = (Set<PosixFilePermission>) value;
                 attributes.perms(attributesToPermissions(path, attrSet));
                 break;
             }
-            case "owner":
+            case IoUtils.OWNER_VIEW_ATTR:
                 attributes.owner(((UserPrincipal) value).getName());
                 break;
-            case "group":
+            case IoUtils.GROUP_VIEW_ATTR:
                 attributes.group(((GroupPrincipal) value).getName());
                 break;
-            case "acl": {
+            case IoUtils.ACL_VIEW_ATTR: {
                 ValidateUtils.checkTrue("acl".equalsIgnoreCase(view), "ACL cannot be set via view=%s", view);
                 @SuppressWarnings("unchecked")
                 List<AclEntry> acl = (List<AclEntry>) value;
                 attributes.acl(acl);
                 break;
             }
-            case "isRegularFile":
-            case "isDirectory":
-            case "isSymbolicLink":
-            case "isOther":
-            case "fileKey":
+            case IoUtils.REGFILE_VIEW_ATTR:
+            case IoUtils.DIRECTORY_VIEW_ATTR:
+            case IoUtils.SYMLINK_VIEW_ATTR:
+            case IoUtils.OTHERFILE_VIEW_ATTR:
+            case IoUtils.FILEKEY_VIEW_ATTR:
                 throw new UnsupportedOperationException(
                         "setAttribute(" + path + ")[" + view + ":" + attr + "=" + value + "] modification N/A");
             default:
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpPosixFileAttributeView.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpPosixFileAttributeView.java
index 147a5c9..2e5a0ac 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpPosixFileAttributeView.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpPosixFileAttributeView.java
@@ -30,6 +30,7 @@ import java.nio.file.attribute.UserPrincipal;
 import java.util.Set;
 
 import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.sftp.client.SftpClient;
 import org.apache.sshd.sftp.client.impl.AbstractSftpFileAttributeView;
 
@@ -75,12 +76,12 @@ public class SftpPosixFileAttributeView extends AbstractSftpFileAttributeView im
 
     @Override
     public void setPermissions(Set<PosixFilePermission> perms) throws IOException {
-        provider.setAttribute(path, "permissions", perms, options);
+        provider.setAttribute(path, IoUtils.PERMISSIONS_VIEW_ATTR, perms, options);
     }
 
     @Override
     public void setGroup(GroupPrincipal group) throws IOException {
-        provider.setAttribute(path, "group", group, options);
+        provider.setAttribute(path, IoUtils.GROUP_VIEW_ATTR, group, options);
     }
 
     @Override
@@ -90,6 +91,6 @@ public class SftpPosixFileAttributeView extends AbstractSftpFileAttributeView im
 
     @Override
     public void setOwner(UserPrincipal owner) throws IOException {
-        provider.setAttribute(path, "owner", owner, options);
+        provider.setAttribute(path, IoUtils.OWNER_VIEW_ATTR, owner, options);
     }
 }
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/common/SftpHelper.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/common/SftpHelper.java
index 4386df4..beb1c32 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/common/SftpHelper.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/common/SftpHelper.java
@@ -62,6 +62,7 @@ import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.BufferUtils;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.sftp.SftpModuleProperties;
 import org.apache.sshd.sftp.client.SftpClient.Attribute;
 import org.apache.sshd.sftp.client.SftpClient.Attributes;
@@ -220,17 +221,17 @@ public final class SftpHelper {
     public static <B extends Buffer> B writeAttrsV3(B buffer, int version, Map<String, ?> attributes) {
         ValidateUtils.checkTrue(version == SftpConstants.SFTP_V3, "Illegal version: %d", version);
 
-        boolean isReg = getBool((Boolean) attributes.get("isRegularFile"));
-        boolean isDir = getBool((Boolean) attributes.get("isDirectory"));
-        boolean isLnk = getBool((Boolean) attributes.get("isSymbolicLink"));
+        boolean isReg = getBool((Boolean) attributes.get(IoUtils.REGFILE_VIEW_ATTR));
+        boolean isDir = getBool((Boolean) attributes.get(IoUtils.DIRECTORY_VIEW_ATTR));
+        boolean isLnk = getBool((Boolean) attributes.get(IoUtils.SYMLINK_VIEW_ATTR));
         @SuppressWarnings("unchecked")
-        Collection<PosixFilePermission> perms = (Collection<PosixFilePermission>) attributes.get("permissions");
-        Number size = (Number) attributes.get("size");
-        FileTime lastModifiedTime = (FileTime) attributes.get("lastModifiedTime");
-        FileTime lastAccessTime = (FileTime) attributes.get("lastAccessTime");
-        Map<?, ?> extensions = (Map<?, ?>) attributes.get("extended");
+        Collection<PosixFilePermission> perms = (Collection<PosixFilePermission>) attributes.get(IoUtils.PERMISSIONS_VIEW_ATTR);
+        Number size = (Number) attributes.get(IoUtils.SIZE_VIEW_ATTR);
+        FileTime lastModifiedTime = (FileTime) attributes.get(IoUtils.LASTMOD_TIME_VIEW_ATTR);
+        FileTime lastAccessTime = (FileTime) attributes.get(IoUtils.LASTACC_TIME_VIEW_ATTR);
+        Map<?, ?> extensions = (Map<?, ?>) attributes.get(IoUtils.EXTENDED_VIEW_ATTR);
         int flags = ((isReg || isLnk) && (size != null) ? SftpConstants.SSH_FILEXFER_ATTR_SIZE : 0)
-                    | (attributes.containsKey("uid") && attributes.containsKey("gid")
+                    | (attributes.containsKey(IoUtils.USERID_VIEW_ATTR) && attributes.containsKey(IoUtils.GROUPID_VIEW_ATTR)
                             ? SftpConstants.SSH_FILEXFER_ATTR_UIDGID : 0)
                     | ((perms != null) ? SftpConstants.SSH_FILEXFER_ATTR_PERMISSIONS : 0)
                     | (((lastModifiedTime != null) && (lastAccessTime != null)) ? SftpConstants.SSH_FILEXFER_ATTR_ACMODTIME : 0)
@@ -240,8 +241,8 @@ public final class SftpHelper {
             buffer.putLong(size.longValue());
         }
         if ((flags & SftpConstants.SSH_FILEXFER_ATTR_UIDGID) != 0) {
-            buffer.putInt(((Number) attributes.get("uid")).intValue());
-            buffer.putInt(((Number) attributes.get("gid")).intValue());
+            buffer.putInt(((Number) attributes.get(IoUtils.USERID_VIEW_ATTR)).intValue());
+            buffer.putInt(((Number) attributes.get(IoUtils.GROUPID_VIEW_ATTR)).intValue());
         }
         if ((flags & SftpConstants.SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {
             buffer.putInt(attributesToPermissions(isReg, isDir, isLnk, perms));
@@ -269,20 +270,20 @@ public final class SftpHelper {
     public static <B extends Buffer> B writeAttrsV4(B buffer, int version, Map<String, ?> attributes) {
         ValidateUtils.checkTrue(version >= SftpConstants.SFTP_V4, "Illegal version: %d", version);
 
-        boolean isReg = getBool((Boolean) attributes.get("isRegularFile"));
-        boolean isDir = getBool((Boolean) attributes.get("isDirectory"));
-        boolean isLnk = getBool((Boolean) attributes.get("isSymbolicLink"));
+        boolean isReg = getBool((Boolean) attributes.get(IoUtils.REGFILE_VIEW_ATTR));
+        boolean isDir = getBool((Boolean) attributes.get(IoUtils.DIRECTORY_VIEW_ATTR));
+        boolean isLnk = getBool((Boolean) attributes.get(IoUtils.SYMLINK_VIEW_ATTR));
         @SuppressWarnings("unchecked")
-        Collection<PosixFilePermission> perms = (Collection<PosixFilePermission>) attributes.get("permissions");
-        Number size = (Number) attributes.get("size");
-        FileTime lastModifiedTime = (FileTime) attributes.get("lastModifiedTime");
-        FileTime lastAccessTime = (FileTime) attributes.get("lastAccessTime");
-        FileTime creationTime = (FileTime) attributes.get("creationTime");
+        Collection<PosixFilePermission> perms = (Collection<PosixFilePermission>) attributes.get(IoUtils.PERMISSIONS_VIEW_ATTR);
+        Number size = (Number) attributes.get(IoUtils.SIZE_VIEW_ATTR);
+        FileTime lastModifiedTime = (FileTime) attributes.get(IoUtils.LASTMOD_TIME_VIEW_ATTR);
+        FileTime lastAccessTime = (FileTime) attributes.get(IoUtils.LASTACC_TIME_VIEW_ATTR);
+        FileTime creationTime = (FileTime) attributes.get(IoUtils.CREATE_TIME_VIEW_ATTR);
         @SuppressWarnings("unchecked")
-        Collection<AclEntry> acl = (Collection<AclEntry>) attributes.get("acl");
-        Map<?, ?> extensions = (Map<?, ?>) attributes.get("extended");
+        Collection<AclEntry> acl = (Collection<AclEntry>) attributes.get(IoUtils.ACL_VIEW_ATTR);
+        Map<?, ?> extensions = (Map<?, ?>) attributes.get(IoUtils.EXTENDED_VIEW_ATTR);
         int flags = (((isReg || isLnk) && (size != null)) ? SftpConstants.SSH_FILEXFER_ATTR_SIZE : 0)
-                    | ((attributes.containsKey("owner") && attributes.containsKey("group"))
+                    | ((attributes.containsKey(IoUtils.OWNER_VIEW_ATTR) && attributes.containsKey(IoUtils.GROUP_VIEW_ATTR))
                             ? SftpConstants.SSH_FILEXFER_ATTR_OWNERGROUP : 0)
                     | ((perms != null) ? SftpConstants.SSH_FILEXFER_ATTR_PERMISSIONS : 0)
                     | ((lastModifiedTime != null) ? SftpConstants.SSH_FILEXFER_ATTR_MODIFYTIME : 0)
@@ -299,8 +300,10 @@ public final class SftpHelper {
             buffer.putLong(size.longValue());
         }
         if ((flags & SftpConstants.SSH_FILEXFER_ATTR_OWNERGROUP) != 0) {
-            buffer.putString(Objects.toString(attributes.get("owner"), SftpUniversalOwnerAndGroup.Owner.getName()));
-            buffer.putString(Objects.toString(attributes.get("group"), SftpUniversalOwnerAndGroup.Group.getName()));
+            buffer.putString(
+                    Objects.toString(attributes.get(IoUtils.OWNER_VIEW_ATTR), SftpUniversalOwnerAndGroup.Owner.getName()));
+            buffer.putString(
+                    Objects.toString(attributes.get(IoUtils.GROUP_VIEW_ATTR), SftpUniversalOwnerAndGroup.Group.getName()));
         }
         if ((flags & SftpConstants.SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {
             buffer.putInt(attributesToPermissions(isReg, isDir, isLnk, perms));
@@ -664,32 +667,32 @@ public final class SftpHelper {
             int type = buffer.getUByte();
             switch (type) {
                 case SftpConstants.SSH_FILEXFER_TYPE_REGULAR:
-                    attrs.put("isRegular", Boolean.TRUE);
+                    attrs.put(IoUtils.REGFILE_VIEW_ATTR, Boolean.TRUE);
                     break;
                 case SftpConstants.SSH_FILEXFER_TYPE_DIRECTORY:
-                    attrs.put("isDirectory", Boolean.TRUE);
+                    attrs.put(IoUtils.DIRECTORY_VIEW_ATTR, Boolean.TRUE);
                     break;
                 case SftpConstants.SSH_FILEXFER_TYPE_SYMLINK:
-                    attrs.put("isSymbolicLink", Boolean.TRUE);
+                    attrs.put(IoUtils.SYMLINK_VIEW_ATTR, Boolean.TRUE);
                     break;
                 case SftpConstants.SSH_FILEXFER_TYPE_SOCKET:
                 case SftpConstants.SSH_FILEXFER_TYPE_CHAR_DEVICE:
                 case SftpConstants.SSH_FILEXFER_TYPE_BLOCK_DEVICE:
                 case SftpConstants.SSH_FILEXFER_TYPE_FIFO:
-                    attrs.put("isOther", Boolean.TRUE);
+                    attrs.put(IoUtils.OTHERFILE_VIEW_ATTR, Boolean.TRUE);
                     break;
                 default: // ignored
             }
         }
 
         if ((flags & SftpConstants.SSH_FILEXFER_ATTR_SIZE) != 0) {
-            attrs.put("size", buffer.getLong());
+            attrs.put(IoUtils.SIZE_VIEW_ATTR, buffer.getLong());
         }
 
         if (version == SftpConstants.SFTP_V3) {
             if ((flags & SftpConstants.SSH_FILEXFER_ATTR_UIDGID) != 0) {
-                attrs.put("uid", buffer.getInt());
-                attrs.put("gid", buffer.getInt());
+                attrs.put(IoUtils.USERID_VIEW_ATTR, buffer.getInt());
+                attrs.put(IoUtils.GROUPID_VIEW_ATTR, buffer.getInt());
             }
         } else {
             if ((version >= SftpConstants.SFTP_V6) && ((flags & SftpConstants.SSH_FILEXFER_ATTR_ALLOCATION_SIZE) != 0)) {
@@ -698,36 +701,37 @@ public final class SftpHelper {
             }
 
             if ((flags & SftpConstants.SSH_FILEXFER_ATTR_OWNERGROUP) != 0) {
-                attrs.put("owner", new DefaultGroupPrincipal(buffer.getString()));
-                attrs.put("group", new DefaultGroupPrincipal(buffer.getString()));
+                attrs.put(IoUtils.OWNER_VIEW_ATTR, new DefaultGroupPrincipal(buffer.getString()));
+                attrs.put(IoUtils.GROUP_VIEW_ATTR, new DefaultGroupPrincipal(buffer.getString()));
             }
         }
 
         if ((flags & SftpConstants.SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {
-            attrs.put("permissions", permissionsToAttributes(buffer.getInt()));
+            attrs.put(IoUtils.PERMISSIONS_VIEW_ATTR, permissionsToAttributes(buffer.getInt()));
         }
 
         if (version == SftpConstants.SFTP_V3) {
             if ((flags & SftpConstants.SSH_FILEXFER_ATTR_ACMODTIME) != 0) {
-                attrs.put("lastAccessTime", readTime(buffer, version, flags));
-                attrs.put("lastModifiedTime", readTime(buffer, version, flags));
+                attrs.put(IoUtils.LASTACC_TIME_VIEW_ATTR, readTime(buffer, version, flags));
+                attrs.put(IoUtils.LASTMOD_TIME_VIEW_ATTR, readTime(buffer, version, flags));
             }
         } else if (version >= SftpConstants.SFTP_V4) {
             if ((flags & SftpConstants.SSH_FILEXFER_ATTR_ACCESSTIME) != 0) {
-                attrs.put("lastAccessTime", readTime(buffer, version, flags));
+                attrs.put(IoUtils.LASTACC_TIME_VIEW_ATTR, readTime(buffer, version, flags));
             }
             if ((flags & SftpConstants.SSH_FILEXFER_ATTR_CREATETIME) != 0) {
-                attrs.put("creationTime", readTime(buffer, version, flags));
+                attrs.put(IoUtils.CREATE_TIME_VIEW_ATTR, readTime(buffer, version, flags));
             }
             if ((flags & SftpConstants.SSH_FILEXFER_ATTR_MODIFYTIME) != 0) {
-                attrs.put("lastModifiedTime", readTime(buffer, version, flags));
+                attrs.put(IoUtils.LASTMOD_TIME_VIEW_ATTR, readTime(buffer, version, flags));
             }
+            // modification time sub-seconds
             if ((version >= SftpConstants.SFTP_V6) && (flags & SftpConstants.SSH_FILEXFER_ATTR_CTIME) != 0) {
                 attrs.put("ctime", readTime(buffer, version, flags));
             }
 
             if ((flags & SftpConstants.SSH_FILEXFER_ATTR_ACL) != 0) {
-                attrs.put("acl", readACLs(buffer, version));
+                attrs.put(IoUtils.ACL_VIEW_ATTR, readACLs(buffer, version));
             }
 
             if ((flags & SftpConstants.SSH_FILEXFER_ATTR_BITS) != 0) {
@@ -762,7 +766,7 @@ public final class SftpHelper {
         }
 
         if ((flags & SftpConstants.SSH_FILEXFER_ATTR_EXTENDED) != 0) {
-            attrs.put("extended", readExtensions(buffer));
+            attrs.put(IoUtils.EXTENDED_VIEW_ATTR, readExtensions(buffer));
         }
 
         return attrs;
@@ -1202,38 +1206,38 @@ public final class SftpHelper {
      *                    7</A>
      */
     public static String getLongName(String shortName, Map<String, ?> attributes) {
-        String owner = Objects.toString(attributes.get("owner"), null);
+        String owner = Objects.toString(attributes.get(IoUtils.OWNER_VIEW_ATTR), null);
         String username = OsUtils.getCanonicalUser(owner);
         if (GenericUtils.isEmpty(username)) {
             username = SftpUniversalOwnerAndGroup.Owner.getName();
         }
 
-        String group = Objects.toString(attributes.get("group"), null);
+        String group = Objects.toString(attributes.get(IoUtils.GROUP_VIEW_ATTR), null);
         group = OsUtils.resolveCanonicalGroup(group, owner);
         if (GenericUtils.isEmpty(group)) {
             group = SftpUniversalOwnerAndGroup.Group.getName();
         }
 
-        Number length = (Number) attributes.get("size");
+        Number length = (Number) attributes.get(IoUtils.SIZE_VIEW_ATTR);
         if (length == null) {
             length = 0L;
         }
 
         String lengthString = String.format("%1$8s", length);
-        String linkCount = Objects.toString(attributes.get("nlink"), null);
+        String linkCount = Objects.toString(attributes.get(IoUtils.NUMLINKS_VIEW_ATTR), null);
         if (GenericUtils.isEmpty(linkCount)) {
             linkCount = "1";
         }
 
-        Boolean isDirectory = (Boolean) attributes.get("isDirectory");
-        Boolean isLink = (Boolean) attributes.get("isSymbolicLink");
+        Boolean isDirectory = (Boolean) attributes.get(IoUtils.DIRECTORY_VIEW_ATTR);
+        Boolean isLink = (Boolean) attributes.get(IoUtils.SYMLINK_VIEW_ATTR);
         @SuppressWarnings("unchecked")
-        Set<PosixFilePermission> perms = (Set<PosixFilePermission>) attributes.get("permissions");
+        Set<PosixFilePermission> perms = (Set<PosixFilePermission>) attributes.get(IoUtils.PERMISSIONS_VIEW_ATTR);
         if (perms == null) {
             perms = EnumSet.noneOf(PosixFilePermission.class);
         }
         String permsString = PosixFilePermissions.toString(perms);
-        String timeStamp = UnixDateFormat.getUnixDate((FileTime) attributes.get("lastModifiedTime"));
+        String timeStamp = UnixDateFormat.getUnixDate((FileTime) attributes.get(IoUtils.LASTMOD_TIME_VIEW_ATTR));
         StringBuilder sb = new StringBuilder(
                 GenericUtils.length(linkCount) + GenericUtils.length(username) + GenericUtils.length(group)
                                              + GenericUtils.length(timeStamp) + GenericUtils.length(lengthString)
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/AbstractSftpSubsystemHelper.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/AbstractSftpSubsystemHelper.java
index dc1123a..f219524 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/AbstractSftpSubsystemHelper.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/AbstractSftpSubsystemHelper.java
@@ -2324,13 +2324,14 @@ public abstract class AbstractSftpSubsystemHelper
     protected String getLongName(Path f, String shortName, SftpClient.Attributes attributes) throws IOException {
         return getLongName(f, shortName,
                 MapBuilder.<String, Object> builder()
-                        .put("owner", attributes.getOwner())
-                        .put("group", attributes.getGroup())
-                        .put("size", attributes.getSize())
-                        .put("isDirectory", attributes.isDirectory())
-                        .put("isSymbolicLink", attributes.isSymbolicLink())
-                        .put("permissions", SftpHelper.permissionsToAttributes(attributes.getPermissions()))
-                        .put("lastModifiedTime", attributes.getModifyTime()).build());
+                        .put(IoUtils.OWNER_VIEW_ATTR, attributes.getOwner())
+                        .put(IoUtils.GROUP_VIEW_ATTR, attributes.getGroup())
+                        .put(IoUtils.SIZE_VIEW_ATTR, attributes.getSize())
+                        .put(IoUtils.DIRECTORY_VIEW_ATTR, attributes.isDirectory())
+                        .put(IoUtils.SYMLINK_VIEW_ATTR, attributes.isSymbolicLink())
+                        .put(IoUtils.PERMISSIONS_VIEW_ATTR, SftpHelper.permissionsToAttributes(attributes.getPermissions()))
+                        .put(IoUtils.LASTMOD_TIME_VIEW_ATTR, attributes.getModifyTime())
+                        .build());
     }
 
     protected String getShortName(Path f) throws IOException {
@@ -2421,37 +2422,40 @@ public abstract class AbstractSftpSubsystemHelper
      * @param  options     The {@link LinkOption}s to use in order to access the file if necessary
      * @return             A {@link Map} of the retrieved attributes
      * @throws IOException If failed to access the file
-     * @see                #resolveMissingFileAttributes(Path, int, Map, LinkOption...)
+     * @see                #resolveReportedFileAttributes(Path, int, LinkOption...)
      */
     protected NavigableMap<String, Object> getAttributes(Path path, int flags, LinkOption... options)
             throws IOException {
-        return SftpPathImpl.withAttributeCache(path, file -> {
-            FileSystem fs = file.getFileSystem();
-            Collection<String> supportedViews = fs.supportedFileAttributeViews();
-            NavigableMap<String, Object> attrs = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-            Collection<String> views;
-
-            if (GenericUtils.isEmpty(supportedViews)) {
-                views = Collections.emptyList();
-            } else if (supportedViews.contains("unix")) {
-                views = SftpFileSystemAccessor.DEFAULT_UNIX_VIEW;
-            } else {
-                views = GenericUtils.map(supportedViews, v -> v + ":*");
-            }
+        return SftpPathImpl.withAttributeCache(path, file -> resolveReportedFileAttributes(file, flags, options));
+    }
 
-            for (String v : views) {
-                Map<String, ?> ta = readFileAttributes(file, v, options);
-                if (MapEntryUtils.isNotEmpty(ta)) {
-                    attrs.putAll(ta);
-                }
-            }
+    protected NavigableMap<String, Object> resolveReportedFileAttributes(Path file, int flags, LinkOption... options)
+            throws IOException {
+        FileSystem fs = file.getFileSystem();
+        Collection<String> supportedViews = fs.supportedFileAttributeViews();
+        NavigableMap<String, Object> attrs = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        Collection<String> views;
+
+        if (GenericUtils.isEmpty(supportedViews)) {
+            views = Collections.emptyList();
+        } else if (supportedViews.contains("unix")) {
+            views = SftpFileSystemAccessor.DEFAULT_UNIX_VIEW;
+        } else {
+            views = GenericUtils.map(supportedViews, v -> v + ":*");
+        }
 
-            Map<String, ?> completions = resolveMissingFileAttributes(file, flags, attrs, options);
-            if (MapEntryUtils.isNotEmpty(completions)) {
-                attrs.putAll(completions);
+        for (String v : views) {
+            Map<String, ?> ta = readFileAttributes(file, v, options);
+            if (MapEntryUtils.isNotEmpty(ta)) {
+                attrs.putAll(ta);
             }
-            return attrs;
-        });
+        }
+
+        Map<String, ?> completions = resolveMissingFileAttributes(file, flags, attrs, options);
+        if (MapEntryUtils.isNotEmpty(completions)) {
+            attrs.putAll(completions);
+        }
+        return attrs;
     }
 
     /**
@@ -2628,7 +2632,7 @@ public abstract class AbstractSftpSubsystemHelper
             Object value = ae.getValue();
             String view = null;
             switch (attribute) {
-                case "size": {
+                case IoUtils.SIZE_VIEW_ATTR: {
                     long newSize = ((Number) value).longValue();
                     SftpFileSystemAccessor accessor = getFileSystemAccessor();
                     ServerSession session = getServerSession();
@@ -2639,36 +2643,36 @@ public abstract class AbstractSftpSubsystemHelper
                     }
                     continue;
                 }
-                case "uid":
+                case IoUtils.USERID_VIEW_ATTR:
                     view = "unix";
                     break;
-                case "gid":
+                case IoUtils.GROUPID_VIEW_ATTR:
                     view = "unix";
                     break;
-                case "owner":
+                case IoUtils.OWNER_VIEW_ATTR:
                     view = "posix";
                     value = toUser(file, (UserPrincipal) value);
                     break;
-                case "group":
+                case IoUtils.GROUP_VIEW_ATTR:
                     view = "posix";
                     value = toGroup(file, (GroupPrincipal) value);
                     break;
-                case "permissions":
+                case IoUtils.PERMISSIONS_VIEW_ATTR:
                     view = "posix";
                     break;
-                case "acl":
+                case IoUtils.ACL_VIEW_ATTR:
                     view = "acl";
                     break;
-                case "creationTime":
+                case IoUtils.CREATE_TIME_VIEW_ATTR:
                     view = "basic";
                     break;
-                case "lastModifiedTime":
+                case IoUtils.LASTMOD_TIME_VIEW_ATTR:
                     view = "basic";
                     break;
-                case "lastAccessTime":
+                case IoUtils.LASTACC_TIME_VIEW_ATTR:
                     view = "basic";
                     break;
-                case "extended":
+                case IoUtils.EXTENDED_VIEW_ATTR:
                     view = "extended";
                     break;
                 default: // ignored
@@ -2715,21 +2719,22 @@ public abstract class AbstractSftpSubsystemHelper
                     getServerSession(), file, view, attribute, value);
         }
 
-        if ("acl".equalsIgnoreCase(attribute) && "acl".equalsIgnoreCase(view)) {
+        if (IoUtils.ACL_VIEW_ATTR.equalsIgnoreCase(attribute) && "acl".equalsIgnoreCase(view)) {
             @SuppressWarnings("unchecked")
             List<AclEntry> acl = (List<AclEntry>) value;
             setFileAccessControl(file, acl, options);
-        } else if ("permissions".equalsIgnoreCase(attribute)) {
+        } else if (IoUtils.PERMISSIONS_VIEW_ATTR.equalsIgnoreCase(attribute)) {
             @SuppressWarnings("unchecked")
             Set<PosixFilePermission> perms = (Set<PosixFilePermission>) value;
             setFilePermissions(file, perms, options);
-        } else if ("owner".equalsIgnoreCase(attribute) || "group".equalsIgnoreCase(attribute)) {
+        } else if (IoUtils.OWNER_VIEW_ATTR.equalsIgnoreCase(attribute)
+                || IoUtils.GROUP_VIEW_ATTR.equalsIgnoreCase(attribute)) {
             setFileOwnership(file, attribute, (Principal) value, options);
-        } else if ("creationTime".equalsIgnoreCase(attribute)
-                || "lastModifiedTime".equalsIgnoreCase(attribute)
-                || "lastAccessTime".equalsIgnoreCase(attribute)) {
+        } else if (IoUtils.CREATE_TIME_VIEW_ATTR.equalsIgnoreCase(attribute)
+                || IoUtils.LASTMOD_TIME_VIEW_ATTR.equalsIgnoreCase(attribute)
+                || IoUtils.LASTACC_TIME_VIEW_ATTR.equalsIgnoreCase(attribute)) {
             setFileTime(file, view, attribute, (FileTime) value, options);
-        } else if ("extended".equalsIgnoreCase(view) && "extended".equalsIgnoreCase(attribute)) {
+        } else if (IoUtils.EXTENDED_VIEW_ATTR.equalsIgnoreCase(attribute) && "extended".equalsIgnoreCase(view)) {
             @SuppressWarnings("unchecked")
             Map<String, byte[]> extensions = (Map<String, byte[]>) value;
             setFileExtensions(file, extensions, options);
@@ -2776,9 +2781,9 @@ public abstract class AbstractSftpSubsystemHelper
          * used to set the file owner to a user principal that is not a group.
          */
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
-        if ("owner".equalsIgnoreCase(attribute)) {
+        if (IoUtils.OWNER_VIEW_ATTR.equalsIgnoreCase(attribute)) {
             accessor.setFileOwner(serverSession, this, file, value, options);
-        } else if ("group".equalsIgnoreCase(attribute)) {
+        } else if (IoUtils.GROUP_VIEW_ATTR.equalsIgnoreCase(attribute)) {
             accessor.setGroupOwner(serverSession, this, file, value, options);
         } else {
             throw new UnsupportedOperationException("Unknown ownership attribute: " + attribute);
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/FileHandle.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/FileHandle.java
index 8e3b453..b583054 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/FileHandle.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/FileHandle.java
@@ -230,12 +230,12 @@ public class FileHandle extends Handle {
 
     public static FileAttribute<?> toFileAttribute(String key, Object val) {
         // Some ignored attributes sent by the SFTP client
-        if ("isOther".equals(key)) {
+        if (IoUtils.OTHERFILE_VIEW_ATTR.equals(key)) {
             if ((Boolean) val) {
                 throw new IllegalArgumentException("Not allowed to use " + key + "=" + val);
             }
             return null;
-        } else if ("isRegular".equals(key)) {
+        } else if (IoUtils.REGFILE_VIEW_ATTR.equals(key)) {
             if (!(Boolean) val) {
                 throw new IllegalArgumentException("Not allowed to use " + key + "=" + val);
             }
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpFileSystemAccessor.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpFileSystemAccessor.java
index 70c1638..369aa9c 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpFileSystemAccessor.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpFileSystemAccessor.java
@@ -74,12 +74,12 @@ public interface SftpFileSystemAccessor {
      */
     NavigableMap<String, FileInfoExtractor<?>> FILEATTRS_RESOLVERS
             = NavigableMapBuilder.<String, FileInfoExtractor<?>> builder(String.CASE_INSENSITIVE_ORDER)
-                    .put("isRegularFile", FileInfoExtractor.ISREG)
-                    .put("isDirectory", FileInfoExtractor.ISDIR)
-                    .put("isSymbolicLink", FileInfoExtractor.ISSYMLINK)
-                    .put("permissions", FileInfoExtractor.PERMISSIONS)
-                    .put("size", FileInfoExtractor.SIZE)
-                    .put("lastModifiedTime", FileInfoExtractor.LASTMODIFIED)
+                    .put(IoUtils.REGFILE_VIEW_ATTR, FileInfoExtractor.ISREG)
+                    .put(IoUtils.DIRECTORY_VIEW_ATTR, FileInfoExtractor.ISDIR)
+                    .put(IoUtils.SYMLINK_VIEW_ATTR, FileInfoExtractor.ISSYMLINK)
+                    .put(IoUtils.PERMISSIONS_VIEW_ATTR, FileInfoExtractor.PERMISSIONS)
+                    .put(IoUtils.SIZE_VIEW_ATTR, FileInfoExtractor.SIZE)
+                    .put(IoUtils.LASTMOD_TIME_VIEW_ATTR, FileInfoExtractor.LASTMODIFIED)
                     .immutable();
 
     /** Whether to invoke {@link FileChannel#force(boolean)} on files open for write when closing */
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpVersionsTest.java b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpVersionsTest.java
index 8a926a9..d277bbc 100644
--- a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpVersionsTest.java
+++ b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpVersionsTest.java
@@ -299,7 +299,7 @@ public class SftpVersionsTest extends AbstractSftpClientTestSupport {
                         }
 
                         @SuppressWarnings("unchecked")
-                        List<AclEntry> aclActual = (List<AclEntry>) attrs.put("acl", aclExpected);
+                        List<AclEntry> aclActual = (List<AclEntry>) attrs.put(IoUtils.ACL_VIEW_ATTR, aclExpected);
                         if (aclActual != null) {
                             log.info("resolveFileAttributes(" + file + ") replaced ACL: " + aclActual);
                         }
@@ -330,7 +330,8 @@ public class SftpVersionsTest extends AbstractSftpClientTestSupport {
             @Override
             public void modifyingAttributes(ServerSession session, Path path, Map<String, ?> attrs) {
                 @SuppressWarnings("unchecked")
-                List<AclEntry> aclActual = MapEntryUtils.isEmpty(attrs) ? null : (List<AclEntry>) attrs.get("acl");
+                List<AclEntry> aclActual
+                        = MapEntryUtils.isEmpty(attrs) ? null : (List<AclEntry>) attrs.get(IoUtils.ACL_VIEW_ATTR);
                 if (getTestedVersion() > SftpConstants.SFTP_V3) {
                     assertListEquals("Mismatched modifying ACL for file=" + path, aclExpected, aclActual);
                 } else {
@@ -342,7 +343,8 @@ public class SftpVersionsTest extends AbstractSftpClientTestSupport {
             public void modifiedAttributes(
                     ServerSession session, Path path, Map<String, ?> attrs, Throwable thrown) {
                 @SuppressWarnings("unchecked")
-                List<AclEntry> aclActual = MapEntryUtils.isEmpty(attrs) ? null : (List<AclEntry>) attrs.get("acl");
+                List<AclEntry> aclActual
+                        = MapEntryUtils.isEmpty(attrs) ? null : (List<AclEntry>) attrs.get(IoUtils.ACL_VIEW_ATTR);
                 if (getTestedVersion() > SftpConstants.SFTP_V3) {
                     assertListEquals("Mismatched modified ACL for file=" + path, aclExpected, aclActual);
                 } else {
@@ -418,7 +420,8 @@ public class SftpVersionsTest extends AbstractSftpClientTestSupport {
                         }
 
                         @SuppressWarnings("unchecked")
-                        Map<String, String> actExtensions = (Map<String, String>) attrs.put("extended", expExtensions);
+                        Map<String, String> actExtensions
+                                = (Map<String, String>) attrs.put(IoUtils.EXTENDED_VIEW_ATTR, expExtensions);
                         if (actExtensions != null) {
                             log.info("resolveFileAttributes(" + file + ") replaced extensions: " + actExtensions);
                         }
@@ -458,7 +461,7 @@ public class SftpVersionsTest extends AbstractSftpClientTestSupport {
             public void modifyingAttributes(ServerSession session, Path path, Map<String, ?> attrs) {
                 @SuppressWarnings("unchecked")
                 Map<String, byte[]> actExtensions
-                        = MapEntryUtils.isEmpty(attrs) ? null : (Map<String, byte[]>) attrs.get("extended");
+                        = MapEntryUtils.isEmpty(attrs) ? null : (Map<String, byte[]>) attrs.get(IoUtils.EXTENDED_VIEW_ATTR);
                 assertExtensionsMapEquals("modifying(" + path + ")", expExtensions, actExtensions);
             }
 
@@ -466,7 +469,7 @@ public class SftpVersionsTest extends AbstractSftpClientTestSupport {
             public void modifiedAttributes(ServerSession session, Path path, Map<String, ?> attrs, Throwable thrown) {
                 @SuppressWarnings("unchecked")
                 Map<String, byte[]> actExtensions
-                        = MapEntryUtils.isEmpty(attrs) ? null : (Map<String, byte[]>) attrs.get("extended");
+                        = MapEntryUtils.isEmpty(attrs) ? null : (Map<String, byte[]>) attrs.get(IoUtils.EXTENDED_VIEW_ATTR);
                 assertExtensionsMapEquals("modified(" + path + ")", expExtensions, actExtensions);
             }
         });
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/AbstractSftpFilesSystemSupport.java b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/AbstractSftpFilesSystemSupport.java
index b516290..9c71dfb 100644
--- a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/AbstractSftpFilesSystemSupport.java
+++ b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/AbstractSftpFilesSystemSupport.java
@@ -41,6 +41,7 @@ import java.util.Map;
 
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.sftp.client.AbstractSftpClientTestSupport;
 import org.apache.sshd.sftp.client.SftpClientFactory;
 import org.apache.sshd.sftp.client.SftpVersionSelector;
@@ -165,10 +166,10 @@ public abstract class AbstractSftpFilesSystemSupport extends AbstractSftpClientT
 
         Map<String, ?> attrs = Files.readAttributes(file, "acl:*", LinkOption.NOFOLLOW_LINKS);
         outputDebugMessage("readAttributes(%s) %s", file, attrs);
-        assertEquals("Mismatched owner for " + file, aclView.getOwner(), attrs.get("owner"));
+        assertEquals("Mismatched owner for " + file, aclView.getOwner(), attrs.get(IoUtils.OWNER_VIEW_ATTR));
 
         @SuppressWarnings("unchecked")
-        List<AclEntry> acl = (List<AclEntry>) attrs.get("acl");
+        List<AclEntry> acl = (List<AclEntry>) attrs.get(IoUtils.ACL_VIEW_ATTR);
         outputDebugMessage("acls(%s) %s", file, acl);
         assertListEquals("Mismatched ACLs for " + file, aclView.getAcl(), acl);
 

[mina-sshd] 04/05: [SSHD-1226] Removed ServerSession argument from SftpFileSystemAccessor invocations since it can be retrieved from the provided SftpSubsystemProxy instance

Posted by lg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit 83a0684c59d45e46b7ad25973745d14a11adcaf9
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Fri Nov 19 08:04:21 2021 +0200

    [SSHD-1226] Removed ServerSession argument from SftpFileSystemAccessor invocations since it can be retrieved from the provided SftpSubsystemProxy instance
---
 CHANGES.md                                         |   2 +
 .../sftp/server/AbstractSftpSubsystemHelper.java   | 128 +++++++++------------
 .../apache/sshd/sftp/server/DirectoryHandle.java   |   8 +-
 .../org/apache/sshd/sftp/server/FileHandle.java    |  12 +-
 .../sshd/sftp/server/SftpFileSystemAccessor.java   | 115 +++++++-----------
 .../org/apache/sshd/sftp/server/SftpSubsystem.java |  19 ++-
 .../java/org/apache/sshd/sftp/client/SftpTest.java |   9 +-
 7 files changed, 115 insertions(+), 178 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index de364fb..7cdd68d 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -18,6 +18,8 @@
 
 ## Potential compatibility issues
 
+* Removed `ServerSession` argument from `SftpFileSystemAccessor` invocations since it can be retrieved from the provided `SftpSubsystemProxy` instance
+
 ## Minor code helpers
 
 * [SSHD-1193](https://issues.apache.org/jira/browse/SSHD-1193) Provide a more user-friendly text in case disconnecting due to timeout(s).
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/AbstractSftpSubsystemHelper.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/AbstractSftpSubsystemHelper.java
index f219524..6687c12 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/AbstractSftpSubsystemHelper.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/AbstractSftpSubsystemHelper.java
@@ -320,16 +320,16 @@ public abstract class AbstractSftpSubsystemHelper
      * @throws IOException if anything wrong happens
      */
     protected void process(Buffer buffer) throws IOException {
+        ServerSession session = getServerSession();
         int length = buffer.getInt();
         int type = buffer.getUByte();
         int id = buffer.getInt();
         if (log.isDebugEnabled()) {
             log.debug("process({})[length={}, type={}, id={}] processing",
-                    getServerSession(), length, SftpConstants.getCommandMessageName(type), id);
+                    session, length, SftpConstants.getCommandMessageName(type), id);
         }
         try {
             SftpEventListener listener = getSftpEventListenerProxy();
-            ServerSession session = getServerSession();
             listener.received(session, type, id);
         } catch (IOException | RuntimeException e) {
             if (type == SftpConstants.SSH_FXP_INIT) {
@@ -631,10 +631,9 @@ public abstract class AbstractSftpSubsystemHelper
 
     protected Map<String, Object> doLStat(int id, String path, int flags) throws IOException {
         Path p = resolveFile(path);
-        ServerSession session = getServerSession();
         if (log.isDebugEnabled()) {
             log.debug("doLStat({})[id={}] SSH_FXP_LSTAT (path={}[{}], flags=0x{})",
-                    session, id, path, p, Integer.toHexString(flags));
+                    getServerSession(), id, path, p, Integer.toHexString(flags));
         }
 
         /*
@@ -643,7 +642,7 @@ public abstract class AbstractSftpSubsystemHelper
          */
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
         LinkOption[] options = accessor.resolveFileAccessLinkOptions(
-                session, this, p, SftpConstants.SSH_FXP_LSTAT, "", false);
+                this, p, SftpConstants.SSH_FXP_LSTAT, "", false);
         return resolveFileAttributes(p, flags, options);
     }
 
@@ -666,9 +665,8 @@ public abstract class AbstractSftpSubsystemHelper
             int id, String path, int cmd, String extension, Map<String, ?> attrs, Boolean followLinks)
             throws IOException {
         if (log.isDebugEnabled()) {
-            ServerSession session = getServerSession();
             log.debug("doSetStat({})[id={}, cmd={}, extension={}]  (path={}, attrs={}, followLinks={})",
-                    session, id, cmd, extension, path, attrs, followLinks);
+                    getServerSession(), id, cmd, extension, path, attrs, followLinks);
         }
 
         Path p = resolveFile(path);
@@ -940,7 +938,7 @@ public abstract class AbstractSftpSubsystemHelper
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
         ServerSession session = getServerSession();
         try (SeekableByteChannel channel = accessor.openFile(
-                session, this, null, file, null, Collections.emptySet())) {
+                this, null, file, null, Collections.emptySet())) {
             channel.position(startOffset);
 
             Digest digest = factory.create();
@@ -999,7 +997,7 @@ public abstract class AbstractSftpSubsystemHelper
                 }
             }
 
-            accessor.closeFile(session, this, null, file, null, channel, Collections.emptySet());
+            accessor.closeFile(this, null, file, null, channel, Collections.emptySet());
         }
     }
 
@@ -1059,7 +1057,7 @@ public abstract class AbstractSftpSubsystemHelper
         boolean traceEnabled = log.isTraceEnabled();
         ServerSession session = getServerSession();
         try (SeekableByteChannel channel = accessor.openFile(
-                session, this, null, path, null, Collections.emptySet())) {
+                this, null, path, null, Collections.emptySet())) {
             channel.position(startOffset);
 
             /*
@@ -1130,7 +1128,7 @@ public abstract class AbstractSftpSubsystemHelper
                 hashValue = GenericUtils.EMPTY_BYTE_ARRAY;
             }
 
-            accessor.closeFile(session, this, null, path, null, channel, Collections.emptySet());
+            accessor.closeFile(this, null, path, null, channel, Collections.emptySet());
         }
 
         if (traceEnabled) {
@@ -1175,11 +1173,10 @@ public abstract class AbstractSftpSubsystemHelper
     protected SimpleImmutableEntry<Path, String> doReadLink(int id, String path) throws IOException {
         Path link = resolveFile(path);
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
-        ServerSession session = getServerSession();
-        String target = accessor.resolveLinkTarget(session, this, link);
+        String target = accessor.resolveLinkTarget(this, link);
         if (log.isDebugEnabled()) {
             log.debug("doReadLink({})[id={}] path={}[{}]: {}",
-                    session, id, path, link, target);
+                    getServerSession(), id, path, link, target);
         }
         return new SimpleImmutableEntry<>(link, target);
     }
@@ -1232,7 +1229,7 @@ public abstract class AbstractSftpSubsystemHelper
         listener.moving(session, o, n, opts);
         try {
             SftpFileSystemAccessor accessor = getFileSystemAccessor();
-            accessor.renameFile(session, this, o, n, opts);
+            accessor.renameFile(this, o, n, opts);
         } catch (IOException | RuntimeException | Error e) {
             listener.moved(session, o, n, opts, e);
             throw e;
@@ -1318,7 +1315,7 @@ public abstract class AbstractSftpSubsystemHelper
         Path src = resolveFile(srcFile);
         Path dst = resolveFile(dstFile);
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
-        accessor.copyFile(getServerSession(), this, src, dst, opts);
+        accessor.copyFile(this, src, dst, opts);
     }
 
     protected void doBlock(Buffer buffer, int id) throws IOException {
@@ -1381,10 +1378,9 @@ public abstract class AbstractSftpSubsystemHelper
     }
 
     protected Map<String, Object> doStat(int id, String path, int flags) throws IOException {
-        ServerSession session = getServerSession();
         if (log.isDebugEnabled()) {
             log.debug("doStat({})[id={}] SSH_FXP_STAT (path={}, flags=0x{})",
-                    session, id, path, Integer.toHexString(flags));
+                    getServerSession(), id, path, Integer.toHexString(flags));
         }
 
         /*
@@ -1394,7 +1390,7 @@ public abstract class AbstractSftpSubsystemHelper
         Path p = resolveFile(path);
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
         LinkOption[] options = accessor.resolveFileAccessLinkOptions(
-                session, this, p, SftpConstants.SSH_FXP_STAT, "", true);
+                this, p, SftpConstants.SSH_FXP_STAT, "", true);
         return resolveFileAttributes(p, flags, options);
     }
 
@@ -1562,14 +1558,13 @@ public abstract class AbstractSftpSubsystemHelper
 
     protected void doRemoveDirectory(int id, String path, boolean followLinks) throws IOException {
         Path p = resolveFile(path);
-        ServerSession session = getServerSession();
         if (log.isDebugEnabled()) {
-            log.debug("doRemoveDirectory({})[id={}] SSH_FXP_RMDIR (path={})[{}]", session, id, path, p);
+            log.debug("doRemoveDirectory({})[id={}] SSH_FXP_RMDIR (path={})[{}]", getServerSession(), id, path, p);
         }
 
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
         LinkOption[] options = accessor.resolveFileAccessLinkOptions(
-                session, this, p, SftpConstants.SSH_FXP_RMDIR, "", followLinks);
+                this, p, SftpConstants.SSH_FXP_RMDIR, "", followLinks);
         if (Files.isDirectory(p, options)) {
             doRemove(id, p, true);
         } else {
@@ -1593,7 +1588,7 @@ public abstract class AbstractSftpSubsystemHelper
         listener.removing(session, p, isDirectory);
         try {
             SftpFileSystemAccessor accessor = getFileSystemAccessor();
-            accessor.removeFile(session, this, p, isDirectory);
+            accessor.removeFile(this, p, isDirectory);
         } catch (IOException | RuntimeException | Error e) {
             listener.removed(session, p, isDirectory, e);
             throw e;
@@ -1627,7 +1622,7 @@ public abstract class AbstractSftpSubsystemHelper
 
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
         LinkOption[] options = accessor.resolveFileAccessLinkOptions(
-                session, this, resolvedPath, SftpConstants.SSH_FXP_MKDIR, "", followLinks);
+                this, resolvedPath, SftpConstants.SSH_FXP_MKDIR, "", followLinks);
         SftpPathImpl.withAttributeCache(resolvedPath, p -> {
             Boolean status = IoUtils.checkFileExists(p, options);
             if (status == null) {
@@ -1647,7 +1642,7 @@ public abstract class AbstractSftpSubsystemHelper
         SftpEventListener listener = getSftpEventListenerProxy();
         listener.creating(session, resolvedPath, attrs);
         try {
-            accessor.createDirectory(session, this, resolvedPath);
+            accessor.createDirectory(this, resolvedPath);
             followLinks = resolvePathResolutionFollowLinks(SftpConstants.SSH_FXP_MKDIR, "", resolvedPath);
             doSetAttributes(SftpConstants.SSH_FXP_MKDIR, "", resolvedPath, attrs, followLinks);
         } catch (IOException | RuntimeException | Error e) {
@@ -1674,14 +1669,13 @@ public abstract class AbstractSftpSubsystemHelper
 
     protected void doRemoveFile(int id, String path, boolean followLinks) throws IOException {
         Path resolvedPath = resolveFile(path);
-        ServerSession session = getServerSession();
         if (log.isDebugEnabled()) {
-            log.debug("doRemoveFile({})[id={}] SSH_FXP_REMOVE (path={}[{}])", session, id, path, resolvedPath);
+            log.debug("doRemoveFile({})[id={}] SSH_FXP_REMOVE (path={}[{}])", getServerSession(), id, path, resolvedPath);
         }
 
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
         LinkOption[] options = accessor.resolveFileAccessLinkOptions(
-                session, this, resolvedPath, SftpConstants.SSH_FXP_REMOVE, "", followLinks);
+                this, resolvedPath, SftpConstants.SSH_FXP_REMOVE, "", followLinks);
         SftpPathImpl.withAttributeCache(resolvedPath, p -> {
             Boolean status = IoUtils.checkFileExists(p, options);
             if (status == null) {
@@ -2124,15 +2118,14 @@ public abstract class AbstractSftpSubsystemHelper
     }
 
     protected void sendLink(Buffer buffer, int id, Path file, String link) throws IOException {
-        // in case we are running on Windows
-        String unixPath = link.replace(File.separatorChar, '/');
-        SftpFileSystemAccessor accessor = getFileSystemAccessor();
-        ServerSession session = getServerSession();
-
         buffer.putByte((byte) SftpConstants.SSH_FXP_NAME);
         buffer.putInt(id);
         buffer.putInt(1); // one response
-        accessor.putRemoteFileName(session, this, file, buffer, unixPath, true);
+
+        // in case we are running on Windows
+        String unixPath = link.replace(File.separatorChar, '/');
+        SftpFileSystemAccessor accessor = getFileSystemAccessor();
+        accessor.putRemoteFileName(this, file, buffer, unixPath, true);
 
         /*
          * As per the spec (https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.10):
@@ -2143,11 +2136,11 @@ public abstract class AbstractSftpSubsystemHelper
         int version = getVersion();
         if (version == SftpConstants.SFTP_V3) {
             String longName = SftpHelper.getLongName(unixPath, attrs);
-            accessor.putRemoteFileName(session, this, file, buffer, longName, false);
+            accessor.putRemoteFileName(this, file, buffer, longName, false);
         }
 
         writeAttrs(buffer, attrs);
-        SftpHelper.indicateEndOfNamesList(buffer, getVersion(), session);
+        SftpHelper.indicateEndOfNamesList(buffer, getVersion(), getServerSession());
         send(buffer);
     }
 
@@ -2162,17 +2155,16 @@ public abstract class AbstractSftpSubsystemHelper
         // in case we are running on Windows
         String unixPath = originalPath.replace(File.separatorChar, '/');
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
-        ServerSession session = getServerSession();
-        accessor.putRemoteFileName(session, this, f, buffer, unixPath, true);
+        accessor.putRemoteFileName(this, f, buffer, unixPath, true);
 
         int version = getVersion();
         if (version == SftpConstants.SFTP_V3) {
             String longName = getLongName(f, getShortName(f), attrs);
-            accessor.putRemoteFileName(session, this, f, buffer, longName, false);
+            accessor.putRemoteFileName(this, f, buffer, longName, false);
         }
 
         writeAttrs(buffer, attrs);
-        SftpHelper.indicateEndOfNamesList(buffer, getVersion(), session);
+        SftpHelper.indicateEndOfNamesList(buffer, getVersion(), getServerSession());
         send(buffer);
     }
 
@@ -2192,7 +2184,7 @@ public abstract class AbstractSftpSubsystemHelper
         ServerSession session = getServerSession();
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
         LinkOption[] options = accessor.resolveFileAccessLinkOptions(
-                session, this, dir.getFile(), SftpConstants.SSH_FXP_READDIR, "", followLinks);
+                this, dir.getFile(), SftpConstants.SSH_FXP_READDIR, "", followLinks);
         int nb = 0;
         Map<String, Path> entries = new TreeMap<>(Comparator.naturalOrder());
         while ((dir.isSendDot() || dir.isSendDotDot() || dir.hasNext()) && (buffer.wpos() < maxSize)) {
@@ -2236,11 +2228,11 @@ public abstract class AbstractSftpSubsystemHelper
         int version = getVersion();
 
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
-        accessor.putRemoteFileName(session, this, f, buffer, shortName, true);
+        accessor.putRemoteFileName(this, f, buffer, shortName, true);
 
         if (version == SftpConstants.SFTP_V3) {
             String longName = getLongName(f, shortName, attributes);
-            accessor.putRemoteFileName(session, this, f, buffer, longName, false);
+            accessor.putRemoteFileName(this, f, buffer, longName, false);
 
             if (log.isTraceEnabled()) {
                 log.trace("writeDirEntry({}) id={})[{}] - writing entry {} [{}]: {}", session, id, index, shortName, longName,
@@ -2276,12 +2268,12 @@ public abstract class AbstractSftpSubsystemHelper
 
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
         ServerSession session = getServerSession();
-        accessor.putRemoteFileName(session, this, f, buffer, shortName, true);
+        accessor.putRemoteFileName(this, f, buffer, shortName, true);
 
         int version = getVersion();
         if (version == SftpConstants.SFTP_V3) {
             String longName = getLongName(f, shortName, options);
-            accessor.putRemoteFileName(session, this, f, buffer, longName, false);
+            accessor.putRemoteFileName(this, f, buffer, longName, false);
 
             if (log.isTraceEnabled()) {
                 log.trace("writeDirEntry(" + session + ") id=" + id + ")[" + index + "] - "
@@ -2553,8 +2545,7 @@ public abstract class AbstractSftpSubsystemHelper
             throws IOException {
         try {
             SftpFileSystemAccessor accessor = getFileSystemAccessor();
-            Map<String, ?> attrs = accessor.readFileAttributes(
-                    getServerSession(), this, file, view, options);
+            Map<String, ?> attrs = accessor.readFileAttributes(this, file, view, options);
             if (MapEntryUtils.isEmpty(attrs)) {
                 return Collections.emptyNavigableMap();
             }
@@ -2602,7 +2593,7 @@ public abstract class AbstractSftpSubsystemHelper
         try {
             SftpFileSystemAccessor accessor = getFileSystemAccessor();
             LinkOption[] options = accessor.resolveFileAccessLinkOptions(
-                    session, this, file, cmd, extension, followLinks);
+                    this, file, cmd, extension, followLinks);
             setFileAttributes(file, attributes, options);
         } catch (IOException | RuntimeException | Error e) {
             listener.modifiedAttributes(session, file, attributes, e);
@@ -2614,12 +2605,11 @@ public abstract class AbstractSftpSubsystemHelper
     protected LinkOption[] getPathResolutionLinkOption(int cmd, String extension, Path path) throws IOException {
         boolean followLinks = resolvePathResolutionFollowLinks(cmd, extension, path);
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
-        return accessor.resolveFileAccessLinkOptions(getServerSession(), this, path, cmd, extension, followLinks);
+        return accessor.resolveFileAccessLinkOptions(this, path, cmd, extension, followLinks);
     }
 
     protected boolean resolvePathResolutionFollowLinks(int cmd, String extension, Path path) throws IOException {
-        ServerSession session = getServerSession();
-        return SftpModuleProperties.AUTO_FOLLOW_LINKS.getRequired(session);
+        return SftpModuleProperties.AUTO_FOLLOW_LINKS.getRequired(getServerSession());
     }
 
     protected void setFileAttributes(
@@ -2635,11 +2625,10 @@ public abstract class AbstractSftpSubsystemHelper
                 case IoUtils.SIZE_VIEW_ATTR: {
                     long newSize = ((Number) value).longValue();
                     SftpFileSystemAccessor accessor = getFileSystemAccessor();
-                    ServerSession session = getServerSession();
                     Set<StandardOpenOption> openOptions = EnumSet.of(StandardOpenOption.WRITE);
-                    try (SeekableByteChannel channel = accessor.openFile(session, this, null, file, null, openOptions)) {
+                    try (SeekableByteChannel channel = accessor.openFile(this, null, file, null, openOptions)) {
                         channel.truncate(newSize);
-                        accessor.closeFile(session, this, null, file, null, channel, openOptions);
+                        accessor.closeFile(this, null, file, null, channel, openOptions);
                     }
                     continue;
                 }
@@ -2762,16 +2751,14 @@ public abstract class AbstractSftpSubsystemHelper
             Path file, String view, String attribute, Object value, LinkOption... options)
             throws IOException {
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
-        accessor.setFileAttribute(
-                getServerSession(), this, file, view, attribute, value, options);
+        accessor.setFileAttribute(this, file, view, attribute, value, options);
     }
 
     protected void setFileOwnership(
             Path file, String attribute, Principal value, LinkOption... options)
             throws IOException {
-        ServerSession serverSession = getServerSession();
         if (log.isDebugEnabled()) {
-            log.debug("setFileOwnership({})[{}] {}={}", serverSession, file, attribute, value);
+            log.debug("setFileOwnership({})[{}] {}={}", getServerSession(), file, attribute, value);
         }
 
         /*
@@ -2782,9 +2769,9 @@ public abstract class AbstractSftpSubsystemHelper
          */
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
         if (IoUtils.OWNER_VIEW_ATTR.equalsIgnoreCase(attribute)) {
-            accessor.setFileOwner(serverSession, this, file, value, options);
+            accessor.setFileOwner(this, file, value, options);
         } else if (IoUtils.GROUP_VIEW_ATTR.equalsIgnoreCase(attribute)) {
-            accessor.setGroupOwner(serverSession, this, file, value, options);
+            accessor.setGroupOwner(this, file, value, options);
         } else {
             throw new UnsupportedOperationException("Unknown ownership attribute: " + attribute);
         }
@@ -2818,26 +2805,23 @@ public abstract class AbstractSftpSubsystemHelper
     protected void setFilePermissions(
             Path file, Set<PosixFilePermission> perms, LinkOption... options)
             throws IOException {
-        ServerSession serverSession = getServerSession();
         if (log.isTraceEnabled()) {
-            log.trace("setFilePermissions({})[{}] {}", serverSession, file, perms);
+            log.trace("setFilePermissions({})[{}] {}", getServerSession(), file, perms);
         }
 
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
-        accessor.setFilePermissions(
-                serverSession, this, file, perms, options);
+        accessor.setFilePermissions(this, file, perms, options);
     }
 
     protected void setFileAccessControl(
             Path file, List<AclEntry> acl, LinkOption... options)
             throws IOException {
-        ServerSession serverSession = getServerSession();
         if (log.isTraceEnabled()) {
-            log.trace("setFileAccessControl({})[{}] {}", serverSession, file, acl);
+            log.trace("setFileAccessControl({})[{}] {}", getServerSession(), file, acl);
         }
 
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
-        accessor.setFileAccessControl(serverSession, this, file, acl, options);
+        accessor.setFileAccessControl(this, file, acl, options);
     }
 
     protected void handleUnsupportedAttributes(Collection<String> attributes) {
@@ -2863,7 +2847,7 @@ public abstract class AbstractSftpSubsystemHelper
     protected GroupPrincipal toGroup(Path file, GroupPrincipal name) throws IOException {
         try {
             SftpFileSystemAccessor accessor = getFileSystemAccessor();
-            return accessor.resolveGroupOwner(getServerSession(), this, file, name);
+            return accessor.resolveGroupOwner(this, file, name);
         } catch (IOException e) {
             handleUserPrincipalLookupServiceException(GroupPrincipal.class, name.toString(), e);
             return null;
@@ -2873,7 +2857,7 @@ public abstract class AbstractSftpSubsystemHelper
     protected UserPrincipal toUser(Path file, UserPrincipal name) throws IOException {
         try {
             SftpFileSystemAccessor accessor = getFileSystemAccessor();
-            return accessor.resolveFileOwner(getServerSession(), this, file, name);
+            return accessor.resolveFileOwner(this, file, name);
         } catch (IOException e) {
             handleUserPrincipalLookupServiceException(UserPrincipal.class, name.toString(), e);
             return null;
@@ -3006,12 +2990,10 @@ public abstract class AbstractSftpSubsystemHelper
      */
     protected Path resolveFile(String remotePath)
             throws IOException, InvalidPathException {
-        ServerSession serverSession = getServerSession();
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
-        Path localPath = accessor.resolveLocalFilePath(
-                serverSession, this, getDefaultDirectory(), remotePath);
+        Path localPath = accessor.resolveLocalFilePath(this, getDefaultDirectory(), remotePath);
         if (log.isTraceEnabled()) {
-            log.trace("resolveFile({}) {} => {}", serverSession, remotePath, localPath);
+            log.trace("resolveFile({}) {} => {}", getServerSession(), remotePath, localPath);
         }
         return localPath;
     }
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/DirectoryHandle.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/DirectoryHandle.java
index 4a8dd9a..a6a55a6 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/DirectoryHandle.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/DirectoryHandle.java
@@ -23,8 +23,6 @@ import java.nio.file.DirectoryStream;
 import java.nio.file.Path;
 import java.util.Iterator;
 
-import org.apache.sshd.server.session.ServerSession;
-
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
@@ -40,9 +38,8 @@ public class DirectoryHandle extends Handle implements Iterator<Path> {
         super(subsystem, dir, handle);
 
         SftpFileSystemAccessor accessor = subsystem.getFileSystemAccessor();
-        ServerSession session = subsystem.getServerSession();
         signalHandleOpening();
-        ds = accessor.openDirectory(session, subsystem, this, dir, handle);
+        ds = accessor.openDirectory(subsystem, this, dir, handle);
 
         Path parent = dir.getParent();
         if (parent == null) {
@@ -104,8 +101,7 @@ public class DirectoryHandle extends Handle implements Iterator<Path> {
         try {
             SftpSubsystem subsystem = getSubsystem();
             SftpFileSystemAccessor accessor = subsystem.getFileSystemAccessor();
-            ServerSession session = subsystem.getServerSession();
-            accessor.closeDirectory(session, subsystem, this, getFile(), getFileHandle(), ds);
+            accessor.closeDirectory(subsystem, this, getFile(), getFileHandle(), ds);
         } finally {
             super.close();
             markDone(); // just making sure
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/FileHandle.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/FileHandle.java
index b583054..9458555 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/FileHandle.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/FileHandle.java
@@ -39,7 +39,6 @@ import java.util.concurrent.atomic.AtomicReference;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.MapEntryUtils;
 import org.apache.sshd.common.util.io.IoUtils;
-import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.sftp.common.SftpConstants;
 import org.apache.sshd.sftp.common.SftpException;
 
@@ -79,14 +78,13 @@ public class FileHandle extends Handle {
                 : fileAttributes.toArray(new FileAttribute<?>[fileAttributes.size()]);
 
         SftpFileSystemAccessor accessor = subsystem.getFileSystemAccessor();
-        ServerSession session = subsystem.getServerSession();
         SeekableByteChannel channel;
         try {
             channel = accessor.openFile(
-                    session, subsystem, this, file, handle, openOptions, fileAttrs);
+                    subsystem, this, file, handle, openOptions, fileAttrs);
         } catch (UnsupportedOperationException e) {
             channel = accessor.openFile(
-                    session, subsystem, this, file, handle, openOptions, IoUtils.EMPTY_FILE_ATTRIBUTES);
+                    subsystem, this, file, handle, openOptions, IoUtils.EMPTY_FILE_ATTRIBUTES);
             subsystem.doSetAttributes(SftpConstants.SSH_FXP_OPEN, "", file, attrs, false);
         }
         this.fileChannel = channel;
@@ -163,8 +161,7 @@ public class FileHandle extends Handle {
 
         SftpSubsystem subsystem = getSubsystem();
         SftpFileSystemAccessor accessor = subsystem.getFileSystemAccessor();
-        ServerSession session = subsystem.getServerSession();
-        accessor.closeFile(session, subsystem, this, getFile(), getFileHandle(), getFileChannel(), getOpenOptions());
+        accessor.closeFile(subsystem, this, getFile(), getFileHandle(), getFileChannel(), getOpenOptions());
     }
 
     public void lock(long offset, long length, int mask) throws IOException {
@@ -172,9 +169,8 @@ public class FileHandle extends Handle {
         long size = (length == 0L) ? channel.size() - offset : length;
         SftpSubsystem subsystem = getSubsystem();
         SftpFileSystemAccessor accessor = subsystem.getFileSystemAccessor();
-        ServerSession session = subsystem.getServerSession();
         FileLock lock = accessor.tryLock(
-                session, subsystem, this, getFile(), getFileHandle(), channel, offset, size, false);
+                subsystem, this, getFile(), getFileHandle(), channel, offset, size, false);
         if (lock == null) {
             throw new SftpException(
                     SftpConstants.SSH_FX_BYTE_RANGE_LOCK_REFUSED,
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpFileSystemAccessor.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpFileSystemAccessor.java
index 369aa9c..8360312 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpFileSystemAccessor.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpFileSystemAccessor.java
@@ -59,7 +59,6 @@ import org.apache.sshd.common.util.SelectorUtils;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.io.FileInfoExtractor;
 import org.apache.sshd.common.util.io.IoUtils;
-import org.apache.sshd.server.session.ServerSession;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -98,7 +97,6 @@ public interface SftpFileSystemAccessor {
     /**
      * Invoked in order to resolve remote file paths reference by the client into ones accessible by the server
      *
-     * @param  session              The {@link ServerSession} through which the request was received
      * @param  subsystem            The SFTP subsystem instance that manages the session
      * @param  rootDir              The default root directory used to resolve relative paths - a.k.a. the
      *                              {@code chroot} location
@@ -110,7 +108,7 @@ public interface SftpFileSystemAccessor {
      *                              SftpSubsystemEnvironment#getDefaultDirectory()
      */
     default Path resolveLocalFilePath(
-            ServerSession session, SftpSubsystemProxy subsystem, Path rootDir, String remotePath)
+            SftpSubsystemProxy subsystem, Path rootDir, String remotePath)
             throws IOException, InvalidPathException {
         String path = SelectorUtils.translateToLocalFileSystemPath(
                 remotePath, '/', rootDir.getFileSystem());
@@ -120,7 +118,6 @@ public interface SftpFileSystemAccessor {
     /**
      * Invoked in order to determine the symbolic link follow options
      *
-     * @param  session     The {@link ServerSession} through which the request was received
      * @param  subsystem   The SFTP subsystem instance that manages the session
      * @param  file        The referenced file
      * @param  cmd         The SFTP command that triggered this access
@@ -131,8 +128,7 @@ public interface SftpFileSystemAccessor {
      * @see                <A HREF="https://issues.apache.org/jira/browse/SSHD-1137">SSHD-1137</A>
      */
     default LinkOption[] resolveFileAccessLinkOptions(
-            ServerSession session, SftpSubsystemProxy subsystem, Path file,
-            int cmd, String extension, boolean followLinks)
+            SftpSubsystemProxy subsystem, Path file, int cmd, String extension, boolean followLinks)
             throws IOException {
         return IoUtils.getLinkOptions(followLinks);
     }
@@ -140,7 +136,6 @@ public interface SftpFileSystemAccessor {
     /**
      * Invoked in order to encode the outgoing referenced file name/path
      *
-     * @param  session     The {@link ServerSession} through which the request was received
      * @param  subsystem   The SFTP subsystem instance that manages the session
      * @param  path        The associated file {@link Path} - <B>Note:</B> might be a symbolic link container
      * @param  buf         The target {@link Buffer} for the encoded string
@@ -151,7 +146,7 @@ public interface SftpFileSystemAccessor {
      * @see                <A HREF="https://issues.apache.org/jira/browse/SSHD-1132">SSHD-1132</A>
      */
     default void putRemoteFileName(
-            ServerSession session, SftpSubsystemProxy subsystem, Path path, Buffer buf, String name, boolean shortName)
+            SftpSubsystemProxy subsystem, Path path, Buffer buf, String name, boolean shortName)
             throws IOException {
         buf.putString(name);
     }
@@ -159,13 +154,11 @@ public interface SftpFileSystemAccessor {
     /**
      * Called whenever a new file is opened
      *
-     * @param  session     The {@link ServerSession} through which the request was received
      * @param  subsystem   The SFTP subsystem instance that manages the session
      * @param  fileHandle  The {@link FileHandle} representing the created channel - may be {@code null} if not invoked
      *                     within the context of such a handle (special cases)
      * @param  file        The requested <U>local</U> file {@link Path} - same one returned by
-     *                     {@link #resolveLocalFilePath(ServerSession, SftpSubsystemProxy, Path, String)
-     *                     resolveLocalFilePath}
+     *                     {@link #resolveLocalFilePath(SftpSubsystemProxy, Path, String) resolveLocalFilePath}
      * @param  handle      The assigned file handle through which the remote peer references this file. May be
      *                     {@code null}/empty if the request is due to some internal functionality instead of due to
      *                     peer requesting a handle to a file.
@@ -175,8 +168,8 @@ public interface SftpFileSystemAccessor {
      * @throws IOException If failed to open
      */
     default SeekableByteChannel openFile(
-            ServerSession session, SftpSubsystemProxy subsystem, FileHandle fileHandle,
-            Path file, String handle, Set<? extends OpenOption> options, FileAttribute<?>... attrs)
+            SftpSubsystemProxy subsystem, FileHandle fileHandle, Path file,
+            String handle, Set<? extends OpenOption> options, FileAttribute<?>... attrs)
             throws IOException {
         /*
          * According to https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#page-33
@@ -193,15 +186,13 @@ public interface SftpFileSystemAccessor {
     /**
      * Called when locking a section of a file is requested
      *
-     * @param  session     The {@link ServerSession} through which the request was received
      * @param  subsystem   The SFTP subsystem instance that manages the session
      * @param  fileHandle  The {@link FileHandle} representing the created channel
      * @param  file        The requested <U>local</U> file {@link Path} - same one returned by
-     *                     {@link #resolveLocalFilePath(ServerSession, SftpSubsystemProxy, Path, String)
-     *                     resolveLocalFilePath}
+     *                     {@link #resolveLocalFilePath(SftpSubsystemProxy, Path, String) resolveLocalFilePath}
      * @param  handle      The assigned file handle through which the remote peer references this file
      * @param  channel     The original {@link Channel} that was returned by
-     *                     {@link #openFile(ServerSession, SftpSubsystemProxy, FileHandle, Path, String, Set, FileAttribute...)}
+     *                     {@link #openFile(SftpSubsystemProxy, FileHandle, Path, String, Set, FileAttribute...)}
      * @param  position    The position at which the locked region is to start - must be non-negative
      * @param  size        The size of the locked region; must be non-negative, and the sum
      *                     <tt>position</tt>&nbsp;+&nbsp;<tt>size</tt> must be non-negative
@@ -213,8 +204,8 @@ public interface SftpFileSystemAccessor {
      */
     @SuppressWarnings("checkstyle:ParameterNumber")
     default FileLock tryLock(
-            ServerSession session, SftpSubsystemProxy subsystem, FileHandle fileHandle,
-            Path file, String handle, Channel channel, long position, long size, boolean shared)
+            SftpSubsystemProxy subsystem, FileHandle fileHandle, Path file, String handle,
+            Channel channel, long position, long size, boolean shared)
             throws IOException {
         if (!(channel instanceof FileChannel)) {
             throw new StreamCorruptedException("Non file channel to lock: " + channel);
@@ -226,23 +217,20 @@ public interface SftpFileSystemAccessor {
     /**
      * Called when file meta-data re-synchronization is required
      *
-     * @param  session     The {@link ServerSession} through which the request was received
      * @param  subsystem   The SFTP subsystem instance that manages the session
      * @param  fileHandle  The {@link FileHandle} representing the created channel
      * @param  file        The requested <U>local</U> file {@link Path} - same one returned by
-     *                     {@link #resolveLocalFilePath(ServerSession, SftpSubsystemProxy, Path, String)
-     *                     resolveLocalFilePath}
+     *                     {@link #resolveLocalFilePath(SftpSubsystemProxy, Path, String) resolveLocalFilePath}
      * @param  handle      The assigned file handle through which the remote peer references this file
      * @param  channel     The original {@link Channel} that was returned by
-     *                     {@link #openFile(ServerSession, SftpSubsystemProxy, FileHandle, Path, String, Set, FileAttribute...)}
+     *                     {@link #openFile(SftpSubsystemProxy, FileHandle, Path, String, Set, FileAttribute...)}
      * @throws IOException If failed to execute the request
      * @see                FileChannel#force(boolean)
      * @see                <A HREF="https://github.com/openssh/openssh-portable/blob/master/PROTOCOL">OpenSSH - section
      *                     10</A>
      */
     default void syncFileData(
-            ServerSession session, SftpSubsystemProxy subsystem, FileHandle fileHandle, Path file, String handle,
-            Channel channel)
+            SftpSubsystemProxy subsystem, FileHandle fileHandle, Path file, String handle, Channel channel)
             throws IOException {
         if (!(channel instanceof FileChannel)) {
             throw new StreamCorruptedException("Non file channel to sync: " + channel);
@@ -254,22 +242,20 @@ public interface SftpFileSystemAccessor {
     /**
      * Called to inform the accessor that it should close the file
      *
-     * @param  session     The {@link ServerSession} through which the request was received
      * @param  subsystem   The SFTP subsystem instance that manages the session
      * @param  fileHandle  The {@link FileHandle} representing the created channel - may be {@code null} if not invoked
      *                     within the context of such a handle (special cases)
      * @param  file        The requested <U>local</U> file {@link Path} - same one returned by
-     *                     {@link #resolveLocalFilePath(ServerSession, SftpSubsystemProxy, Path, String)
-     *                     resolveLocalFilePath}
+     *                     {@link #resolveLocalFilePath(SftpSubsystemProxy, Path, String) resolveLocalFilePath}
      * @param  handle      The assigned file handle through which the remote peer references this file
      * @param  channel     The original {@link Channel} that was returned by
-     *                     {@link #openFile(ServerSession, SftpSubsystemProxy, FileHandle, Path, String, Set, FileAttribute...)}
+     *                     {@link #openFile(SftpSubsystemProxy, FileHandle, Path, String, Set, FileAttribute...)}
      * @param  options     The original options used to open the channel
      * @throws IOException If failed to execute the request
      */
     default void closeFile(
-            ServerSession session, SftpSubsystemProxy subsystem, FileHandle fileHandle,
-            Path file, String handle, Channel channel, Set<? extends OpenOption> options)
+            SftpSubsystemProxy subsystem, FileHandle fileHandle, Path file,
+            String handle, Channel channel, Set<? extends OpenOption> options)
             throws IOException {
         if ((channel == null) || (!channel.isOpen())) {
             return;
@@ -278,7 +264,7 @@ public interface SftpFileSystemAccessor {
         if ((channel instanceof FileChannel)
                 && GenericUtils.containsAny(options, IoUtils.WRITEABLE_OPEN_OPTIONS)
                 && PropertyResolverUtils.getBooleanProperty(
-                        session, PROP_AUTO_SYNC_FILE_ON_CLOSE, DEFAULT_AUTO_SYNC_FILE_ON_CLOSE)) {
+                        subsystem.getSession(), PROP_AUTO_SYNC_FILE_ON_CLOSE, DEFAULT_AUTO_SYNC_FILE_ON_CLOSE)) {
             ((FileChannel) channel).force(true);
         }
 
@@ -288,18 +274,16 @@ public interface SftpFileSystemAccessor {
     /**
      * Called when a new directory stream is requested
      *
-     * @param  session     The {@link ServerSession} through which the request was received
      * @param  subsystem   The SFTP subsystem instance that manages the session
      * @param  dirHandle   The {@link DirectoryHandle} representing the stream
      * @param  dir         The requested <U>local</U> directory {@link Path} - same one returned by
-     *                     {@link #resolveLocalFilePath(ServerSession, SftpSubsystemProxy, Path, String)
-     *                     resolveLocalFilePath}
+     *                     {@link #resolveLocalFilePath(SftpSubsystemProxy, Path, String) resolveLocalFilePath}
      * @param  handle      The assigned directory handle through which the remote peer references this directory
      * @return             The opened {@link DirectoryStream}
      * @throws IOException If failed to open
      */
     default DirectoryStream<Path> openDirectory(
-            ServerSession session, SftpSubsystemProxy subsystem, DirectoryHandle dirHandle, Path dir, String handle)
+            SftpSubsystemProxy subsystem, DirectoryHandle dirHandle, Path dir, String handle)
             throws IOException {
         return Files.newDirectoryStream(dir);
     }
@@ -307,19 +291,17 @@ public interface SftpFileSystemAccessor {
     /**
      * Called when a directory stream is no longer required
      *
-     * @param  session     The {@link ServerSession} through which the request was received
      * @param  subsystem   The SFTP subsystem instance that manages the session
      * @param  dirHandle   The {@link DirectoryHandle} representing the stream - may be {@code null} if not invoked
      *                     within the context of such a handle (special cases)
      * @param  dir         The requested <U>local</U> directory {@link Path} - same one returned by
-     *                     {@link #resolveLocalFilePath(ServerSession, SftpSubsystemProxy, Path, String)
-     *                     resolveLocalFilePath}
+     *                     {@link #resolveLocalFilePath(SftpSubsystemProxy, Path, String) resolveLocalFilePath}
      * @param  handle      The assigned directory handle through which the remote peer references this directory
      * @param  ds          The disposed {@link DirectoryStream}
      * @throws IOException If failed to open
      */
     default void closeDirectory(
-            ServerSession session, SftpSubsystemProxy subsystem, DirectoryHandle dirHandle,
+            SftpSubsystemProxy subsystem, DirectoryHandle dirHandle,
             Path dir, String handle, DirectoryStream<Path> ds)
             throws IOException {
         if (ds == null) {
@@ -332,11 +314,9 @@ public interface SftpFileSystemAccessor {
     /**
      * Invoked when required to retrieve file attributes for a specific file system view
      *
-     * @param  session     The {@link ServerSession} through which the request was received
      * @param  subsystem   The SFTP subsystem instance that manages the session
      * @param  file        The requested <U>local</U> file {@link Path} - same one returned by
-     *                     {@link #resolveLocalFilePath(ServerSession, SftpSubsystemProxy, Path, String)
-     *                     resolveLocalFilePath}
+     *                     {@link #resolveLocalFilePath(SftpSubsystemProxy, Path, String) resolveLocalFilePath}
      * @param  view        The required view name
      * @param  options     The access {@link LinkOption}-s
      * @return             A {@link Map} of all the attributes available for the file in the view
@@ -344,8 +324,7 @@ public interface SftpFileSystemAccessor {
      * @see                Files#readAttributes(Path, String, LinkOption...)
      */
     default Map<String, ?> readFileAttributes(
-            ServerSession session, SftpSubsystemProxy subsystem,
-            Path file, String view, LinkOption... options)
+            SftpSubsystemProxy subsystem, Path file, String view, LinkOption... options)
             throws IOException {
         return Files.readAttributes(file, view, options);
     }
@@ -353,11 +332,9 @@ public interface SftpFileSystemAccessor {
     /**
      * Sets a view attribute for a local file
      *
-     * @param  session     The {@link ServerSession} through which the request was received
      * @param  subsystem   The SFTP subsystem instance that manages the session
      * @param  file        The requested <U>local</U> file {@link Path} - same one returned by
-     *                     {@link #resolveLocalFilePath(ServerSession, SftpSubsystemProxy, Path, String)
-     *                     resolveLocalFilePath}
+     *                     {@link #resolveLocalFilePath(SftpSubsystemProxy, Path, String) resolveLocalFilePath}
      * @param  view        The required view name
      * @param  attribute   The attribute name
      * @param  value       The attribute value
@@ -365,8 +342,8 @@ public interface SftpFileSystemAccessor {
      * @throws IOException If failed to set the attribute
      */
     default void setFileAttribute(
-            ServerSession session, SftpSubsystemProxy subsystem, Path file,
-            String view, String attribute, Object value, LinkOption... options)
+            SftpSubsystemProxy subsystem, Path file, String view,
+            String attribute, Object value, LinkOption... options)
             throws IOException {
         if (value == null) {
             return;
@@ -376,7 +353,7 @@ public interface SftpFileSystemAccessor {
     }
 
     default UserPrincipal resolveFileOwner(
-            ServerSession session, SftpSubsystemProxy subsystem, Path file, UserPrincipal name)
+            SftpSubsystemProxy subsystem, Path file, UserPrincipal name)
             throws IOException {
         FileSystem fileSystem = file.getFileSystem();
         UserPrincipalLookupService lookupService = fileSystem.getUserPrincipalLookupService();
@@ -390,8 +367,7 @@ public interface SftpFileSystemAccessor {
     }
 
     default void setFileOwner(
-            ServerSession session, SftpSubsystemProxy subsystem, Path file,
-            Principal value, LinkOption... options)
+            SftpSubsystemProxy subsystem, Path file, Principal value, LinkOption... options)
             throws IOException {
         if (value == null) {
             return;
@@ -411,7 +387,7 @@ public interface SftpFileSystemAccessor {
     }
 
     default GroupPrincipal resolveGroupOwner(
-            ServerSession session, SftpSubsystemProxy subsystem, Path file, GroupPrincipal name)
+            SftpSubsystemProxy subsystem, Path file, GroupPrincipal name)
             throws IOException {
         FileSystem fileSystem = file.getFileSystem();
         UserPrincipalLookupService lookupService = fileSystem.getUserPrincipalLookupService();
@@ -424,8 +400,7 @@ public interface SftpFileSystemAccessor {
     }
 
     default void setGroupOwner(
-            ServerSession session, SftpSubsystemProxy subsystem,
-            Path file, Principal value, LinkOption... options)
+            SftpSubsystemProxy subsystem, Path file, Principal value, LinkOption... options)
             throws IOException {
         if (value == null) {
             return;
@@ -445,8 +420,7 @@ public interface SftpFileSystemAccessor {
     }
 
     default void setFilePermissions(
-            ServerSession session, SftpSubsystemProxy subsystem, Path file,
-            Set<PosixFilePermission> perms, LinkOption... options)
+            SftpSubsystemProxy subsystem, Path file, Set<PosixFilePermission> perms, LinkOption... options)
             throws IOException {
         if (OsUtils.isWin32()) {
             IoUtils.setPermissionsToFile(file.toFile(), perms);
@@ -462,8 +436,7 @@ public interface SftpFileSystemAccessor {
     }
 
     default void setFileAccessControl(
-            ServerSession session, SftpSubsystemProxy subsystem,
-            Path file, List<AclEntry> acl, LinkOption... options)
+            SftpSubsystemProxy subsystem, Path file, List<AclEntry> acl, LinkOption... options)
             throws IOException {
         AclFileAttributeView view = Files.getFileAttributeView(file, AclFileAttributeView.class, options);
         if (view == null) {
@@ -473,20 +446,16 @@ public interface SftpFileSystemAccessor {
         view.setAcl(acl);
     }
 
-    default void createDirectory(
-            ServerSession session, SftpSubsystemProxy subsystem, Path path)
-            throws IOException {
+    default void createDirectory(SftpSubsystemProxy subsystem, Path path) throws IOException {
         Files.createDirectory(path);
     }
 
     /**
      * Invoked in order to create a link to a path
      *
-     * @param  session     The {@link ServerSession} through which the request was received
      * @param  subsystem   The SFTP subsystem instance that manages the session
      * @param  link        The requested <U>link</U> {@link Path} - same one returned by
-     *                     {@link #resolveLocalFilePath(ServerSession, SftpSubsystemProxy, Path, String)
-     *                     resolveLocalFilePath}
+     *                     {@link #resolveLocalFilePath(SftpSubsystemProxy, Path, String) resolveLocalFilePath}
      * @param  existing    The <U>existing</U> {@link Path} that the link should reference
      * @param  symLink     {@code true} if this should be a symbolic link
      * @throws IOException If failed to create the link
@@ -494,7 +463,7 @@ public interface SftpFileSystemAccessor {
      * @see                Files#createSymbolicLink(Path, Path, FileAttribute...)
      */
     default void createLink(
-            ServerSession session, SftpSubsystemProxy subsystem, Path link, Path existing, boolean symLink)
+            SftpSubsystemProxy subsystem, Path link, Path existing, boolean symLink)
             throws IOException {
         if (symLink) {
             Files.createSymbolicLink(link, existing);
@@ -503,16 +472,13 @@ public interface SftpFileSystemAccessor {
         }
     }
 
-    default String resolveLinkTarget(
-            ServerSession session, SftpSubsystemProxy subsystem, Path link)
-            throws IOException {
+    default String resolveLinkTarget(SftpSubsystemProxy subsystem, Path link) throws IOException {
         Path target = Files.readSymbolicLink(link);
         return target.toString();
     }
 
     default void renameFile(
-            ServerSession session, SftpSubsystemProxy subsystem,
-            Path oldPath, Path newPath, Collection<CopyOption> opts)
+            SftpSubsystemProxy subsystem, Path oldPath, Path newPath, Collection<CopyOption> opts)
             throws IOException {
         Files.move(oldPath, newPath,
                 GenericUtils.isEmpty(opts)
@@ -521,8 +487,7 @@ public interface SftpFileSystemAccessor {
     }
 
     default void copyFile(
-            ServerSession session, SftpSubsystemProxy subsystem,
-            Path src, Path dst, Collection<CopyOption> opts)
+            SftpSubsystemProxy subsystem, Path src, Path dst, Collection<CopyOption> opts)
             throws IOException {
         Files.copy(src, dst,
                 GenericUtils.isEmpty(opts)
@@ -531,7 +496,7 @@ public interface SftpFileSystemAccessor {
     }
 
     default void removeFile(
-            ServerSession session, SftpSubsystemProxy subsystem, Path path, boolean isDirectory)
+            SftpSubsystemProxy subsystem, Path path, boolean isDirectory)
             throws IOException {
         Files.delete(path);
     }
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpSubsystem.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpSubsystem.java
index eac48fe..d985c5d 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpSubsystem.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpSubsystem.java
@@ -346,7 +346,7 @@ public class SftpSubsystem
         listener.linking(session, link, existing, symLink);
         try {
             SftpFileSystemAccessor accessor = getFileSystemAccessor();
-            accessor.createLink(session, this, link, existing, symLink);
+            accessor.createLink(this, link, existing, symLink);
         } catch (IOException | RuntimeException | Error e) {
             listener.linked(session, link, existing, symLink, e);
             throw e;
@@ -369,15 +369,14 @@ public class SftpSubsystem
     @Override
     protected void doOpenSSHFsync(int id, String handle) throws IOException {
         Handle h = handles.get(handle);
-        ServerSession session = getServerSession();
         if (log.isDebugEnabled()) {
-            log.debug("doOpenSSHFsync({})[id={}] {}[{}]", session, id, handle, h);
+            log.debug("doOpenSSHFsync({})[id={}] {}[{}]", getServerSession(), id, handle, h);
         }
 
         FileHandle fileHandle = validateHandle(handle, h, FileHandle.class);
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
         accessor.syncFileData(
-                session, this, fileHandle, fileHandle.getFile(),
+                this, fileHandle, fileHandle.getFile(),
                 fileHandle.getFileHandle(), fileHandle.getFileChannel());
     }
 
@@ -425,7 +424,7 @@ public class SftpSubsystem
 
             SftpFileSystemAccessor accessor = getFileSystemAccessor();
             LinkOption[] options = accessor.resolveFileAccessLinkOptions(
-                    getServerSession(), this, path, SftpConstants.SSH_FXP_EXTENDED, targetType, false);
+                    this, path, SftpConstants.SSH_FXP_EXTENDED, targetType, false);
             if (Files.isDirectory(path, options)) {
                 throw new NotDirectoryException(path.toString());
             }
@@ -449,10 +448,9 @@ public class SftpSubsystem
     protected byte[] doMD5Hash(
             int id, String targetType, String target, long startOffset, long length, byte[] quickCheckHash)
             throws Exception {
-        ServerSession session = getServerSession();
         if (log.isDebugEnabled()) {
             log.debug("doMD5Hash({})({})[{}] offset={}, length={}, quick-hash={}",
-                    session, targetType, target, startOffset, length,
+                    getServerSession(), targetType, target, startOffset, length,
                     BufferUtils.toHex(':', quickCheckHash));
         }
 
@@ -478,7 +476,7 @@ public class SftpSubsystem
 
             SftpFileSystemAccessor accessor = getFileSystemAccessor();
             LinkOption[] options = accessor.resolveFileAccessLinkOptions(
-                    session, this, path, SftpConstants.SSH_FXP_EXTENDED, targetType, true);
+                    this, path, SftpConstants.SSH_FXP_EXTENDED, targetType, true);
             if (Files.isDirectory(path, options)) {
                 throw new NotDirectoryException(path.toString());
             }
@@ -805,17 +803,16 @@ public class SftpSubsystem
     @Override
     protected Map<String, Object> doFStat(int id, String handle, int flags) throws IOException {
         Handle h = handles.get(handle);
-        ServerSession session = getServerSession();
         if (log.isDebugEnabled()) {
             log.debug("doFStat({})[id={}] SSH_FXP_FSTAT (handle={}[{}], flags=0x{})",
-                    session, id, handle, h, Integer.toHexString(flags));
+                    getServerSession(), id, handle, h, Integer.toHexString(flags));
         }
 
         Handle fileHandle = validateHandle(handle, h, Handle.class);
         SftpFileSystemAccessor accessor = getFileSystemAccessor();
         Path file = fileHandle.getFile();
         LinkOption[] options = accessor.resolveFileAccessLinkOptions(
-                session, this, file, SftpConstants.SSH_FXP_FSTAT, "", true);
+                this, file, SftpConstants.SSH_FXP_FSTAT, "", true);
         return resolveFileAttributes(file, flags, options);
     }
 
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpTest.java b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpTest.java
index 4232dc6..35422f8 100644
--- a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpTest.java
+++ b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpTest.java
@@ -618,21 +618,20 @@ public class SftpTest extends AbstractSftpClientTestSupport {
             factory.setFileSystemAccessor(new SftpFileSystemAccessor() {
                 @Override
                 public SeekableByteChannel openFile(
-                        ServerSession session, SftpSubsystemProxy subsystem, FileHandle fileHandle, Path file,
+                        SftpSubsystemProxy subsystem, FileHandle fileHandle, Path file,
                         String handle, Set<? extends OpenOption> options, FileAttribute<?>... attrs)
                         throws IOException {
                     fileHolder.set(file);
                     return SftpFileSystemAccessor.super.openFile(
-                            session, subsystem, fileHandle, file, handle, options, attrs);
+                            subsystem, fileHandle, file, handle, options, attrs);
                 }
 
                 @Override
                 public DirectoryStream<Path> openDirectory(
-                        ServerSession session, SftpSubsystemProxy subsystem,
-                        DirectoryHandle dirHandle, Path dir, String handle)
+                        SftpSubsystemProxy subsystem, DirectoryHandle dirHandle, Path dir, String handle)
                         throws IOException {
                     dirHolder.set(dir);
-                    return SftpFileSystemAccessor.super.openDirectory(session, subsystem, dirHandle, dir, handle);
+                    return SftpFileSystemAccessor.super.openDirectory(subsystem, dirHandle, dir, handle);
                 }
 
                 @Override

[mina-sshd] 05/05: [SSHD-1226] Added SFTP server-side capability to provide file/folder custom extension attributes

Posted by lg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit 3e382d75e8b629afe5a6297b6e43818a341bd78d
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Fri Nov 19 08:57:41 2021 +0200

    [SSHD-1226] Added SFTP server-side capability to provide file/folder custom extension attributes
---
 CHANGES.md                                         |   1 +
 docs/sftp.md                                       |  57 +++++++-
 .../sftp/server/AbstractSftpSubsystemHelper.java   |  20 ++-
 .../sshd/sftp/server/SftpFileSystemAccessor.java   |  34 +++++
 .../sftp/client/extensions/SftpExtensionsTest.java | 147 +++++++++++++++++++++
 .../extensions/UnsupportedExtensionTest.java       |  62 ---------
 6 files changed, 250 insertions(+), 71 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 7cdd68d..1abc7d5 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -44,3 +44,4 @@
 * [SSHD-1219](https://issues.apache.org/jira/browse/SSHD-1219) Obtaining rsa-sha2-256 or rsa-sha2-512 signatures from an SSH agent
 * [SSHD-1220](https://issues.apache.org/jira/browse/SSHD-1220) Reduce number of L(STAT) calls made by the SftpFileSystem
 * [SSHD-1221](https://issues.apache.org/jira/browse/SSHD-1221) Support key constraints when adding a key to an SSH agent
+* [SSHD-1226](https://issues.apache.org/jira/browse/SSHD-1226) Added SFTP server-side capability to provide file/folder custom extension attributes
diff --git a/docs/sftp.md b/docs/sftp.md
index b7c6362..e76ddf3 100644
--- a/docs/sftp.md
+++ b/docs/sftp.md
@@ -601,7 +601,11 @@ Collection<ScanDirEntry> matches = ds.scan(client);
 
 ```
 
-## Extensions
+## Extensions & custom file/folder attributes
+
+Extending the SFTP protocol and/or the reported file/folder attributes
+
+### SFTP protocol extensions
 
 Both client and server support several of the SFTP extensions specified in various drafts:
 
@@ -685,7 +689,7 @@ try (ClientSession session = client.connect(username, host, port).verify(timeout
 
 ```
 
-### Contributing support for a new extension
+#### Contributing support for a new SFTP extension
 
 * Add the code to handle the new extension in `AbstractSftpSubsystemHelper#executeExtendedCommand`
 
@@ -698,6 +702,55 @@ for sending and receiving the newly added extension.
 
 See how other extensions are implemented and follow their example
 
+### Providing/processing file/folder custom attributes
+
+According to [SFTP - File Attributes](https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02#section-5) it is possible to provide
+custom attributes for a referenced file/folder. The client-side code supports this via the `Attributes#getExtensions` call. On the server-side
+one needs to provide a custom `SftpFileSystemAccessor` that overrides the `resolveReportedFileAttributes` method (which by default
+simply returns the original attrbiutes as-is. A similar hook method has been provided in case a client attempts to apply custom attributes - simply
+need to provide a implementation that obverrides `applyExtensionFileAttributes` (which by default ignores the attributes).
+
+```java
+class MyCustomSftpFileSystemAccessor implements SftpFileSystemAccessor {
+    @Override
+    public NavigableMap<String, Object> resolveReportedFileAttributes(
+            SftpSubsystemProxy subsystem, Path file, int flags, NavigableMap<String, Object> attrs, LinkOption... options)
+                throws IOException {
+        Map<String, Object> extra = (Map<String, Object>) attrs.get(IoUtils.EXTENDED_VIEW_ATTR);
+        if (extra == null) {
+            extra = new HashMap<>();
+            attrs.put(IoUtils.EXTENDED_VIEW_ATTR, extra)
+        }
+        extra.put("custom1", ...some string...);
+        extra.put("custom", ...some byte[]...)
+    }
+    
+    @Override
+    public void applyExtensionFileAttributes(
+            SftpSubsystemProxy subsystem, Path file, Map<String, byte[]> extensions, LinkOption... options)
+                throws IOException {
+        if (MapEntryUtils.isNotEmpty(extensions)) {
+            ...process the extensions...
+        }
+    }
+}
+
+SftpSubsystemFactory factory = new SftpSubsystemFactory.Builder()
+    .withFileSystemAccessor(new MyCustomSftpFileSystemAccessor())
+    .build();
+
+SshdServer sshd = ...setup...
+sshd.setSubsystemFactories(Collections.singletonList(factory));
+```
+
+
+
+**Note:**
+
+* The code assumes that the extension name is a **string** - the draft specification actually allows an array of bytes as well, but we chose simplicity.
+
+* The value can be either a string or an array of bytes. If the value is neither (e.g., an integer) then the value's *toString()* will be used.
+
 ## References
 
 * [SFTP drafts for the various versions](https://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/)
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/AbstractSftpSubsystemHelper.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/AbstractSftpSubsystemHelper.java
index 6687c12..812f24b 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/AbstractSftpSubsystemHelper.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/AbstractSftpSubsystemHelper.java
@@ -2418,7 +2418,10 @@ public abstract class AbstractSftpSubsystemHelper
      */
     protected NavigableMap<String, Object> getAttributes(Path path, int flags, LinkOption... options)
             throws IOException {
-        return SftpPathImpl.withAttributeCache(path, file -> resolveReportedFileAttributes(file, flags, options));
+        NavigableMap<String, Object> attrs
+                = SftpPathImpl.withAttributeCache(path, file -> resolveReportedFileAttributes(file, flags, options));
+        SftpFileSystemAccessor accessor = getFileSystemAccessor();
+        return accessor.resolveReportedFileAttributes(this, path, flags, attrs, options);
     }
 
     protected NavigableMap<String, Object> resolveReportedFileAttributes(Path file, int flags, LinkOption... options)
@@ -2780,10 +2783,6 @@ public abstract class AbstractSftpSubsystemHelper
     protected void setFileExtensions(
             Path file, Map<String, byte[]> extensions, LinkOption... options)
             throws IOException {
-        if (MapEntryUtils.isEmpty(extensions)) {
-            return;
-        }
-
         /*
          * According to v3,4,5:
          *
@@ -2794,10 +2793,17 @@ public abstract class AbstractSftpSubsystemHelper
          */
         int version = getVersion();
         if (version < SftpConstants.SFTP_V6) {
-            if (log.isDebugEnabled()) {
-                log.debug("setFileExtensions({})[{}]: {}", getServerSession(), file, extensions);
+            if (MapEntryUtils.isNotEmpty(extensions) && log.isDebugEnabled()) {
+                log.debug("setFileExtensions({})[{}]: {}", getServerSession(), file, extensions.keySet());
             }
+
+            SftpFileSystemAccessor accessor = getFileSystemAccessor();
+            accessor.applyExtensionFileAttributes(this, file, extensions, options);
         } else {
+            if (MapEntryUtils.isEmpty(extensions)) {
+                return;
+            }
+
             throw new UnsupportedOperationException("File extensions not supported");
         }
     }
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpFileSystemAccessor.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpFileSystemAccessor.java
index 8360312..6d7c18f 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpFileSystemAccessor.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/server/SftpFileSystemAccessor.java
@@ -134,6 +134,40 @@ public interface SftpFileSystemAccessor {
     }
 
     /**
+     * Invoked in order to allow intervention to the reported file attributes - e.g., add custom/extended properties
+     *
+     * @param  subsystem   The SFTP subsystem instance that manages the session
+     * @param  file        The referenced file
+     * @param  flags       A mask of the original required attributes
+     * @param  attrs       The default resolved attributes map
+     * @param  options     The {@link LinkOption}-s that were used to access the file's attributes
+     * @return             The updated attributes map
+     * @throws IOException If failed to resolve the attributes
+     * @see                <A HREF="https://issues.apache.org/jira/browse/SSHD-1226">SSHD-1226</A>
+     */
+    default NavigableMap<String, Object> resolveReportedFileAttributes(
+            SftpSubsystemProxy subsystem, Path file, int flags,
+            NavigableMap<String, Object> attrs, LinkOption... options)
+            throws IOException {
+        return attrs;
+    }
+
+    /**
+     * Invoked in order to allow processing of custom file attributes
+     *
+     * @param  subsystem   The SFTP subsystem instance that manages the session
+     * @param  file        The referenced file
+     * @param  extensions  The received extensions - may be {@code null}/empty
+     * @param  options     The {@link LinkOption}-s that were used to access the file's standard attributes
+     * @throws IOException If failed to apply the attributes
+     */
+    default void applyExtensionFileAttributes(
+            SftpSubsystemProxy subsystem, Path file, Map<String, byte[]> extensions, LinkOption... options)
+            throws IOException {
+        // ignored
+    }
+
+    /**
      * Invoked in order to encode the outgoing referenced file name/path
      *
      * @param  subsystem   The SFTP subsystem instance that manages the session
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/SftpExtensionsTest.java b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/SftpExtensionsTest.java
new file mode 100644
index 0000000..dbdcdf8
--- /dev/null
+++ b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/SftpExtensionsTest.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.sftp.client.extensions;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.MapEntryUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.server.subsystem.SubsystemFactory;
+import org.apache.sshd.sftp.client.AbstractSftpClientTestSupport;
+import org.apache.sshd.sftp.client.RawSftpClient;
+import org.apache.sshd.sftp.client.SftpClient;
+import org.apache.sshd.sftp.client.SftpClient.Attributes;
+import org.apache.sshd.sftp.common.SftpConstants;
+import org.apache.sshd.sftp.server.SftpFileSystemAccessor;
+import org.apache.sshd.sftp.server.SftpSubsystemFactory;
+import org.apache.sshd.sftp.server.SftpSubsystemProxy;
+import org.apache.sshd.util.test.CommonTestSupportUtils;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.testcontainers.shaded.com.google.common.base.Objects;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class SftpExtensionsTest extends AbstractSftpClientTestSupport {
+    public SftpExtensionsTest() throws IOException {
+        super();
+    }
+
+    @Test // see SSHD-890
+    public void testUnsupportedExtension() throws IOException {
+        try (SftpClient sftpClient = createSingleSessionClient()) {
+            RawSftpClient sftp = assertObjectInstanceOf("Not a raw SFTP client", RawSftpClient.class, sftpClient);
+
+            String opcode = getCurrentTestName();
+            Buffer buffer = new ByteArrayBuffer(Integer.BYTES + GenericUtils.length(opcode) + Byte.SIZE, false);
+            buffer.putString(opcode);
+
+            int cmd = sftp.send(SftpConstants.SSH_FXP_EXTENDED, buffer);
+            Buffer responseBuffer = sftp.receive(cmd);
+
+            responseBuffer.getInt(); // Ignoring length
+            int type = responseBuffer.getUByte();
+            responseBuffer.getInt(); // Ignoring message ID
+            int substatus = responseBuffer.getInt();
+
+            assertEquals("Type is not STATUS", SftpConstants.SSH_FXP_STATUS, type);
+            assertEquals("Sub-Type is not UNSUPPORTED", SftpConstants.SSH_FX_OP_UNSUPPORTED, substatus);
+        }
+    }
+
+    @Test   // see SSHD-1266
+    public void testCustomFileExtensionAttributes() throws IOException {
+        Path targetPath = detectTargetFolder();
+        Path parentPath = targetPath.getParent();
+        Path localFile = CommonTestSupportUtils.resolve(
+                targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName());
+        Files.createDirectories(localFile.getParent());
+        Files.writeString(localFile, getClass().getName() + "#" + getCurrentTestName() + "@" + new Date(),
+                StandardCharsets.UTF_8);
+
+        List<? extends SubsystemFactory> factories = sshd.getSubsystemFactories();
+        assertEquals("Mismatched subsystem factories count", 1, GenericUtils.size(factories));
+
+        SubsystemFactory f = factories.get(0);
+        assertObjectInstanceOf("Not an SFTP subsystem factory", SftpSubsystemFactory.class, f);
+
+        Map<String, String> expected = Collections.unmodifiableMap(
+                MapEntryUtils.MapBuilder.<String, String> builder()
+                        .put("test", getCurrentTestName())
+                        .put("class", getClass().getSimpleName())
+                        .put("package", getClass().getPackage().getName())
+                        .build());
+
+        SftpSubsystemFactory factory = (SftpSubsystemFactory) f;
+        SftpFileSystemAccessor accessor = factory.getFileSystemAccessor();
+        Attributes attrs;
+        try {
+            factory.setFileSystemAccessor(new SftpFileSystemAccessor() {
+                @Override
+                public NavigableMap<String, Object> resolveReportedFileAttributes(
+                        SftpSubsystemProxy subsystem,
+                        Path file, int flags, NavigableMap<String, Object> attrs, LinkOption... options)
+                        throws IOException {
+                    if (Objects.equal(file, localFile)) {
+                        @SuppressWarnings("unchecked")
+                        Map<String, Object> extra = (Map<String, Object>) attrs.get(IoUtils.EXTENDED_VIEW_ATTR);
+                        if (MapEntryUtils.isEmpty(extra)) {
+                            attrs.put(IoUtils.EXTENDED_VIEW_ATTR, expected);
+                        } else {
+                            extra.putAll(expected);
+                        }
+                    }
+                    return attrs;
+                }
+            });
+
+            try (SftpClient sftp = createSingleSessionClient()) {
+                attrs = sftp.stat(CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, localFile));
+            }
+
+        } finally {
+            factory.setFileSystemAccessor(accessor);    // restore original value
+        }
+
+        Map<String, byte[]> extsMap = attrs.getExtensions();
+        assertTrue("No extended attributes provided", MapEntryUtils.isNotEmpty(extsMap));
+
+        Map<String, String> actual = extsMap.entrySet()
+                .stream()
+                .collect(Collectors.toMap(
+                        Map.Entry::getKey, e -> new String(e.getValue(), StandardCharsets.UTF_8),
+                        MapEntryUtils.throwingMerger(), () -> new TreeMap<>(String.CASE_INSENSITIVE_ORDER)));
+        assertMapEquals(IoUtils.EXTENDED_VIEW_ATTR, expected, actual);
+    }
+}
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/UnsupportedExtensionTest.java b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/UnsupportedExtensionTest.java
deleted file mode 100644
index cea742a..0000000
--- a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/extensions/UnsupportedExtensionTest.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.sshd.sftp.client.extensions;
-
-import java.io.IOException;
-
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
-import org.apache.sshd.sftp.client.AbstractSftpClientTestSupport;
-import org.apache.sshd.sftp.client.RawSftpClient;
-import org.apache.sshd.sftp.client.SftpClient;
-import org.apache.sshd.sftp.common.SftpConstants;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runners.MethodSorters;
-
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class UnsupportedExtensionTest extends AbstractSftpClientTestSupport {
-    public UnsupportedExtensionTest() throws IOException {
-        super();
-    }
-
-    @Test // see SSHD-890
-    public void testUnsupportedExtension() throws IOException {
-        try (SftpClient sftpClient = createSingleSessionClient()) {
-            RawSftpClient sftp = assertObjectInstanceOf("Not a raw SFTP client", RawSftpClient.class, sftpClient);
-
-            String opcode = getCurrentTestName();
-            Buffer buffer = new ByteArrayBuffer(Integer.BYTES + GenericUtils.length(opcode) + Byte.SIZE, false);
-            buffer.putString(opcode);
-
-            int cmd = sftp.send(SftpConstants.SSH_FXP_EXTENDED, buffer);
-            Buffer responseBuffer = sftp.receive(cmd);
-
-            responseBuffer.getInt(); // Ignoring length
-            int type = responseBuffer.getUByte();
-            responseBuffer.getInt(); // Ignoring message ID
-            int substatus = responseBuffer.getInt();
-
-            assertEquals("Type is not STATUS", SftpConstants.SSH_FXP_STATUS, type);
-            assertEquals("Sub-Type is not UNSUPPORTED", SftpConstants.SSH_FX_OP_UNSUPPORTED, substatus);
-        }
-    }
-}

[mina-sshd] 01/05: Excluded failing MINA test

Posted by lg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit a708d45c435f843a763c22512c9ee9d71a6d29a1
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Fri Nov 19 07:29:06 2021 +0200

    Excluded failing MINA test
---
 sshd-mina/pom.xml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sshd-mina/pom.xml b/sshd-mina/pom.xml
index fc66c88..0d9894f 100644
--- a/sshd-mina/pom.xml
+++ b/sshd-mina/pom.xml
@@ -127,6 +127,7 @@
                         <exclude>**/CompressionTest.java</exclude>
                         <exclude>**/NoServerNoClientTest.java</exclude>
                         <exclude>**/OpenSSHCertificateTest.java</exclude>
+                        <exclude>**/FileHostKeyCertificateProviderTest.java</exclude>
                         <!-- exclude>**/PortForwardingTest.java</exclude -->
                         <exclude>**/MacTest.java</exclude>
                         <exclude>**/SpringConfigTest.java</exclude>