http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/test/java/org/apache/sshd/common/subsystem/sftp/SftpConstantsTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/common/subsystem/sftp/SftpConstantsTest.java b/sshd-core/src/test/java/org/apache/sshd/common/subsystem/sftp/SftpConstantsTest.java deleted file mode 100644 index d059d36..0000000 --- a/sshd-core/src/test/java/org/apache/sshd/common/subsystem/sftp/SftpConstantsTest.java +++ /dev/null @@ -1,75 +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.common.subsystem.sftp; - -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.util.test.BaseTestSupport; -import org.apache.sshd.util.test.NoIoTestCase; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runners.MethodSorters; - -/** - * @author <a href="mailto:d...@mina.apache.org">Apache MINA SSHD Project</a> - */ -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Category({ NoIoTestCase.class }) -public class SftpConstantsTest extends BaseTestSupport { - public SftpConstantsTest() { - super(); - } - - @Test - public void testRenameModesNotMarkedAsOpcodes() { - for (int cmd : new int[]{ - SftpConstants.SSH_FXP_RENAME_OVERWRITE, - SftpConstants.SSH_FXP_RENAME_ATOMIC, - SftpConstants.SSH_FXP_RENAME_NATIVE - }) { - String name = SftpConstants.getCommandMessageName(cmd); - assertFalse("Mismatched name for " + cmd + ": " + name, name.startsWith("SSH_FXP_RENAME_")); - } - } - - @Test - public void testRealPathModesNotMarkedAsOpcodes() { - for (int cmd = SftpConstants.SSH_FXP_REALPATH_NO_CHECK; cmd <= SftpConstants.SSH_FXP_REALPATH_STAT_IF; cmd++) { - String name = SftpConstants.getCommandMessageName(cmd); - assertFalse("Mismatched name for " + cmd + ": " + name, name.startsWith("SSH_FXP_REALPATH_")); - } - } - - @Test - public void testSubstatusNameResolution() { - for (int status = SftpConstants.SSH_FX_OK; status <= SftpConstants.SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK; status++) { - String name = SftpConstants.getStatusName(status); - assertTrue("Failed to convert status=" + status + ": " + name, name.startsWith("SSH_FX_")); - } - } - - @Test - public void testSubstatusMessageResolution() { - for (int status = SftpConstants.SSH_FX_OK; status <= SftpConstants.SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK; status++) { - String message = SftpHelper.resolveStatusMessage(status); - assertTrue("Missing message for status=" + status, GenericUtils.isNotEmpty(message)); - } - } -}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/test/java/org/apache/sshd/common/subsystem/sftp/SftpUniversalOwnerAndGroupTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/common/subsystem/sftp/SftpUniversalOwnerAndGroupTest.java b/sshd-core/src/test/java/org/apache/sshd/common/subsystem/sftp/SftpUniversalOwnerAndGroupTest.java deleted file mode 100644 index 704aa05..0000000 --- a/sshd-core/src/test/java/org/apache/sshd/common/subsystem/sftp/SftpUniversalOwnerAndGroupTest.java +++ /dev/null @@ -1,70 +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.common.subsystem.sftp; - -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.util.test.BaseTestSupport; -import org.apache.sshd.util.test.NoIoTestCase; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runners.MethodSorters; - -/** - * @author <a href="mailto:d...@mina.apache.org">Apache MINA SSHD Project</a> - */ -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Category({ NoIoTestCase.class }) -public class SftpUniversalOwnerAndGroupTest extends BaseTestSupport { - public SftpUniversalOwnerAndGroupTest() { - super(); - } - - @Test - public void testNameFormat() { - for (SftpUniversalOwnerAndGroup value : SftpUniversalOwnerAndGroup.VALUES) { - String name = value.getName(); - assertFalse(value.name() + ": empty name", GenericUtils.isEmpty(name)); - assertTrue(value.name() + ": bad suffix", name.charAt(name.length() - 1) == '@'); - - for (int index = 0; index < name.length() - 1; index++) { - char ch = name.charAt(index); - if ((ch < 'A') || (ch > 'Z')) { - fail("Non-uppercase character in " + name); - } - } - } - } - - @Test - public void testFromName() { - for (String name : new String[]{null, "", getCurrentTestName()}) { - assertNull("Unexpected value for '" + name + "'", SftpUniversalOwnerAndGroup.fromName(name)); - } - - for (SftpUniversalOwnerAndGroup expected : SftpUniversalOwnerAndGroup.VALUES) { - String name = expected.getName(); - for (int index = 0; index < name.length(); index++) { - assertSame(name, expected, SftpUniversalOwnerAndGroup.fromName(name)); - name = shuffleCase(name); - } - } - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java index 2f07cab..8c083a3 100644 --- a/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java +++ b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java @@ -55,7 +55,6 @@ import org.apache.sshd.common.PropertyResolverUtils; import org.apache.sshd.common.auth.UserAuthMethodFactory; import org.apache.sshd.common.channel.Channel; import org.apache.sshd.common.channel.ChannelListener; -import org.apache.sshd.common.channel.TestChannelListener; import org.apache.sshd.common.channel.Window; import org.apache.sshd.common.channel.WindowClosedException; import org.apache.sshd.common.io.IoSession; @@ -78,6 +77,7 @@ import org.apache.sshd.server.session.ServerSessionImpl; import org.apache.sshd.util.test.BaseTestSupport; import org.apache.sshd.util.test.EchoShell; import org.apache.sshd.util.test.EchoShellFactory; +import org.apache.sshd.util.test.TestChannelListener; import org.junit.After; import org.junit.Before; import org.junit.FixMethodOrder; http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystemFactoryTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystemFactoryTest.java b/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystemFactoryTest.java deleted file mode 100644 index 6420411..0000000 --- a/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystemFactoryTest.java +++ /dev/null @@ -1,101 +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.server.subsystem.sftp; - -import java.util.concurrent.ExecutorService; - -import org.apache.sshd.util.test.BaseTestSupport; -import org.apache.sshd.util.test.NoIoTestCase; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runners.MethodSorters; -import org.mockito.Mockito; - -/** - * @author <a href="mailto:d...@mina.apache.org">Apache MINA SSHD Project</a> - */ -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Category({ NoIoTestCase.class }) -public class SftpSubsystemFactoryTest extends BaseTestSupport { - public SftpSubsystemFactoryTest() { - super(); - } - - /** - * Make sure that the builder returns a factory with the default values - * if no {@code withXXX} method is invoked - */ - @Test - public void testBuilderDefaultFactoryValues() { - SftpSubsystemFactory factory = new SftpSubsystemFactory.Builder().build(); - assertNull("Mismatched executor", factory.getExecutorService()); - assertFalse("Mismatched shutdown state", factory.isShutdownOnExit()); - assertSame("Mismatched unsupported attribute policy", SftpSubsystemFactory.DEFAULT_POLICY, factory.getUnsupportedAttributePolicy()); - } - - /** - * Make sure that the builder initializes correctly the built factory - */ - @Test - public void testBuilderCorrectlyInitializesFactory() { - SftpSubsystemFactory.Builder builder = new SftpSubsystemFactory.Builder(); - ExecutorService service = dummyExecutor(); - SftpSubsystemFactory factory = builder.withExecutorService(service) - .withShutdownOnExit(true) - .build(); - assertSame("Mismatched executor", service, factory.getExecutorService()); - assertTrue("Mismatched shutdown state", factory.isShutdownOnExit()); - - for (UnsupportedAttributePolicy policy : UnsupportedAttributePolicy.VALUES) { - SftpSubsystemFactory actual = builder.withUnsupportedAttributePolicy(policy).build(); - assertSame("Mismatched unsupported attribute policy", policy, actual.getUnsupportedAttributePolicy()); - } - } - - /** - * <UL> - * <LI> - * Make sure the builder returns new instances on every call to - * {@link SftpSubsystemFactory.Builder#build()} method - * </LI> - * - * <LI> - * Make sure values are preserved between successive invocations - * of the {@link SftpSubsystemFactory.Builder#build()} method - * </LI> - * </UL - */ - @Test - public void testBuilderUniqueInstance() { - SftpSubsystemFactory.Builder builder = new SftpSubsystemFactory.Builder(); - SftpSubsystemFactory f1 = builder.withExecutorService(dummyExecutor()).build(); - SftpSubsystemFactory f2 = builder.build(); - assertNotSame("No new instance built", f1, f2); - assertSame("Mismatched executors", f1.getExecutorService(), f2.getExecutorService()); - - SftpSubsystemFactory f3 = builder.withExecutorService(dummyExecutor()).build(); - assertNotSame("Executor service not changed", f1.getExecutorService(), f3.getExecutorService()); - } - - private static ExecutorService dummyExecutor() { - return Mockito.mock(ExecutorService.class); - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SshFsMounter.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SshFsMounter.java b/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SshFsMounter.java deleted file mode 100644 index e6b10e0..0000000 --- a/sshd-core/src/test/java/org/apache/sshd/server/subsystem/sftp/SshFsMounter.java +++ /dev/null @@ -1,327 +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.server.subsystem.sftp; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.TreeMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; - -import org.apache.sshd.common.PropertyResolver; -import org.apache.sshd.common.PropertyResolverUtils; -import org.apache.sshd.common.config.SshConfigFileReader; -import org.apache.sshd.common.io.BuiltinIoServiceFactoryFactories; -import org.apache.sshd.common.io.IoServiceFactory; -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.ValidateUtils; -import org.apache.sshd.common.util.logging.AbstractLoggingBean; -import org.apache.sshd.common.util.security.SecurityUtils; -import org.apache.sshd.common.util.threads.ThreadUtils; -import org.apache.sshd.server.Command; -import org.apache.sshd.server.CommandFactory; -import org.apache.sshd.server.Environment; -import org.apache.sshd.server.ExitCallback; -import org.apache.sshd.server.SessionAware; -import org.apache.sshd.server.SshServer; -import org.apache.sshd.server.auth.password.AcceptAllPasswordAuthenticator; -import org.apache.sshd.server.forward.AcceptAllForwardingFilter; -import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; -import org.apache.sshd.server.scp.ScpCommandFactory; -import org.apache.sshd.server.session.ServerSession; -import org.apache.sshd.server.shell.InteractiveProcessShellFactory; -import org.apache.sshd.util.test.Utils; - -/** - * A basic implementation to allow remote mounting of the local file system via SFTP - * - * @author <a href="mailto:d...@mina.apache.org">Apache MINA SSHD Project</a> - */ -public final class SshFsMounter { - public static class MounterCommand extends AbstractLoggingBean implements Command, SessionAware, Runnable { - private final String command; - private final String cmdName; - private final List<String> args; - private String username; - private InputStream stdin; - private PrintStream stdout; - private PrintStream stderr; - private ExitCallback callback; - private ExecutorService executor; - private Future<?> future; - - public MounterCommand(String command) { - this.command = ValidateUtils.checkNotNullAndNotEmpty(command, "No command"); - - String[] comps = GenericUtils.split(this.command, ' '); - int numComps = GenericUtils.length(comps); - cmdName = GenericUtils.trimToEmpty(ValidateUtils.checkNotNullAndNotEmpty(comps[0], "No command name")); - if (numComps > 1) { - args = new ArrayList<>(numComps - 1); - for (int index = 1; index < numComps; index++) { - String c = GenericUtils.trimToEmpty(comps[index]); - if (GenericUtils.isEmpty(c)) { - continue; - } - - args.add(c); - } - } else { - args = Collections.emptyList(); - } - - log.info("<init>(" + command + ")"); - } - - @Override - public void run() { - try { - log.info("run(" + username + ")[" + command + "] start"); - if ("id".equals(cmdName)) { - int numArgs = GenericUtils.size(args); - if (numArgs <= 0) { - stdout.println("uid=0(root) gid=0(root) groups=0(root)"); - } else if (numArgs == 1) { - String modifier = args.get(0); - if ("-u".equals(modifier) || "-G".equals(modifier)) { - stdout.println("0"); - } else { - throw new IllegalArgumentException("Unknown modifier: " + modifier); - } - } else { - throw new IllegalArgumentException("Unexpected extra command arguments"); - } - } else { - throw new UnsupportedOperationException("Unknown command"); - } - - log.info("run(" + username + ")[" + command + "] end"); - callback.onExit(0); - } catch (Exception e) { - log.error("run(" + username + ")[" + command + "] " + e.getClass().getSimpleName() + ": " + e.getMessage(), e); - stderr.append(e.getClass().getSimpleName()).append(": ").println(e.getMessage()); - callback.onExit(-1, e.toString()); - } - } - - @Override - public void setSession(ServerSession session) { - username = session.getUsername(); - } - - @Override - public void setInputStream(InputStream in) { - this.stdin = in; - } - - @Override - public void setOutputStream(OutputStream out) { - this.stdout = new PrintStream(out, true); - } - - @Override - public void setErrorStream(OutputStream err) { - this.stderr = new PrintStream(err, true); - } - - @Override - public void setExitCallback(ExitCallback callback) { - this.callback = callback; - } - - @Override - public void start(Environment env) throws IOException { - executor = ThreadUtils.newSingleThreadExecutor(getClass().getSimpleName()); - future = executor.submit(this); - } - - @Override - public void destroy() { - stopCommand(); - - if (stdout != null) { - try { - log.info("destroy(" + username + ")[" + command + "] close stdout"); - stdout.close(); - log.info("destroy(" + username + ")[" + command + "] stdout closed"); - } finally { - stdout = null; - } - } - - if (stderr != null) { - try { - log.info("destroy(" + username + ")[" + command + "] close stderr"); - stderr.close(); - log.info("destroy(" + username + ")[" + command + "] stderr closed"); - } finally { - stderr = null; - } - } - - if (stdin != null) { - try { - log.info("destroy(" + username + ")[" + command + "] close stdin"); - stdin.close(); - log.info("destroy(" + username + ")[" + command + "] stdin closed"); - } catch (IOException e) { - log.warn("destroy(" + username + ")[" + command + "] failed (" + e.getClass().getSimpleName() + ") to close stdin: " + e.getMessage()); - if (log.isDebugEnabled()) { - log.debug("destroy(" + username + ")[" + command + "] failure details", e); - } - } finally { - stdin = null; - } - } - } - - private void stopCommand() { - if ((future != null) && (!future.isDone())) { - try { - log.info("stopCommand(" + username + ")[" + command + "] cancelling"); - future.cancel(true); - log.info("stopCommand(" + username + ")[" + command + "] cancelled"); - } finally { - future = null; - } - } - - if ((executor != null) && (!executor.isShutdown())) { - try { - log.info("stopCommand(" + username + ")[" + command + "] shutdown executor"); - executor.shutdownNow(); - log.info("stopCommand(" + username + ")[" + command + "] executor shut down"); - } finally { - executor = null; - } - } - } - } - - public static class MounterCommandFactory implements CommandFactory { - public static final MounterCommandFactory INSTANCE = new MounterCommandFactory(); - - public MounterCommandFactory() { - super(); - } - - @Override - public Command createCommand(String command) { - return new MounterCommand(command); - } - } - - private SshFsMounter() { - throw new UnsupportedOperationException("No instance"); - } - - ////////////////////////////////////////////////////////////////////////// - - public static void main(String[] args) throws Exception { - int port = SshConfigFileReader.DEFAULT_PORT; - boolean error = false; - Map<String, Object> options = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - int numArgs = GenericUtils.length(args); - for (int i = 0; i < numArgs; i++) { - String argName = args[i]; - if ("-p".equals(argName)) { - if ((i + 1) >= numArgs) { - System.err.println("option requires an argument: " + argName); - break; - } - port = Integer.parseInt(args[++i]); - } else if ("-io".equals(argName)) { - if (i + 1 >= numArgs) { - System.err.println("option requires an argument: " + argName); - break; - } - - String provider = args[++i]; - if ("mina".equals(provider)) { - System.setProperty(IoServiceFactory.class.getName(), BuiltinIoServiceFactoryFactories.MINA.getFactoryClassName()); - } else if ("nio2".endsWith(provider)) { - System.setProperty(IoServiceFactory.class.getName(), BuiltinIoServiceFactoryFactories.NIO2.getFactoryClassName()); - } else { - System.err.println("provider should be mina or nio2: " + argName); - error = true; - break; - } - } else if ("-o".equals(argName)) { - if ((i + 1) >= numArgs) { - System.err.println("option requires and argument: " + argName); - error = true; - break; - } - String opt = args[++i]; - int idx = opt.indexOf('='); - if (idx <= 0) { - System.err.println("bad syntax for option: " + opt); - error = true; - break; - } - options.put(opt.substring(0, idx), opt.substring(idx + 1)); - } else if (argName.startsWith("-")) { - System.err.println("illegal option: " + argName); - error = true; - break; - } else { - System.err.println("extra argument: " + argName); - error = true; - break; - } - } - if (error) { - System.err.println("usage: sshfs [-p port] [-io mina|nio2] [-o option=value]"); - System.exit(-1); - } - - SshServer sshd = Utils.setupTestServer(SshFsMounter.class); - Map<String, Object> props = sshd.getProperties(); - props.putAll(options); - PropertyResolver resolver = PropertyResolverUtils.toPropertyResolver(options); - File targetFolder = Objects.requireNonNull(Utils.detectTargetFolder(MounterCommandFactory.class), "Failed to detect target folder"); - if (SecurityUtils.isBouncyCastleRegistered()) { - sshd.setKeyPairProvider(SecurityUtils.createGeneratorHostKeyProvider(new File(targetFolder, "key.pem").toPath())); - } else { - sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File(targetFolder, "key.ser"))); - } - // Should come AFTER key pair provider setup so auto-welcome can be generated if needed - SshServer.setupServerBanner(sshd, resolver); - - sshd.setShellFactory(InteractiveProcessShellFactory.INSTANCE); - sshd.setPasswordAuthenticator(AcceptAllPasswordAuthenticator.INSTANCE); - sshd.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE); - sshd.setCommandFactory(new ScpCommandFactory.Builder().withDelegate(MounterCommandFactory.INSTANCE).build()); - sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory())); - sshd.setPort(port); - - System.err.println("Starting SSHD on port " + port); - sshd.start(); - Thread.sleep(Long.MAX_VALUE); - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/test/java/org/apache/sshd/util/test/TestChannelListener.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/util/test/TestChannelListener.java b/sshd-core/src/test/java/org/apache/sshd/util/test/TestChannelListener.java new file mode 100644 index 0000000..bc34c25 --- /dev/null +++ b/sshd-core/src/test/java/org/apache/sshd/util/test/TestChannelListener.java @@ -0,0 +1,155 @@ +/* + * 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.util.test; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +import org.apache.sshd.common.NamedResource; +import org.apache.sshd.common.channel.Channel; +import org.apache.sshd.common.channel.ChannelListener; +import org.apache.sshd.common.util.logging.AbstractLoggingBean; +import org.junit.Assert; + +/** + * @author <a href="mailto:d...@mina.apache.org">Apache MINA SSHD Project</a> + */ +public class TestChannelListener extends AbstractLoggingBean implements ChannelListener, NamedResource { + private final String name; + private final Collection<Channel> activeChannels = new CopyOnWriteArraySet<>(); + private final Semaphore activeChannelsCounter = new Semaphore(0); + private final Collection<Channel> openChannels = new CopyOnWriteArraySet<>(); + private final Semaphore openChannelsCounter = new Semaphore(0); + private final Collection<Channel> failedChannels = new CopyOnWriteArraySet<>(); + private final Semaphore failedChannelsCounter = new Semaphore(0); + private final Map<Channel, Collection<String>> channelStateHints = new ConcurrentHashMap<>(); + private final Semaphore chanelStateCounter = new Semaphore(0); + private final Semaphore modificationsCounter = new Semaphore(0); + private final Semaphore closedChannelsCounter = new Semaphore(0); + + public TestChannelListener(String discriminator) { + super(discriminator); + name = discriminator; + } + + public boolean waitForModification(long timeout, TimeUnit unit) throws InterruptedException { + return modificationsCounter.tryAcquire(timeout, unit); + } + + @Override + public String getName() { + return name; + } + + public Collection<Channel> getActiveChannels() { + return activeChannels; + } + + @Override + public void channelInitialized(Channel channel) { + Assert.assertTrue("Same channel instance re-initialized: " + channel, activeChannels.add(channel)); + activeChannelsCounter.release(); + modificationsCounter.release(); + log.info("channelInitialized({})", channel); + } + + public boolean waitForActiveChannelsChange(long timeout, TimeUnit unit) throws InterruptedException { + return activeChannelsCounter.tryAcquire(timeout, unit); + } + + public Collection<Channel> getOpenChannels() { + return openChannels; + } + + @Override + public void channelOpenSuccess(Channel channel) { + Assert.assertTrue("Open channel not activated: " + channel, activeChannels.contains(channel)); + Assert.assertTrue("Same channel instance re-opened: " + channel, openChannels.add(channel)); + openChannelsCounter.release(); + modificationsCounter.release(); + log.info("channelOpenSuccess({})", channel); + } + + public boolean waitForOpenChannelsChange(long timeout, TimeUnit unit) throws InterruptedException { + return openChannelsCounter.tryAcquire(timeout, unit); + } + + public Collection<Channel> getFailedChannels() { + return failedChannels; + } + + @Override + public void channelOpenFailure(Channel channel, Throwable reason) { + Assert.assertTrue("Failed channel not activated: " + channel, activeChannels.contains(channel)); + Assert.assertTrue("Same channel instance re-failed: " + channel, failedChannels.add(channel)); + failedChannelsCounter.release(); + modificationsCounter.release(); + log.warn("channelOpenFailure({}) {} : {}", channel, reason.getClass().getSimpleName(), reason.getMessage()); + if (log.isDebugEnabled()) { + log.debug("channelOpenFailure(" + channel + ") details", reason); + } + } + + public boolean waitForFailedChannelsChange(long timeout, TimeUnit unit) throws InterruptedException { + return failedChannelsCounter.tryAcquire(timeout, unit); + } + + @Override + public void channelClosed(Channel channel, Throwable reason) { + Assert.assertTrue("Unknown closed channel instance: " + channel, activeChannels.remove(channel)); + activeChannelsCounter.release(); + closedChannelsCounter.release(); + modificationsCounter.release(); + log.info("channelClosed({})", channel); + } + + public boolean waitForClosedChannelsChange(long timeout, TimeUnit unit) throws InterruptedException { + return closedChannelsCounter.tryAcquire(timeout, unit); + } + + public Map<Channel, Collection<String>> getChannelStateHints() { + return channelStateHints; + } + + @Override + public void channelStateChanged(Channel channel, String hint) { + Collection<String> hints; + synchronized (channelStateHints) { + hints = channelStateHints.get(channel); + if (hints == null) { + hints = new CopyOnWriteArrayList<>(); + channelStateHints.put(channel, hints); + } + } + + hints.add(hint); + chanelStateCounter.release(); + modificationsCounter.release(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + getName() + "]"; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-git/pom.xml ---------------------------------------------------------------------- diff --git a/sshd-git/pom.xml b/sshd-git/pom.xml index d0f6c6a..f9e16a7 100644 --- a/sshd-git/pom.xml +++ b/sshd-git/pom.xml @@ -61,6 +61,12 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-sftp</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-mina/pom.xml ---------------------------------------------------------------------- diff --git a/sshd-mina/pom.xml b/sshd-mina/pom.xml index b14b18f..0234e85 100644 --- a/sshd-mina/pom.xml +++ b/sshd-mina/pom.xml @@ -50,6 +50,19 @@ <!-- test dependencies --> <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-core</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-sftp</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> <groupId>net.i2p.crypto</groupId> <artifactId>eddsa</artifactId> <scope>test</scope> @@ -107,20 +120,54 @@ </dependencies> <build> - <testSourceDirectory>${projectRoot}/sshd-core/src/test/java</testSourceDirectory> - <resources> - <resource> - <directory>src/main/filtered-resources</directory> - <filtering>true</filtering> - </resource> - <resource> - <directory>${projectRoot}/sshd-core/src/test/resources</directory> - <targetPath>${project.build.testOutputDirectory}</targetPath> - </resource> - </resources> + <testSourceDirectory>${build.directory}/test-sources</testSourceDirectory> + <testResources> + <testResource> + <directory>${build.directory}/test-resources</directory> + </testResource> + </testResources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <executions> + <execution> + <id>copy-test-resources</id> + <phase>generate-test-resources</phase> + <goals> + <goal>copy-resources</goal> + </goals> + <configuration> + <outputDirectory>${build.directory}/test-resources</outputDirectory> + <resources> + <resource> + <directory>${projectRoot}/sshd-core/src/test/resources</directory> + </resource> + </resources> + </configuration> + </execution> + <execution> + <id>copy-test-sources</id> + <phase>generate-test-sources</phase> + <goals> + <goal>copy-resources</goal> + </goals> + <configuration> + <outputDirectory>${build.directory}/test-sources</outputDirectory> + <resources> + <resource> + <directory>${projectRoot}/sshd-core/src/test/java</directory> + </resource> + <resource> + <directory>${projectRoot}/sshd-sftp/src/test/java</directory> + </resource> + </resources> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <redirectTestOutputToFile>true</redirectTestOutputToFile> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/pom.xml ---------------------------------------------------------------------- diff --git a/sshd-sftp/pom.xml b/sshd-sftp/pom.xml new file mode 100644 index 0000000..7d4f74a --- /dev/null +++ b/sshd-sftp/pom.xml @@ -0,0 +1,103 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + + <!-- + + 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. + --> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd</artifactId> + <version>1.7.1-SNAPSHOT</version> + </parent> + + <artifactId>sshd-sftp</artifactId> + <name>Apache Mina SSHD :: SFTP</name> + <packaging>jar</packaging> + <inceptionYear>2018</inceptionYear> + + <properties> + <projectRoot>${project.basedir}/..</projectRoot> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-core</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.apache.sshd</groupId> + <artifactId>sshd-core</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.jcraft</groupId> + <artifactId>jsch</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.jcraft</groupId> + <artifactId>jzlib</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <redirectTestOutputToFile>true</redirectTestOutputToFile> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <configuration> + <additionalparam>-Xdoclint:none</additionalparam> + </configuration> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/client/simple/SimpleSftpClient.java ---------------------------------------------------------------------- diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/simple/SimpleSftpClient.java b/sshd-sftp/src/main/java/org/apache/sshd/client/simple/SimpleSftpClient.java new file mode 100644 index 0000000..1034046 --- /dev/null +++ b/sshd-sftp/src/main/java/org/apache/sshd/client/simple/SimpleSftpClient.java @@ -0,0 +1,179 @@ +/* + * 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.client.simple; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.channels.Channel; +import java.security.KeyPair; +import java.util.Objects; + +import org.apache.sshd.client.subsystem.sftp.SftpClient; +import org.apache.sshd.common.util.ValidateUtils; + +/** + * A simplified <U>synchronous</U> API for obtaining SFTP sessions. + * + * @author <a href="mailto:d...@mina.apache.org">Apache MINA SSHD Project</a> + */ +public interface SimpleSftpClient extends Channel { + /** + * Creates an SFTP session on the default port and logs in using the provided credentials + * + * @param host The target host name or address + * @param username Username + * @param password Password + * @return Created {@link SftpClient} - <B>Note:</B> closing the client also closes its + * underlying session + * @throws IOException If failed to login or authenticate + */ + default SftpClient sftpLogin(String host, String username, String password) throws IOException { + return sftpLogin(host, SimpleClientConfigurator.DEFAULT_PORT, username, password); + } + + /** + * Creates an SFTP session using the provided credentials + * + * @param host The target host name or address + * @param port The target port + * @param username Username + * @param password Password + * @return Created {@link SftpClient} - <B>Note:</B> closing the client also closes its + * underlying session + * @throws IOException If failed to login or authenticate + */ + default SftpClient sftpLogin(String host, int port, String username, String password) throws IOException { + return sftpLogin(InetAddress.getByName(ValidateUtils.checkNotNullAndNotEmpty(host, "No host")), port, username, password); + } + + /** + * Creates an SFTP session on the default port and logs in using the provided credentials + * + * @param host The target host name or address + * @param username Username + * @param identity The {@link KeyPair} identity + * @return Created {@link SftpClient} - <B>Note:</B> closing the client also closes its + * underlying session + * @throws IOException If failed to login or authenticate + */ + default SftpClient sftpLogin(String host, String username, KeyPair identity) throws IOException { + return sftpLogin(host, SimpleClientConfigurator.DEFAULT_PORT, username, identity); + } + + /** + * Creates an SFTP session using the provided credentials + * + * @param host The target host name or address + * @param port The target port + * @param username Username + * @param identity The {@link KeyPair} identity + * @return Created {@link SftpClient} - <B>Note:</B> closing the client also closes its + * underlying session + * @throws IOException If failed to login or authenticate + */ + default SftpClient sftpLogin(String host, int port, String username, KeyPair identity) throws IOException { + return sftpLogin(InetAddress.getByName(ValidateUtils.checkNotNullAndNotEmpty(host, "No host")), port, username, identity); + } + + /** + * Creates an SFTP session on the default port and logs in using the provided credentials + * + * @param host The target host {@link InetAddress} + * @param username Username + * @param password Password + * @return Created {@link SftpClient} - <B>Note:</B> closing the client also closes its + * underlying session + * @throws IOException If failed to login or authenticate + */ + default SftpClient sftpLogin(InetAddress host, String username, String password) throws IOException { + return sftpLogin(host, SimpleClientConfigurator.DEFAULT_PORT, username, password); + } + + /** + * Creates an SFTP session using the provided credentials + * + * @param host The target host {@link InetAddress} + * @param port The target port + * @param username Username + * @param password Password + * @return Created {@link SftpClient} - <B>Note:</B> closing the client also closes its + * underlying session + * @throws IOException If failed to login or authenticate + */ + default SftpClient sftpLogin(InetAddress host, int port, String username, String password) throws IOException { + return sftpLogin(new InetSocketAddress(Objects.requireNonNull(host, "No host address"), port), username, password); + } + + /** + * Creates an SFTP session on the default port and logs in using the provided credentials + * + * @param host The target host {@link InetAddress} + * @param username Username + * @param identity The {@link KeyPair} identity + * @return Created {@link SftpClient} - <B>Note:</B> closing the client also closes its + * underlying session + * @throws IOException If failed to login or authenticate + */ + default SftpClient sftpLogin(InetAddress host, String username, KeyPair identity) throws IOException { + return sftpLogin(host, SimpleClientConfigurator.DEFAULT_PORT, username, identity); + } + + /** + * Creates an SFTP session using the provided credentials + * + * @param host The target host {@link InetAddress} + * @param port The target port + * @param username Username + * @param identity The {@link KeyPair} identity + * @return Created {@link SftpClient} - <B>Note:</B> closing the client also closes its + * underlying session + * @throws IOException If failed to login or authenticate + */ + default SftpClient sftpLogin(InetAddress host, int port, String username, KeyPair identity) throws IOException { + return sftpLogin(new InetSocketAddress(Objects.requireNonNull(host, "No host address"), port), username, identity); + } + + /** + * Creates an SFTP session using the provided credentials + * + * @param target The target {@link SocketAddress} + * @param username Username + * @param password Password + * @return Created {@link SftpClient} - <B>Note:</B> closing the client also closes its + * underlying session + * @throws IOException If failed to login or authenticate + */ + SftpClient sftpLogin(SocketAddress target, String username, String password) throws IOException; + + /** + * Creates an SFTP session using the provided credentials + * + * @param target The target {@link SocketAddress} + * @param username Username + * @param identity The {@link KeyPair} identity + * @return Created {@link SftpClient} - <B>Note:</B> closing the client also closes its + * underlying session + * @throws IOException If failed to login or authenticate + */ + SftpClient sftpLogin(SocketAddress target, String username, KeyPair identity) throws IOException; + +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/client/simple/SimpleSftpClientImpl.java ---------------------------------------------------------------------- diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/simple/SimpleSftpClientImpl.java b/sshd-sftp/src/main/java/org/apache/sshd/client/simple/SimpleSftpClientImpl.java new file mode 100644 index 0000000..09a7007 --- /dev/null +++ b/sshd-sftp/src/main/java/org/apache/sshd/client/simple/SimpleSftpClientImpl.java @@ -0,0 +1,170 @@ +/* + * 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.client.simple; + +import java.io.IOException; +import java.lang.reflect.Proxy; +import java.net.SocketAddress; +import java.security.KeyPair; + +import org.apache.sshd.client.session.ClientSession; +import org.apache.sshd.client.subsystem.sftp.SftpClient; +import org.apache.sshd.client.subsystem.sftp.SftpClientFactory; +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.common.util.logging.AbstractLoggingBean; + +public class SimpleSftpClientImpl extends AbstractLoggingBean implements SimpleSftpClient { + + private SimpleClient client; + private SftpClientFactory sftpClientFactory; + + public SimpleSftpClientImpl(SimpleClient client) { + this(client, null); + } + + public SimpleSftpClientImpl(SimpleClient client, SftpClientFactory sftpClientFactory) { + this.client = client; + this.sftpClientFactory = sftpClientFactory != null ? sftpClientFactory : SftpClientFactory.instance(); + } + + public SimpleClient getClient() { + return client; + } + + public void setClient(SimpleClient client) { + this.client = client; + } + + public SftpClientFactory getSftpClientFactory() { + return sftpClientFactory; + } + + public void setSftpClientFactory(SftpClientFactory sftpClientFactory) { + this.sftpClientFactory = sftpClientFactory; + } + + @Override + public SftpClient sftpLogin(SocketAddress target, String username, String password) throws IOException { + return createSftpClient(client.sessionLogin(target, username, password)); + } + + @Override + public SftpClient sftpLogin(SocketAddress target, String username, KeyPair identity) throws IOException { + return createSftpClient(client.sessionLogin(target, username, identity)); + } + + protected SftpClient createSftpClient(final ClientSession session) throws IOException { + Exception err = null; + try { + SftpClient client = sftpClientFactory.createSftpClient(session); + try { + return createSftpClient(session, client); + } catch (Exception e) { + err = GenericUtils.accumulateException(err, e); + try { + client.close(); + } catch (Exception t) { + if (log.isDebugEnabled()) { + log.debug("createSftpClient({}) failed ({}) to close client: {}", + session, t.getClass().getSimpleName(), t.getMessage()); + } + + if (log.isTraceEnabled()) { + log.trace("createSftpClient(" + session + ") client close failure details", t); + } + err = GenericUtils.accumulateException(err, t); + } + } + } catch (Exception e) { + err = GenericUtils.accumulateException(err, e); + } + + // This point is reached if error occurred + log.warn("createSftpClient({}) failed ({}) to create session: {}", + session, err.getClass().getSimpleName(), err.getMessage()); + + try { + session.close(); + } catch (Exception e) { + if (log.isDebugEnabled()) { + log.debug("createSftpClient({}) failed ({}) to close session: {}", + session, e.getClass().getSimpleName(), e.getMessage()); + } + + if (log.isTraceEnabled()) { + log.trace("createSftpClient(" + session + ") session close failure details", e); + } + err = GenericUtils.accumulateException(err, e); + } + + if (err instanceof IOException) { + throw (IOException) err; + } else { + throw new IOException(err); + } + } + + protected SftpClient createSftpClient(final ClientSession session, final SftpClient client) throws IOException { + ClassLoader loader = getClass().getClassLoader(); + Class<?>[] interfaces = {SftpClient.class}; + return (SftpClient) Proxy.newProxyInstance(loader, interfaces, (proxy, method, args) -> { + Throwable err = null; + Object result = null; + String name = method.getName(); + try { + result = method.invoke(client, args); + } catch (Throwable t) { + if (log.isTraceEnabled()) { + log.trace("invoke(SftpClient#{}) failed ({}) to execute: {}", + name, t.getClass().getSimpleName(), t.getMessage()); + } + err = GenericUtils.accumulateException(err, t); + } + + // propagate the "close" call to the session as well + if ("close".equals(name) && GenericUtils.isEmpty(args)) { + try { + session.close(); + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug("invoke(ClientSession#{}) failed ({}) to execute: {}", + name, t.getClass().getSimpleName(), t.getMessage()); + } + err = GenericUtils.accumulateException(err, t); + } + } + + if (err != null) { + throw err; + } + + return result; + }); + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public void close() throws IOException { + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/RawSftpClient.java ---------------------------------------------------------------------- diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/RawSftpClient.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/RawSftpClient.java new file mode 100644 index 0000000..676a03e --- /dev/null +++ b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/RawSftpClient.java @@ -0,0 +1,44 @@ +/* + * 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.client.subsystem.sftp; + +import java.io.IOException; + +import org.apache.sshd.common.util.buffer.Buffer; + +/** + * @author <a href="mailto:d...@mina.apache.org">Apache MINA SSHD Project</a> + */ +public interface RawSftpClient { + /** + * @param cmd Command to send - <B>Note:</B> only lower 8-bits are used + * @param buffer The {@link Buffer} containing the command data + * @return The assigned request id + * @throws IOException if failed to send command + */ + int send(int cmd, Buffer buffer) throws IOException; + + /** + * @param id The expected request id + * @return The received response {@link Buffer} containing the request id + * @throws IOException If connection closed or interrupted + */ + Buffer receive(int id) throws IOException; +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpAclFileAttributeView.java ---------------------------------------------------------------------- diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpAclFileAttributeView.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpAclFileAttributeView.java new file mode 100644 index 0000000..7cada6e --- /dev/null +++ b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpAclFileAttributeView.java @@ -0,0 +1,67 @@ +/* + * 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.client.subsystem.sftp; + +import java.io.IOException; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.attribute.AclEntry; +import java.nio.file.attribute.AclFileAttributeView; +import java.nio.file.attribute.PosixFileAttributes; +import java.nio.file.attribute.UserPrincipal; +import java.util.List; + +import org.apache.sshd.client.subsystem.sftp.impl.AbstractSftpFileAttributeView; + +/** + * @author <a href="mailto:d...@mina.apache.org">Apache MINA SSHD Project</a> + */ +public class SftpAclFileAttributeView extends AbstractSftpFileAttributeView implements AclFileAttributeView { + public SftpAclFileAttributeView(SftpFileSystemProvider provider, Path path, LinkOption... options) { + super(provider, path, options); + } + + @Override + public UserPrincipal getOwner() throws IOException { + PosixFileAttributes v = provider.readAttributes(path, PosixFileAttributes.class, options); + return v.owner(); + } + + @Override + public void setOwner(UserPrincipal owner) throws IOException { + provider.setAttribute(path, "posix", "owner", owner, options); + } + + @Override + public String name() { + return "acl"; + } + + @Override + public List<AclEntry> getAcl() throws IOException { + return readRemoteAttributes().getAcl(); + } + + @Override + public void setAcl(List<AclEntry> acl) throws IOException { + writeRemoteAttributes(new SftpClient.Attributes().acl(acl)); + } + +}