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

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-vfs.git


The following commit(s) were added to refs/heads/master by this push:
     new b1030e6  VFS-590 VFS-617 Proceed with moveTo operation if the exec 
channel for… (#75)
b1030e6 is described below

commit b1030e61013b55cacff82a2354b1c9b3456fd2a7
Author: Alex Pearce <[email protected]>
AuthorDate: Mon Dec 23 18:06:27 2019 +0000

    VFS-590 VFS-617 Proceed with moveTo operation if the exec channel for… (#75)
    
    * VFS-590 VFS-617 Proceed with moveTo operation if the exec channel for 
permission checks is closed
    
    * VFS-590 VFS-617 Apache license headers
    
    * VFS-590 VFS-617 Fix merge conflict
    
    * VFS-590 VFS-617 Test read, write, delete and rename on sftp closed exec 
channel
    
    * VFS-590 VFS-617 Clean execdisabled initialization
    
    Co-authored-by: sauerbraten <[email protected]>
---
 .../commons/vfs2/provider/sftp/SftpFileObject.java |   7 +
 .../commons/vfs2/provider/sftp/SftpFileSystem.java |  33 ++
 .../provider/sftp/UserIsOwnerPosixPermissions.java |  29 +
 .../test/java/org/apache/commons/vfs2/RunTest.java |   2 +-
 ...Case.java => AbstractSftpProviderTestCase.java} | 199 ++-----
 .../SftpProviderClosedExecChannelTestCase.java     |  47 ++
 .../test/SftpProviderStreamProxyModeTestCase.java  | 104 ++++
 .../provider/sftp/test/SftpProviderTestCase.java   | 650 +--------------------
 8 files changed, 292 insertions(+), 779 deletions(-)

diff --git 
a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/SftpFileObject.java
 
b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/SftpFileObject.java
index 27645b7..5c24502 100644
--- 
a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/SftpFileObject.java
+++ 
b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/SftpFileObject.java
@@ -228,6 +228,13 @@ public class SftpFileObject extends 
AbstractFileObject<SftpFileSystem> {
         statSelf();
         boolean isInGroup = false;
         if (checkIds) {
+            if(getAbstractFileSystem().isExecDisabled()) {
+                // Exec is disabled, so we won't be able to ascertain the 
current user's UID and GID.
+                // Return "always-true" permissions as a workaround, knowing 
that the SFTP server won't
+                // let us perform unauthorized actions anyway.
+                return new UserIsOwnerPosixPermissions(attrs.getPermissions());
+            }
+
             for (final int groupId : getAbstractFileSystem().getGroupsIds()) {
                 if (groupId == attrs.getGId()) {
                     isInGroup = true;
diff --git 
a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/SftpFileSystem.java
 
b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/SftpFileSystem.java
index e8c204f..a33f510 100644
--- 
a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/SftpFileSystem.java
+++ 
b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/SftpFileSystem.java
@@ -21,6 +21,8 @@ import java.io.InputStreamReader;
 import java.util.Collection;
 import java.util.Objects;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.commons.vfs2.Capability;
 import org.apache.commons.vfs2.FileObject;
 import org.apache.commons.vfs2.FileSystemException;
@@ -40,6 +42,8 @@ import com.jcraft.jsch.SftpException;
  */
 public class SftpFileSystem extends AbstractFileSystem {
 
+    private static final Log LOG = LogFactory.getLog(SftpFileSystem.class);
+
     private static final int UNIDENTIFED = -1;
 
     private static final int SLEEP_MILLIS = 100;
@@ -76,12 +80,18 @@ public class SftpFileSystem extends AbstractFileSystem {
      */
     private volatile int[] groupsIds;
 
+    /**
+     * Some SFTP-only servers disable the exec channel. When exec is disabled, 
things like getUId() will always fail.
+     */
+    private final boolean execDisabled;
+
     protected SftpFileSystem(final GenericFileName rootName, final Session 
session,
             final FileSystemOptions fileSystemOptions) {
         super(rootName, null, fileSystemOptions);
         this.session = Objects.requireNonNull(session, "session");
         this.connectTimeoutMillis = SftpFileSystemConfigBuilder.getInstance()
                 .getConnectTimeoutMillis(fileSystemOptions);
+        this.execDisabled = detectExecDisabled();
     }
 
     @Override
@@ -315,4 +325,27 @@ public class SftpFileSystem extends AbstractFileSystem {
         }
         return channel.getExitStatus();
     }
+
+    /**
+     * @see SftpFileSystem#execDisabled
+     */
+    public boolean isExecDisabled() {
+        return execDisabled;
+    }
+
+    /**
+     * Some SFTP-only servers disable the exec channel.
+     *
+     * Attempt to detect this by calling getUid.
+     */
+    private boolean detectExecDisabled() {
+        try {
+            getUId();
+            return false;
+        } catch(JSchException | IOException e) {
+            LOG.debug("Cannot get UID, assuming no exec channel is present", 
e);
+            return true;
+        }
+    }
+
 }
diff --git 
a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/UserIsOwnerPosixPermissions.java
 
b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/UserIsOwnerPosixPermissions.java
new file mode 100644
index 0000000..c986e20
--- /dev/null
+++ 
b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/sftp/UserIsOwnerPosixPermissions.java
@@ -0,0 +1,29 @@
+/*
+ * 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.commons.vfs2.provider.sftp;
+
+import org.apache.commons.vfs2.util.PosixPermissions;
+
+/**
+ * Pretends that the current user is always the owner and in the same group.
+ */
+public class UserIsOwnerPosixPermissions extends PosixPermissions {
+
+    public UserIsOwnerPosixPermissions(final int permissions) {
+        super(permissions, true, true);
+    }
+}
\ No newline at end of file
diff --git a/commons-vfs2/src/test/java/org/apache/commons/vfs2/RunTest.java 
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/RunTest.java
index a1c794d..740de96 100644
--- a/commons-vfs2/src/test/java/org/apache/commons/vfs2/RunTest.java
+++ b/commons-vfs2/src/test/java/org/apache/commons/vfs2/RunTest.java
@@ -49,7 +49,7 @@ public class RunTest {
                 // UrlProviderTestCase.suite(),
                 // ResourceProviderTestCase.suite(),
                 // HttpProviderTestCase.suite(),
-                // SftpProviderTestCase.suite(),
+                // AbstractSftpProviderTestCase.suite(),
                 // JarProviderTestCase.suite(),
                 // NestedJarTestCase.suite(),
                 // ZipProviderTestCase.suite(),
diff --git 
a/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderTestCase.java
 
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/AbstractSftpProviderTestCase.java
similarity index 78%
copy from 
commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderTestCase.java
copy to 
commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/AbstractSftpProviderTestCase.java
index 35aec44..51a30af 100644
--- 
a/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderTestCase.java
+++ 
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/AbstractSftpProviderTestCase.java
@@ -24,7 +24,6 @@ import java.io.OutputStream;
 import java.io.PrintStream;
 import java.net.InetSocketAddress;
 import java.net.Socket;
-import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.TreeMap;
@@ -39,12 +38,8 @@ import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
 import org.apache.commons.vfs2.provider.sftp.SftpFileProvider;
 import org.apache.commons.vfs2.provider.sftp.SftpFileSystem;
 import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
-import org.apache.commons.vfs2.provider.sftp.SftpStreamProxy;
 import org.apache.commons.vfs2.provider.sftp.TrustEveryoneUserInfo;
 import org.apache.commons.vfs2.test.AbstractProviderTestConfig;
-import org.apache.commons.vfs2.test.PermissionsTests;
-import org.apache.commons.vfs2.test.ProviderReadTests;
-import org.apache.commons.vfs2.test.ProviderTestConfig;
 import org.apache.commons.vfs2.test.ProviderTestSuite;
 import org.apache.commons.vfs2.util.FreeSocketPortUtil;
 import org.apache.ftpserver.ftplet.FtpException;
@@ -73,22 +68,18 @@ import org.apache.sshd.server.sftp.SftpSubsystem;
 import com.jcraft.jsch.SftpATTRS;
 import com.jcraft.jsch.TestIdentityRepositoryFactory;
 
-import junit.extensions.TestSetup;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
 /**
  * Tests cases for the SFTP provider.
  * <p>
  * Starts and stops an embedded Apache SSHd (MINA) server.
  * </p>
  */
-public class SftpProviderTestCase extends AbstractProviderTestConfig {
+abstract class AbstractSftpProviderTestCase extends AbstractProviderTestConfig 
{
 
     /**
      * The underlying file system
      */
-    private SftpFileSystem fileSystem;
+    protected SftpFileSystem fileSystem;
 
     /**
      * Implements FileSystemFactory because SSHd does not know about users and 
home directories.
@@ -165,16 +156,16 @@ public class SftpProviderTestCase extends 
AbstractProviderTestConfig {
 
     // private static final String DEFAULT_PWD = "testtest";
 
-    private static String ConnectionUri;
+    protected static String ConnectionUri;
 
     private static SshServer Server;
 
     private static final String TEST_URI = "test.sftp.uri";
 
-    /** True if we are testing the SFTP stream proxy */
-    private final boolean streamProxyMode;
-
-    private static String getSystemTestUriOverride() {
+    /**
+     * True if we are testing the SFTP stream proxy
+     */
+    protected static String getSystemTestUriOverride() {
         return System.getProperty(TEST_URI);
     }
 
@@ -184,14 +175,13 @@ public class SftpProviderTestCase extends 
AbstractProviderTestConfig {
      * @throws FtpException
      * @throws IOException
      */
-    private static void setUpClass() throws FtpException, IOException {
-        SocketPort = FreeSocketPortUtil.findFreeLocalPort();
-        // Use %40 for @ in a URL
-        ConnectionUri = String.format("sftp://%s@localhost:%d";, DEFAULT_USER, 
SocketPort);
-
+    private static void setUpClass(final boolean isExecChannelClosed) throws 
IOException {
         if (Server != null) {
             return;
         }
+        SocketPort = FreeSocketPortUtil.findFreeLocalPort();
+        // Use %40 for @ in a URL
+        ConnectionUri = String.format("sftp://%s@localhost:%d";, DEFAULT_USER, 
SocketPort);
         // System.setProperty("vfs.sftp.sshdir", getTestDirectory() + 
"/../vfs.sftp.sshdir");
         final String tmpDir = System.getProperty("java.io.tmpdir");
         Server = SshServer.setUpDefaultServer();
@@ -246,7 +236,7 @@ public class SftpProviderTestCase extends 
AbstractProviderTestConfig {
             }
         });
         // Allows the execution of commands
-        Server.setCommandFactory(new ScpCommandFactory(new 
TestCommandFactory()));
+        Server.setCommandFactory(new ScpCommandFactory(new 
TestCommandFactory(isExecChannelClosed)));
         // HACK Start
         // How do we really do simple user to directory matching?
         Server.setFileSystemFactory(new TestFileSystemFactory());
@@ -259,10 +249,20 @@ public class SftpProviderTestCase extends 
AbstractProviderTestConfig {
         // HACK End
     }
 
-    static private class BaseProviderTestSuite extends ProviderTestSuite {
+    static class SftpProviderTestSuite extends ProviderTestSuite {
+        private final boolean isExecChannelClosed;
 
-        public BaseProviderTestSuite(final ProviderTestConfig providerConfig) 
throws Exception {
+        public SftpProviderTestSuite(final AbstractSftpProviderTestCase 
providerConfig) throws Exception {
             super(providerConfig);
+            this.isExecChannelClosed = providerConfig.isExecChannelClosed();
+        }
+
+        @Override
+        protected void setUp() throws Exception {
+            if (getSystemTestUriOverride() == null) {
+                setUpClass(isExecChannelClosed);
+            }
+            super.setUp();
         }
 
         @Override
@@ -273,61 +273,13 @@ public class SftpProviderTestCase extends 
AbstractProviderTestConfig {
             for (final AbstractSession session : Server.getActiveSessions()) {
                 session.close(true);
             }
+            tearDownClass();
             super.tearDown();
         }
 
     }
 
-    /**
-     * Creates the test suite for the ftp file system.
-     */
-    public static Test suite() throws Exception {
-        // The test suite to be returned
-        final TestSuite suite = new TestSuite();
-
-        // --- Standard VFS test suite
-        final SftpProviderTestCase standardTestCase = new 
SftpProviderTestCase(false);
-        final ProviderTestSuite sftpSuite = new 
BaseProviderTestSuite(standardTestCase);
-
-        // VFS-405: set/get permissions
-        sftpSuite.addTests(PermissionsTests.class);
-
-        suite.addTest(sftpSuite);
-
-        // --- VFS-440: stream proxy test suite
-        // We override the addBaseTests method so that only
-        // one test is run (we just test that the input/output are correctly 
forwarded, and
-        // hence if the reading test succeeds/fails the other will also 
succeed/fail)
-        final SftpProviderTestCase streamProxyTestCase = new 
SftpProviderTestCase(true);
-        final ProviderTestSuite sftpStreamSuite = new 
BaseProviderTestSuite(streamProxyTestCase) {
-            @Override
-            protected void addBaseTests() throws Exception {
-                // Just tries to read
-                addTests(ProviderReadTests.class);
-            }
-        };
-        suite.addTest(sftpStreamSuite);
-
-        // Decorate the test suite to set up the Sftp server
-        final TestSetup setup = new TestSetup(suite) {
-            @Override
-            protected void setUp() throws Exception {
-                if (getSystemTestUriOverride() == null) {
-                    setUpClass();
-                }
-                super.setUp();
-            }
-
-            @Override
-            protected void tearDown() throws Exception {
-                // Close SFTP server if needed
-                tearDownClass();
-                super.tearDown();
-            }
-        };
-
-        return setup;
-    }
+    protected abstract boolean isExecChannelClosed();
 
     /**
      * Stops the embedded Apache SSHd Server (MINA).
@@ -337,13 +289,10 @@ public class SftpProviderTestCase extends 
AbstractProviderTestConfig {
     private static void tearDownClass() throws InterruptedException {
         if (Server != null) {
             Server.stop();
+            Server = null;
         }
     }
 
-    public SftpProviderTestCase(final boolean streamProxyMode) {
-        this.streamProxyMode = streamProxyMode;
-    }
-
     /**
      * Returns the base folder for tests.
      */
@@ -359,37 +308,6 @@ public class SftpProviderTestCase extends 
AbstractProviderTestConfig {
         builder.setStrictHostKeyChecking(fileSystemOptions, "no");
         builder.setUserInfo(fileSystemOptions, new TrustEveryoneUserInfo());
         builder.setIdentityRepositoryFactory(fileSystemOptions, new 
TestIdentityRepositoryFactory());
-
-        if (streamProxyMode) {
-            final FileSystemOptions proxyOptions = (FileSystemOptions) 
fileSystemOptions.clone();
-
-            final URI parsedURI = new URI(uri);
-            final String userInfo = parsedURI.getUserInfo();
-            final String[] userFields = userInfo == null ? null : 
userInfo.split(":", 2);
-
-            builder.setProxyType(fileSystemOptions, 
SftpFileSystemConfigBuilder.PROXY_STREAM);
-            if (userFields != null) {
-                if (userFields.length > 0) {
-                    builder.setProxyUser(fileSystemOptions, userFields[0]);
-                }
-                if (userFields.length > 1) {
-                    builder.setProxyPassword(fileSystemOptions, userFields[1]);
-                }
-            }
-            builder.setProxyHost(fileSystemOptions, parsedURI.getHost());
-            builder.setProxyPort(fileSystemOptions, parsedURI.getPort());
-            builder.setProxyCommand(fileSystemOptions, 
SftpStreamProxy.NETCAT_COMMAND);
-            builder.setProxyOptions(fileSystemOptions, proxyOptions);
-            builder.setProxyPassword(fileSystemOptions, 
parsedURI.getAuthority());
-
-            // Set up the new URI
-            if (userInfo == null) {
-                uri = String.format("sftp://localhost:%d";, 
parsedURI.getPort());
-            } else {
-                uri = String.format("sftp://%s@localhost:%d";, userInfo, 
parsedURI.getPort());
-            }
-        }
-
         final FileObject fileObject = manager.resolveFile(uri, 
fileSystemOptions);
         this.fileSystem = (SftpFileSystem) fileObject.getFileSystem();
         return fileObject;
@@ -406,14 +324,19 @@ public class SftpProviderTestCase extends 
AbstractProviderTestConfig {
     /**
      * The command factory for the SSH server: Handles these commands
      * <p>
-     * <li>{@code id -u} (permissions test)</li>
-     * <li>{@code id -G} (permission tests)</li>
-     * <li>{@code nc -q 0 localhost port} (Stream proxy tests)</li>
+     * <li><code>id -u</code> (permissions test)</li>
+     * <li><code>id -G</code> (permission tests)</li>
+     * <li><code>nc -q 0 localhost port</code> (Stream proxy tests)</li>
      * </p>
      */
     private static class TestCommandFactory extends ScpCommandFactory {
 
         public static final Pattern NETCAT_COMMAND = Pattern.compile("nc -q 0 
localhost (\\d+)");
+        private final boolean isExecChannelClosed;
+
+        public TestCommandFactory(final boolean isExecChannelClosed) {
+            this.isExecChannelClosed = isExecChannelClosed;
+        }
 
         @Override
         public Command createCommand(final String command) {
@@ -448,7 +371,11 @@ public class SftpProviderTestCase extends 
AbstractProviderTestConfig {
                 public void start(final Environment env) throws IOException {
                     int code = 0;
                     if (command.equals("id -G") || command.equals("id -u")) {
-                        new PrintStream(out).println(0);
+                        if (isExecChannelClosed) {
+                            throw new IOException();
+                        } else {
+                            new PrintStream(out).println(0);
+                        }
                     } else if (NETCAT_COMMAND.matcher(command).matches()) {
                         final Matcher matcher = 
NETCAT_COMMAND.matcher(command);
                         matcher.matches();
@@ -499,7 +426,7 @@ public class SftpProviderTestCase extends 
AbstractProviderTestConfig {
      *                 broken. The integer argument is 0 if everything went 
well.
      */
     private static void connect(final String name, final InputStream in, final 
OutputStream out,
-            final ExitCallback callback) {
+                                final ExitCallback callback) {
         final Thread thread = new Thread((Runnable) () -> {
             int code = 0;
             try {
@@ -571,30 +498,30 @@ public class SftpProviderTestCase extends 
AbstractProviderTestConfig {
             final int id = buffer.getInt();
 
             switch (type) {
-            case SSH_FXP_SETSTAT:
-            case SSH_FXP_FSETSTAT: {
-                // Get the path
-                final String path = buffer.getString();
-                // Get the permission
-                final SftpAttrs attrs = new SftpAttrs(buffer);
-                permissions.put(path, attrs.permissions);
-                // System.err.format("Setting [%s] permission to %o%n", path, 
attrs.permissions);
-                break;
-            }
+                case SSH_FXP_SETSTAT:
+                case SSH_FXP_FSETSTAT: {
+                    // Get the path
+                    final String path = buffer.getString();
+                    // Get the permission
+                    final SftpAttrs attrs = new SftpAttrs(buffer);
+                    permissions.put(path, attrs.permissions);
+                    // System.err.format("Setting [%s] permission to %o%n", 
path, attrs.permissions);
+                    break;
+                }
 
-            case SSH_FXP_REMOVE: {
-                // Remove cached attributes
-                final String path = buffer.getString();
-                permissions.remove(path);
-                // System.err.format("Removing [%s] permission cache%n", path);
-                break;
-            }
+                case SSH_FXP_REMOVE: {
+                    // Remove cached attributes
+                    final String path = buffer.getString();
+                    permissions.remove(path);
+                    // System.err.format("Removing [%s] permission cache%n", 
path);
+                    break;
+                }
 
-            case SSH_FXP_INIT: {
-                // Just grab the version here
-                this._version = id;
-                break;
-            }
+                case SSH_FXP_INIT: {
+                    // Just grab the version here
+                    this._version = id;
+                    break;
+                }
             }
 
             buffer.rpos(rpos);
diff --git 
a/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderClosedExecChannelTestCase.java
 
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderClosedExecChannelTestCase.java
new file mode 100644
index 0000000..b6e21f3
--- /dev/null
+++ 
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderClosedExecChannelTestCase.java
@@ -0,0 +1,47 @@
+/*
+ * 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.commons.vfs2.provider.sftp.test;
+
+import org.apache.commons.vfs2.test.*;
+
+import junit.framework.Test;
+
+public class SftpProviderClosedExecChannelTestCase extends 
AbstractSftpProviderTestCase {
+    @Override
+    protected boolean isExecChannelClosed() {
+        return true;
+    }
+
+    /**
+     * Creates the test suite for the sftp file system.
+     */
+    public static Test suite() throws Exception {
+        final SftpProviderTestSuite suite = new SftpProviderTestSuite(new 
SftpProviderClosedExecChannelTestCase()){
+        @Override
+        protected void addBaseTests() throws Exception {
+            addTests(ProviderReadTests.class);
+            addTests(ProviderWriteTests.class);
+            addTests(ProviderDeleteTests.class);
+            addTests(ProviderRenameTests.class);
+            addTests(NamingTests.class);
+            // VFS-405: set/get permissions
+            addTests(PermissionsTests.class);
+        }
+    };
+        return suite;
+    }
+}
diff --git 
a/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderStreamProxyModeTestCase.java
 
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderStreamProxyModeTestCase.java
new file mode 100644
index 0000000..db525e5
--- /dev/null
+++ 
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderStreamProxyModeTestCase.java
@@ -0,0 +1,104 @@
+/*
+ * 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.commons.vfs2.provider.sftp.test;
+
+import java.net.URI;
+
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.commons.vfs2.FileSystemOptions;
+import org.apache.commons.vfs2.provider.sftp.SftpFileSystem;
+import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
+import org.apache.commons.vfs2.provider.sftp.SftpStreamProxy;
+import org.apache.commons.vfs2.provider.sftp.TrustEveryoneUserInfo;
+import org.apache.commons.vfs2.test.PermissionsTests;
+import org.apache.commons.vfs2.test.ProviderReadTests;
+
+import com.jcraft.jsch.TestIdentityRepositoryFactory;
+
+import junit.framework.Test;
+
+public class SftpProviderStreamProxyModeTestCase extends 
AbstractSftpProviderTestCase {
+    @Override
+    protected boolean isExecChannelClosed() {
+        return false;
+    }
+
+    // --- VFS-440: stream proxy test suite
+    // We override the addBaseTests method so that only
+    // one test is run (we just test that the input/output are correctly 
forwarded, and
+    // hence if the reading test succeeds/fails the other will also 
succeed/fail)
+    public static Test suite() throws Exception {
+        final SftpProviderTestSuite suite = new SftpProviderTestSuite(new 
SftpProviderStreamProxyModeTestCase()) {
+            @Override
+            protected void addBaseTests() throws Exception {
+                // Just tries to read
+                addTests(ProviderReadTests.class);
+                // VFS-405: set/get permissions
+                addTests(PermissionsTests.class);
+            }
+        };
+        return suite;
+    }
+
+    @Override
+    public FileObject getBaseTestFolder(final FileSystemManager manager) 
throws Exception {
+        String uri = getSystemTestUriOverride();
+        if (uri == null) {
+            uri = ConnectionUri;
+        }
+
+        final FileSystemOptions fileSystemOptions = new FileSystemOptions();
+        final SftpFileSystemConfigBuilder builder = 
SftpFileSystemConfigBuilder.getInstance();
+        builder.setStrictHostKeyChecking(fileSystemOptions, "no");
+        builder.setUserInfo(fileSystemOptions, new TrustEveryoneUserInfo());
+        builder.setIdentityRepositoryFactory(fileSystemOptions, new 
TestIdentityRepositoryFactory());
+
+        final FileSystemOptions proxyOptions = (FileSystemOptions) 
fileSystemOptions.clone();
+
+        final URI parsedURI = new URI(uri);
+        final String userInfo = parsedURI.getUserInfo();
+        final String[] userFields = userInfo == null ? null : 
userInfo.split(":", 2);
+
+        builder.setProxyType(fileSystemOptions, 
SftpFileSystemConfigBuilder.PROXY_STREAM);
+        if (userFields != null) {
+            if (userFields.length > 0) {
+                builder.setProxyUser(fileSystemOptions, userFields[0]);
+            }
+            if (userFields.length > 1) {
+                builder.setProxyPassword(fileSystemOptions, userFields[1]);
+            }
+        }
+        builder.setProxyHost(fileSystemOptions, parsedURI.getHost());
+        builder.setProxyPort(fileSystemOptions, parsedURI.getPort());
+        builder.setProxyCommand(fileSystemOptions, 
SftpStreamProxy.NETCAT_COMMAND);
+        builder.setProxyOptions(fileSystemOptions, proxyOptions);
+        builder.setProxyPassword(fileSystemOptions, parsedURI.getAuthority());
+
+        // Set up the new URI
+        if (userInfo == null) {
+            uri = String.format("sftp://localhost:%d";, parsedURI.getPort());
+        } else {
+            uri = String.format("sftp://%s@localhost:%d";, userInfo, 
parsedURI.getPort());
+        }
+
+
+        final FileObject fileObject = manager.resolveFile(uri, 
fileSystemOptions);
+        this.fileSystem = (SftpFileSystem) fileObject.getFileSystem();
+        return fileObject;
+    }
+}
diff --git 
a/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderTestCase.java
 
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderTestCase.java
index 35aec44..e837066 100644
--- 
a/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderTestCase.java
+++ 
b/commons-vfs2/src/test/java/org/apache/commons/vfs2/provider/sftp/test/SftpProviderTestCase.java
@@ -16,658 +16,24 @@
  */
 package org.apache.commons.vfs2.provider.sftp.test;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.TreeMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.commons.AbstractVfsTestCase;
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemManager;
-import org.apache.commons.vfs2.FileSystemOptions;
-import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
-import org.apache.commons.vfs2.provider.sftp.SftpFileProvider;
-import org.apache.commons.vfs2.provider.sftp.SftpFileSystem;
-import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
-import org.apache.commons.vfs2.provider.sftp.SftpStreamProxy;
-import org.apache.commons.vfs2.provider.sftp.TrustEveryoneUserInfo;
-import org.apache.commons.vfs2.test.AbstractProviderTestConfig;
 import org.apache.commons.vfs2.test.PermissionsTests;
-import org.apache.commons.vfs2.test.ProviderReadTests;
-import org.apache.commons.vfs2.test.ProviderTestConfig;
-import org.apache.commons.vfs2.test.ProviderTestSuite;
-import org.apache.commons.vfs2.util.FreeSocketPortUtil;
-import org.apache.ftpserver.ftplet.FtpException;
-import org.apache.sshd.SshServer;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Session;
-import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.session.AbstractSession;
-import org.apache.sshd.common.util.Buffer;
-import org.apache.sshd.common.util.SecurityUtils;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.Environment;
-import org.apache.sshd.server.ExitCallback;
-import org.apache.sshd.server.FileSystemFactory;
-import org.apache.sshd.server.FileSystemView;
-import org.apache.sshd.server.ForwardingFilter;
-import org.apache.sshd.server.SshFile;
-import org.apache.sshd.server.auth.UserAuthNone;
-import org.apache.sshd.server.command.ScpCommandFactory;
-import org.apache.sshd.server.filesystem.NativeSshFile;
-import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider;
-import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
-import org.apache.sshd.server.session.ServerSession;
-import org.apache.sshd.server.sftp.SftpSubsystem;
-
-import com.jcraft.jsch.SftpATTRS;
-import com.jcraft.jsch.TestIdentityRepositoryFactory;
 
-import junit.extensions.TestSetup;
 import junit.framework.Test;
-import junit.framework.TestSuite;
-
-/**
- * Tests cases for the SFTP provider.
- * <p>
- * Starts and stops an embedded Apache SSHd (MINA) server.
- * </p>
- */
-public class SftpProviderTestCase extends AbstractProviderTestConfig {
-
-    /**
-     * The underlying file system
-     */
-    private SftpFileSystem fileSystem;
-
-    /**
-     * Implements FileSystemFactory because SSHd does not know about users and 
home directories.
-     */
-    static final class TestFileSystemFactory implements FileSystemFactory {
-        /**
-         * Accepts only the known test user.
-         */
-        @Override
-        public FileSystemView createFileSystemView(final Session session) 
throws IOException {
-            final String userName = session.getUsername();
-            if (!DEFAULT_USER.equals(userName)) {
-                return null;
-            }
-            return new 
TestFileSystemView(AbstractVfsTestCase.getTestDirectory(), userName);
-        }
-    }
-
-    /**
-     * Implements FileSystemView because SSHd does not know about users and 
home directories.
-     */
-    static final class TestFileSystemView implements FileSystemView {
-        private final String homeDirStr;
-
-        private final String userName;
-
-        // private boolean caseInsensitive;
-
-        public TestFileSystemView(final String homeDirStr, final String 
userName) {
-            this.homeDirStr = new File(homeDirStr).getAbsolutePath();
-            this.userName = userName;
-        }
-
-        @Override
-        public SshFile getFile(final SshFile baseDir, final String file) {
-            return this.getFile(baseDir.getAbsolutePath(), file);
-        }
-
-        @Override
-        public SshFile getFile(final String file) {
-            return this.getFile(homeDirStr, file);
-        }
-
-        protected SshFile getFile(final String dir, final String file) {
-            final String home = 
removePrefix(NativeSshFile.normalizeSeparateChar(homeDirStr));
-            String userFileName = 
removePrefix(NativeSshFile.normalizeSeparateChar(file));
-            final File sshFile = userFileName.startsWith(home) ? new 
File(userFileName) : new File(home, userFileName);
-            userFileName = 
removePrefix(NativeSshFile.normalizeSeparateChar(sshFile.getAbsolutePath()));
-            return new TestNativeSshFile(userFileName, sshFile, userName);
-        }
-
-        private String removePrefix(final String s) {
-            final int index = s.indexOf('/');
-            if (index < 1) {
-                return s;
-            }
-            return s.substring(index);
-        }
-    }
-
-    /**
-     * Extends NativeSshFile because its constructor is protected and I do not 
want to create a whole NativeSshFile
-     * implementation for testing.
-     */
-    static class TestNativeSshFile extends NativeSshFile {
-        TestNativeSshFile(final String fileName, final File file, final String 
userName) {
-            super(fileName, file, userName);
-        }
-    }
-
-    private static int SocketPort;
-
-    private static final String DEFAULT_USER = "testtest";
-
-    // private static final String DEFAULT_PWD = "testtest";
-
-    private static String ConnectionUri;
 
-    private static SshServer Server;
-
-    private static final String TEST_URI = "test.sftp.uri";
-
-    /** True if we are testing the SFTP stream proxy */
-    private final boolean streamProxyMode;
-
-    private static String getSystemTestUriOverride() {
-        return System.getProperty(TEST_URI);
-    }
-
-    /**
-     * Creates and starts an embedded Apache SSHd Server (MINA).
-     *
-     * @throws FtpException
-     * @throws IOException
-     */
-    private static void setUpClass() throws FtpException, IOException {
-        SocketPort = FreeSocketPortUtil.findFreeLocalPort();
-        // Use %40 for @ in a URL
-        ConnectionUri = String.format("sftp://%s@localhost:%d";, DEFAULT_USER, 
SocketPort);
-
-        if (Server != null) {
-            return;
-        }
-        // System.setProperty("vfs.sftp.sshdir", getTestDirectory() + 
"/../vfs.sftp.sshdir");
-        final String tmpDir = System.getProperty("java.io.tmpdir");
-        Server = SshServer.setUpDefaultServer();
-        Server.setPort(SocketPort);
-        if (SecurityUtils.isBouncyCastleRegistered()) {
-            // A temporary file will hold the key
-            final File keyFile = File.createTempFile("key", ".pem", new 
File(tmpDir));
-            keyFile.deleteOnExit();
-            // It has to be deleted in order to be generated
-            keyFile.delete();
-
-            final PEMGeneratorHostKeyProvider keyProvider = new 
PEMGeneratorHostKeyProvider(keyFile.getAbsolutePath());
-            Server.setKeyPairProvider(keyProvider);
-        } else {
-            Server.setKeyPairProvider(new 
SimpleGeneratorHostKeyProvider(tmpDir + "/key.ser"));
-        }
-        final List<NamedFactory<Command>> list = new ArrayList<>(1);
-        list.add(new NamedFactory<Command>() {
-
-            @Override
-            public String getName() {
-                return "sftp";
-            }
-
-            @Override
-            public Command create() {
-                return new MySftpSubsystem();
-            }
-        });
-        Server.setSubsystemFactories(list);
-        Server.setPasswordAuthenticator((username, password, session) -> 
username != null && username.equals(password));
-        Server.setPublickeyAuthenticator((username, key, session) -> true);
-        Server.setForwardingFilter(new ForwardingFilter() {
-            @Override
-            public boolean canConnect(final InetSocketAddress address, final 
ServerSession session) {
-                return true;
-            }
-
-            @Override
-            public boolean canForwardAgent(final ServerSession session) {
-                return true;
-            }
-
-            @Override
-            public boolean canForwardX11(final ServerSession session) {
-                return true;
-            }
-
-            @Override
-            public boolean canListen(final InetSocketAddress address, final 
ServerSession session) {
-                return true;
-            }
-        });
-        // Allows the execution of commands
-        Server.setCommandFactory(new ScpCommandFactory(new 
TestCommandFactory()));
-        // HACK Start
-        // How do we really do simple user to directory matching?
-        Server.setFileSystemFactory(new TestFileSystemFactory());
-        // HACK End
-        Server.start();
-        // HACK Start
-        // How do we really do simple security?
-        // Do this after we start the server to simplify this set up code.
-        Server.getUserAuthFactories().add(new UserAuthNone.Factory());
-        // HACK End
-    }
-
-    static private class BaseProviderTestSuite extends ProviderTestSuite {
-
-        public BaseProviderTestSuite(final ProviderTestConfig providerConfig) 
throws Exception {
-            super(providerConfig);
-        }
-
-        @Override
-        protected void tearDown() throws Exception {
-            // Close all active sessions
-            // Note that it should be done by super.tearDown()
-            // while closing
-            for (final AbstractSession session : Server.getActiveSessions()) {
-                session.close(true);
-            }
-            super.tearDown();
-        }
+public class SftpProviderTestCase extends AbstractSftpProviderTestCase {
 
+    @Override
+    protected boolean isExecChannelClosed() {
+        return false;
     }
 
     /**
-     * Creates the test suite for the ftp file system.
+     * Creates the test suite for the sftp file system.
      */
     public static Test suite() throws Exception {
-        // The test suite to be returned
-        final TestSuite suite = new TestSuite();
-
-        // --- Standard VFS test suite
-        final SftpProviderTestCase standardTestCase = new 
SftpProviderTestCase(false);
-        final ProviderTestSuite sftpSuite = new 
BaseProviderTestSuite(standardTestCase);
-
+        final SftpProviderTestSuite suite = new SftpProviderTestSuite(new 
SftpProviderTestCase());
         // VFS-405: set/get permissions
-        sftpSuite.addTests(PermissionsTests.class);
-
-        suite.addTest(sftpSuite);
-
-        // --- VFS-440: stream proxy test suite
-        // We override the addBaseTests method so that only
-        // one test is run (we just test that the input/output are correctly 
forwarded, and
-        // hence if the reading test succeeds/fails the other will also 
succeed/fail)
-        final SftpProviderTestCase streamProxyTestCase = new 
SftpProviderTestCase(true);
-        final ProviderTestSuite sftpStreamSuite = new 
BaseProviderTestSuite(streamProxyTestCase) {
-            @Override
-            protected void addBaseTests() throws Exception {
-                // Just tries to read
-                addTests(ProviderReadTests.class);
-            }
-        };
-        suite.addTest(sftpStreamSuite);
-
-        // Decorate the test suite to set up the Sftp server
-        final TestSetup setup = new TestSetup(suite) {
-            @Override
-            protected void setUp() throws Exception {
-                if (getSystemTestUriOverride() == null) {
-                    setUpClass();
-                }
-                super.setUp();
-            }
-
-            @Override
-            protected void tearDown() throws Exception {
-                // Close SFTP server if needed
-                tearDownClass();
-                super.tearDown();
-            }
-        };
-
-        return setup;
-    }
-
-    /**
-     * Stops the embedded Apache SSHd Server (MINA).
-     *
-     * @throws InterruptedException
-     */
-    private static void tearDownClass() throws InterruptedException {
-        if (Server != null) {
-            Server.stop();
-        }
-    }
-
-    public SftpProviderTestCase(final boolean streamProxyMode) {
-        this.streamProxyMode = streamProxyMode;
-    }
-
-    /**
-     * Returns the base folder for tests.
-     */
-    @Override
-    public FileObject getBaseTestFolder(final FileSystemManager manager) 
throws Exception {
-        String uri = getSystemTestUriOverride();
-        if (uri == null) {
-            uri = ConnectionUri;
-        }
-
-        final FileSystemOptions fileSystemOptions = new FileSystemOptions();
-        final SftpFileSystemConfigBuilder builder = 
SftpFileSystemConfigBuilder.getInstance();
-        builder.setStrictHostKeyChecking(fileSystemOptions, "no");
-        builder.setUserInfo(fileSystemOptions, new TrustEveryoneUserInfo());
-        builder.setIdentityRepositoryFactory(fileSystemOptions, new 
TestIdentityRepositoryFactory());
-
-        if (streamProxyMode) {
-            final FileSystemOptions proxyOptions = (FileSystemOptions) 
fileSystemOptions.clone();
-
-            final URI parsedURI = new URI(uri);
-            final String userInfo = parsedURI.getUserInfo();
-            final String[] userFields = userInfo == null ? null : 
userInfo.split(":", 2);
-
-            builder.setProxyType(fileSystemOptions, 
SftpFileSystemConfigBuilder.PROXY_STREAM);
-            if (userFields != null) {
-                if (userFields.length > 0) {
-                    builder.setProxyUser(fileSystemOptions, userFields[0]);
-                }
-                if (userFields.length > 1) {
-                    builder.setProxyPassword(fileSystemOptions, userFields[1]);
-                }
-            }
-            builder.setProxyHost(fileSystemOptions, parsedURI.getHost());
-            builder.setProxyPort(fileSystemOptions, parsedURI.getPort());
-            builder.setProxyCommand(fileSystemOptions, 
SftpStreamProxy.NETCAT_COMMAND);
-            builder.setProxyOptions(fileSystemOptions, proxyOptions);
-            builder.setProxyPassword(fileSystemOptions, 
parsedURI.getAuthority());
-
-            // Set up the new URI
-            if (userInfo == null) {
-                uri = String.format("sftp://localhost:%d";, 
parsedURI.getPort());
-            } else {
-                uri = String.format("sftp://%s@localhost:%d";, userInfo, 
parsedURI.getPort());
-            }
-        }
-
-        final FileObject fileObject = manager.resolveFile(uri, 
fileSystemOptions);
-        this.fileSystem = (SftpFileSystem) fileObject.getFileSystem();
-        return fileObject;
-    }
-
-    /**
-     * Prepares the file system manager.
-     */
-    @Override
-    public void prepare(final DefaultFileSystemManager manager) throws 
Exception {
-        manager.addProvider("sftp", new SftpFileProvider());
-    }
-
-    /**
-     * The command factory for the SSH server: Handles these commands
-     * <p>
-     * <li>{@code id -u} (permissions test)</li>
-     * <li>{@code id -G} (permission tests)</li>
-     * <li>{@code nc -q 0 localhost port} (Stream proxy tests)</li>
-     * </p>
-     */
-    private static class TestCommandFactory extends ScpCommandFactory {
-
-        public static final Pattern NETCAT_COMMAND = Pattern.compile("nc -q 0 
localhost (\\d+)");
-
-        @Override
-        public Command createCommand(final String command) {
-            return new Command() {
-                public ExitCallback callback = null;
-                public OutputStream out = null;
-                public OutputStream err = null;
-                public InputStream in = null;
-
-                @Override
-                public void setInputStream(final InputStream in) {
-                    this.in = in;
-                }
-
-                @Override
-                public void setOutputStream(final OutputStream out) {
-                    this.out = out;
-                }
-
-                @Override
-                public void setErrorStream(final OutputStream err) {
-                    this.err = err;
-                }
-
-                @Override
-                public void setExitCallback(final ExitCallback callback) {
-                    this.callback = callback;
-
-                }
-
-                @Override
-                public void start(final Environment env) throws IOException {
-                    int code = 0;
-                    if (command.equals("id -G") || command.equals("id -u")) {
-                        new PrintStream(out).println(0);
-                    } else if (NETCAT_COMMAND.matcher(command).matches()) {
-                        final Matcher matcher = 
NETCAT_COMMAND.matcher(command);
-                        matcher.matches();
-                        final int port = Integer.parseInt(matcher.group(1));
-
-                        final Socket socket = new Socket((String) null, port);
-
-                        if (out != null) {
-                            connect("from nc", socket.getInputStream(), out, 
null);
-                        }
-
-                        if (in != null) {
-                            connect("to nc", in, socket.getOutputStream(), 
callback);
-                        }
-
-                        return;
-
-                    } else {
-                        if (err != null) {
-                            new PrintStream(err).format("Unknown command 
%s%n", command);
-                        }
-                        code = -1;
-                    }
-
-                    if (out != null) {
-                        out.flush();
-                    }
-                    if (err != null) {
-                        err.flush();
-                    }
-                    callback.onExit(code);
-                }
-
-                @Override
-                public void destroy() {
-                }
-            };
-        }
-    }
-
-    /**
-     * Creates a pipe thread that connects an input to an output
-     *
-     * @param name     The name of the thread (for debugging purposes)
-     * @param in       The input stream
-     * @param out      The output stream
-     * @param callback An object whose method {@linkplain 
ExitCallback#onExit(int)} will be called when the pipe is
-     *                 broken. The integer argument is 0 if everything went 
well.
-     */
-    private static void connect(final String name, final InputStream in, final 
OutputStream out,
-            final ExitCallback callback) {
-        final Thread thread = new Thread((Runnable) () -> {
-            int code = 0;
-            try {
-                final byte buffer[] = new byte[1024];
-                int len;
-                while ((len = in.read(buffer, 0, buffer.length)) != -1) {
-                    out.write(buffer, 0, len);
-                    out.flush();
-                }
-            } catch (final SshException ex1) {
-                // Nothing to do, this occurs when the connection
-                // is closed on the remote side
-            } catch (final IOException ex2) {
-                if (!ex2.getMessage().equals("Pipe closed")) {
-                    code = -1;
-                }
-            }
-            if (callback != null) {
-                callback.onExit(code);
-            }
-        }, name);
-        thread.setDaemon(true);
-        thread.start();
-    }
-
-    private static class SftpAttrs {
-        int flags = 0;
-        private int uid;
-        long size = 0;
-        private int gid;
-        private int atime;
-        private int permissions;
-        private int mtime;
-        private String[] extended;
-
-        private SftpAttrs(final Buffer buf) {
-            int flags = 0;
-            flags = buf.getInt();
-
-            if ((flags & SftpATTRS.SSH_FILEXFER_ATTR_SIZE) != 0) {
-                size = buf.getLong();
-            }
-            if ((flags & SftpATTRS.SSH_FILEXFER_ATTR_UIDGID) != 0) {
-                uid = buf.getInt();
-                gid = buf.getInt();
-            }
-            if ((flags & SftpATTRS.SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {
-                permissions = buf.getInt();
-            }
-            if ((flags & SftpATTRS.SSH_FILEXFER_ATTR_ACMODTIME) != 0) {
-                atime = buf.getInt();
-            }
-            if ((flags & SftpATTRS.SSH_FILEXFER_ATTR_ACMODTIME) != 0) {
-                mtime = buf.getInt();
-            }
-
-        }
-    }
-
-    private static class MySftpSubsystem extends SftpSubsystem {
-        TreeMap<String, Integer> permissions = new TreeMap<>();
-        private int _version;
-
-        @Override
-        protected void process(final Buffer buffer) throws IOException {
-            final int rpos = buffer.rpos();
-            final int length = buffer.getInt();
-            final int type = buffer.getByte();
-            final int id = buffer.getInt();
-
-            switch (type) {
-            case SSH_FXP_SETSTAT:
-            case SSH_FXP_FSETSTAT: {
-                // Get the path
-                final String path = buffer.getString();
-                // Get the permission
-                final SftpAttrs attrs = new SftpAttrs(buffer);
-                permissions.put(path, attrs.permissions);
-                // System.err.format("Setting [%s] permission to %o%n", path, 
attrs.permissions);
-                break;
-            }
-
-            case SSH_FXP_REMOVE: {
-                // Remove cached attributes
-                final String path = buffer.getString();
-                permissions.remove(path);
-                // System.err.format("Removing [%s] permission cache%n", path);
-                break;
-            }
-
-            case SSH_FXP_INIT: {
-                // Just grab the version here
-                this._version = id;
-                break;
-            }
-            }
-
-            buffer.rpos(rpos);
-            super.process(buffer);
-
-        }
-
-        @Override
-        protected void writeAttrs(final Buffer buffer, final SshFile file, 
final int flags) throws IOException {
-            if (!file.doesExist()) {
-                throw new FileNotFoundException(file.getAbsolutePath());
-            }
-
-            int p = 0;
-
-            final Integer cached = permissions.get(file.getAbsolutePath());
-            if (cached != null) {
-                // Use cached permissions
-                // System.err.format("Using cached [%s] permission of %o%n", 
file.getAbsolutePath(), cached);
-                p |= cached;
-            } else {
-                // Use permissions from Java file
-                if (file.isReadable()) {
-                    p |= S_IRUSR;
-                }
-                if (file.isWritable()) {
-                    p |= S_IWUSR;
-                }
-                if (file.isExecutable()) {
-                    p |= S_IXUSR;
-                }
-            }
-
-            if (_version >= 4) {
-                final long size = file.getSize();
-                // String username = session.getUsername();
-                final long lastModif = file.getLastModified();
-                if (file.isFile()) {
-                    buffer.putInt(SSH_FILEXFER_ATTR_PERMISSIONS);
-                    buffer.putByte((byte) SSH_FILEXFER_TYPE_REGULAR);
-                    buffer.putInt(p);
-                } else if (file.isDirectory()) {
-                    buffer.putInt(SSH_FILEXFER_ATTR_PERMISSIONS);
-                    buffer.putByte((byte) SSH_FILEXFER_TYPE_DIRECTORY);
-                    buffer.putInt(p);
-                } else {
-                    buffer.putInt(0);
-                    buffer.putByte((byte) SSH_FILEXFER_TYPE_UNKNOWN);
-                }
-            } else {
-                if (file.isFile()) {
-                    p |= 0100000;
-                }
-                if (file.isDirectory()) {
-                    p |= 0040000;
-                }
-
-                if (file.isFile()) {
-                    buffer.putInt(SSH_FILEXFER_ATTR_SIZE | 
SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
-                    buffer.putLong(file.getSize());
-                    buffer.putInt(p);
-                    buffer.putInt(file.getLastModified() / 1000);
-                    buffer.putInt(file.getLastModified() / 1000);
-                } else if (file.isDirectory()) {
-                    buffer.putInt(SSH_FILEXFER_ATTR_PERMISSIONS | 
SSH_FILEXFER_ATTR_ACMODTIME);
-                    buffer.putInt(p);
-                    buffer.putInt(file.getLastModified() / 1000);
-                    buffer.putInt(file.getLastModified() / 1000);
-                } else {
-                    buffer.putInt(0);
-                }
-            }
-        }
-
+        suite.addTests(PermissionsTests.class);
+        return suite;
     }
 }

Reply via email to