You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/07/15 13:52:17 UTC
[1/2] mina-sshd git commit: [SSHD-516] Add support for
"space-available" extension
Repository: mina-sshd
Updated Branches:
refs/heads/master adb313ebc -> ea46a25d2
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImplTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImplTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImplTest.java
new file mode 100644
index 0000000..b9597d7
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImplTest.java
@@ -0,0 +1,201 @@
+/*
+ * 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.extensions.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.subsystem.sftp.AbstractSftpClientTestSupport;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
+import org.apache.sshd.client.subsystem.sftp.extensions.CopyDataExtension;
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.random.Random;
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+public class CopyDataExtensionImplTest extends AbstractSftpClientTestSupport {
+ private static final List<Object[]> PARAMETERS =
+ Collections.unmodifiableList(
+ Arrays.<Object[]>asList(
+ new Object[] {
+ Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
+ Integer.valueOf(0),
+ Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
+ Long.valueOf(0L)
+ },
+ new Object[] {
+ Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
+ Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE / 2),
+ Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE / 4),
+ Long.valueOf(0L)
+ },
+ new Object[] {
+ Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
+ Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE / 2),
+ Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE / 4),
+ Long.valueOf(IoUtils.DEFAULT_COPY_SIZE / 2)
+ },
+ new Object[] {
+ Integer.valueOf(Byte.MAX_VALUE),
+ Integer.valueOf(Byte.MAX_VALUE / 2),
+ Integer.valueOf(Byte.MAX_VALUE), // attempt to read more than available
+ Long.valueOf(0L)
+ }
+ ));
+
+ @Parameters(name = "size={0}, readOffset={1}, readLength={2}, writeOffset={3}")
+ public static Collection<Object[]> parameters() {
+ return PARAMETERS;
+ }
+
+ private int size, srcOffset, length;
+ private long dstOffset;
+
+ public CopyDataExtensionImplTest(int size, int srcOffset, int length, long dstOffset) throws IOException {
+ this.size = size;
+ this.srcOffset = srcOffset;
+ this.length = length;
+ this.dstOffset = dstOffset;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ setupServer();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ tearDownServer();
+ }
+
+ @Test
+ public void testCopyDataExtension() throws Exception {
+ testCopyDataExtension(size, srcOffset, length, dstOffset);
+ }
+
+ private void testCopyDataExtension(int dataSize, int readOffset, int readLength, long writeOffset) throws Exception {
+ byte[] seed = (getClass().getName() + "#" + getCurrentTestName()
+ + "-" + dataSize
+ + "-" + readOffset + "/" + readLength + "/" + writeOffset
+ + System.getProperty("line.separator"))
+ .getBytes(StandardCharsets.UTF_8)
+ ;
+ try(ByteArrayOutputStream baos=new ByteArrayOutputStream(dataSize + seed.length)) {
+ while (baos.size() < dataSize) {
+ baos.write(seed);
+ }
+
+ testCopyDataExtension(baos.toByteArray(), readOffset, readLength, writeOffset);
+ }
+ }
+
+ private void testCopyDataExtension(byte[] data, int readOffset, int readLength, long writeOffset) throws Exception {
+ Path targetPath = detectTargetFolder().toPath();
+ Path parentPath = targetPath.getParent();
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
+ LinkOption[] options = IoUtils.getLinkOptions(false);
+ String baseName = readOffset + "-" + readLength + "-" + writeOffset;
+ Path srcFile = assertHierarchyTargetFolderExists(lclSftp, options).resolve(baseName + "-src.txt");
+ Files.write(srcFile, data, IoUtils.EMPTY_OPEN_OPTIONS);
+ String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
+
+ Path dstFile = srcFile.getParent().resolve(baseName + "-dst.txt");
+ if (Files.exists(dstFile, options)) {
+ Files.delete(dstFile);
+ }
+ String dstPath = Utils.resolveRelativeRemotePath(parentPath, dstFile);
+
+ try(SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ if (writeOffset > 0L) {
+ Factory<? extends Random> factory = client.getRandomFactory();
+ Random randomizer = factory.create();
+ long totalLength = writeOffset + readLength;
+ byte[] workBuf = new byte[(int) Math.min(totalLength, IoUtils.DEFAULT_COPY_SIZE)];
+ try(OutputStream output = Files.newOutputStream(dstFile, IoUtils.EMPTY_OPEN_OPTIONS)) {
+ while(totalLength > 0L) {
+ randomizer.fill(workBuf);
+ output.write(workBuf);
+ totalLength -= workBuf.length;
+ }
+ }
+ }
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(SftpClient sftp = session.createSftpClient()) {
+ CopyDataExtension ext = assertExtensionCreated(sftp, CopyDataExtension.class);
+ try(CloseableHandle readHandle = sftp.open(srcPath, SftpClient.OpenMode.Read);
+ CloseableHandle writeHandle = sftp.open(dstPath, SftpClient.OpenMode.Write, SftpClient.OpenMode.Create)) {
+ ext.copyData(readHandle, readOffset, readLength, writeHandle, writeOffset);
+ }
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ int available = data.length, required = readOffset + readLength;
+ if (required > available) {
+ required = available;
+ }
+ byte[] expected = new byte[required - readOffset];
+ System.arraycopy(data, readOffset, expected, 0, expected.length);
+
+ byte[] actual = new byte[expected.length];
+ try(FileChannel channel = FileChannel.open(dstFile, IoUtils.EMPTY_OPEN_OPTIONS)) {
+ int readLen = channel.read(ByteBuffer.wrap(actual), writeOffset);
+ assertEquals("Mismatched read data size", expected.length, readLen);
+ }
+ assertArrayEquals("Mismatched copy data", expected, actual);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyFileExtensionImplTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyFileExtensionImplTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyFileExtensionImplTest.java
new file mode 100644
index 0000000..7e5c87d
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyFileExtensionImplTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.extensions.impl;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.client.SftpException;
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.subsystem.sftp.AbstractSftpClientTestSupport;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.extensions.CopyFileExtension;
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class CopyFileExtensionImplTest extends AbstractSftpClientTestSupport {
+ public CopyFileExtensionImplTest() throws IOException {
+ super();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ setupServer();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ tearDownServer();
+ }
+
+ @Test
+ public void testCopyFileExtension() throws Exception {
+ Path targetPath = detectTargetFolder().toPath();
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName());
+ Utils.deleteRecursive(lclSftp);
+
+ byte[] data = (getClass().getName() + "#" + getCurrentTestName()).getBytes(StandardCharsets.UTF_8);
+ Path srcFile = assertHierarchyTargetFolderExists(lclSftp).resolve("src.txt");
+ Files.write(srcFile, data, IoUtils.EMPTY_OPEN_OPTIONS);
+
+ Path parentPath = targetPath.getParent();
+ String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
+ Path dstFile = lclSftp.resolve("dst.txt");
+ String dstPath = Utils.resolveRelativeRemotePath(parentPath, dstFile);
+
+ LinkOption[] options = IoUtils.getLinkOptions(false);
+ assertFalse("Destination file unexpectedly exists", Files.exists(dstFile, options));
+
+ try(SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(SftpClient sftp = session.createSftpClient()) {
+ CopyFileExtension ext = assertExtensionCreated(sftp, CopyFileExtension.class);
+ ext.copyFile(srcPath, dstPath, false);
+ assertTrue("Source file not preserved", Files.exists(srcFile, options));
+ assertTrue("Destination file not created", Files.exists(dstFile, options));
+
+ byte[] actual = Files.readAllBytes(dstFile);
+ assertArrayEquals("Mismatched copied data", data, actual);
+
+ try {
+ ext.copyFile(srcPath, dstPath, false);
+ fail("Unexpected success to overwrite existing destination: " + dstFile);
+ } catch(IOException e) {
+ assertTrue("Not an SftpException", e instanceof SftpException);
+ }
+ }
+ } finally {
+ client.stop();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/SpaceAvailableExtensionImplTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/SpaceAvailableExtensionImplTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/SpaceAvailableExtensionImplTest.java
new file mode 100644
index 0000000..08c561d
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/SpaceAvailableExtensionImplTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.extensions.impl;
+
+import java.io.IOException;
+import java.io.StreamCorruptedException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.subsystem.sftp.AbstractSftpClientTestSupport;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.extensions.SpaceAvailableExtension;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.subsystem.sftp.extensions.SpaceAvailableExtensionInfo;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.subsystem.sftp.SftpSubsystem;
+import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class SpaceAvailableExtensionImplTest extends AbstractSftpClientTestSupport {
+ public SpaceAvailableExtensionImplTest() throws IOException {
+ super();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ setupServer();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ tearDownServer();
+ }
+
+ @Test
+ public void testFileStoreReport() throws Exception {
+ Path targetPath = detectTargetFolder().toPath();
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName());
+ Path parentPath = targetPath.getParent();
+ FileStore store = Files.getFileStore(lclSftp.getRoot());
+ final String queryPath = Utils.resolveRelativeRemotePath(parentPath, lclSftp);
+ final SpaceAvailableExtensionInfo expected = new SpaceAvailableExtensionInfo(store);
+ sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystemFactory() {
+ @Override
+ public Command create() {
+ return new SftpSubsystem(getExecutorService(), isShutdownOnExit(), getUnsupportedAttributePolicy()) {
+ @Override
+ protected SpaceAvailableExtensionInfo doSpaceAvailable(int id, String path) throws IOException {
+ if (!queryPath.equals(path)) {
+ throw new StreamCorruptedException("Mismatched query paths: expected=" + queryPath + ", actual=" + path);
+ }
+
+ return expected;
+ }
+ };
+ }
+ }));
+
+ try(SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(SftpClient sftp = session.createSftpClient()) {
+ SpaceAvailableExtension ext = assertExtensionCreated(sftp, SpaceAvailableExtension.class);
+ SpaceAvailableExtensionInfo actual = ext.available(queryPath);
+ assertEquals("Mismatched information", expected, actual);
+ }
+ } finally {
+ client.stop();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHExtensionsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHExtensionsTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHExtensionsTest.java
deleted file mode 100644
index f44aaf3..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHExtensionsTest.java
+++ /dev/null
@@ -1,217 +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.client.subsystem.sftp.extensions.openssh;
-
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXP_EXTENDED_REPLY;
-
-import java.io.IOException;
-import java.io.StreamCorruptedException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.client.subsystem.sftp.AbstractSftpClientTestSupport;
-import org.apache.sshd.client.subsystem.sftp.SftpClient;
-import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.subsystem.sftp.SftpConstants;
-import org.apache.sshd.common.subsystem.sftp.extensions.openssh.AbstractOpenSSHExtensionParser.OpenSSHExtension;
-import org.apache.sshd.common.subsystem.sftp.extensions.openssh.FstatVfsExtensionParser;
-import org.apache.sshd.common.subsystem.sftp.extensions.openssh.StatVfsExtensionParser;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.io.IoUtils;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.subsystem.sftp.SftpSubsystem;
-import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
-import org.apache.sshd.util.Utils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runners.MethodSorters;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenSSHExtensionsTest extends AbstractSftpClientTestSupport {
- public OpenSSHExtensionsTest() throws IOException {
- super();
- }
-
- @Before
- public void setUp() throws Exception {
- setupServer();
- }
-
- @After
- public void tearDown() throws Exception {
- tearDownServer();
- }
-
- @Test
- public void testFsync() throws IOException {
- Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
- Path srcFile = assertHierarchyTargetFolderExists(lclSftp).resolve(getCurrentTestName() + ".txt");
- byte[] expected=(getClass().getName() + "#" + getCurrentTestName()).getBytes(StandardCharsets.UTF_8);
-
- Path parentPath = targetPath.getParent();
- String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
- try(SshClient client = SshClient.setUpDefaultClient()) {
- client.start();
-
- try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
- session.addPasswordIdentity(getCurrentTestName());
- session.auth().verify(5L, TimeUnit.SECONDS);
-
- try(SftpClient sftp = session.createSftpClient()) {
- OpenSSHFsyncExtension fsync = assertExtensionCreated(sftp, OpenSSHFsyncExtension.class);
- try(CloseableHandle fileHandle = sftp.open(srcPath, SftpClient.OpenMode.Write, SftpClient.OpenMode.Create)) {
- sftp.write(fileHandle, 0L, expected);
- fsync.fsync(fileHandle);
-
- byte[] actual = Files.readAllBytes(srcFile);
- assertArrayEquals("Mismatched written data", expected, actual);
- }
- }
- } finally {
- client.stop();
- }
- }
- }
-
- @Test
- public void testStat() throws Exception {
- Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
- Path srcFile = assertHierarchyTargetFolderExists(lclSftp).resolve(getCurrentTestName() + ".txt");
- Files.write(srcFile, (getClass().getName() + "#" + getCurrentTestName()).getBytes(StandardCharsets.UTF_8), IoUtils.EMPTY_OPEN_OPTIONS);
- Path parentPath = targetPath.getParent();
- String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
-
- final AtomicReference<String> extensionHolder = new AtomicReference<String>(null);
- final OpenSSHStatExtensionInfo expected = new OpenSSHStatExtensionInfo();
- {
- expected.f_bavail = Short.MAX_VALUE;
- expected.f_bfree = Integer.MAX_VALUE;
- expected.f_blocks = Short.MAX_VALUE;
- expected.f_bsize = IoUtils.DEFAULT_COPY_SIZE;
- expected.f_favail = Long.MAX_VALUE;
- expected.f_ffree = Byte.MAX_VALUE;
- expected.f_files = 3777347L;
- expected.f_flag = OpenSSHStatExtensionInfo.SSH_FXE_STATVFS_ST_RDONLY;
- expected.f_frsize = 7365L;
- expected.f_fsid = 1L;
- expected.f_namemax = 256;
- }
- sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystemFactory() {
- @Override
- public Command create() {
- return new SftpSubsystem(getExecutorService(), isShutdownOnExit(), getUnsupportedAttributePolicy()) {
- @Override
- protected List<OpenSSHExtension> resolveOpenSSHExtensions() {
- List<OpenSSHExtension> original = super.resolveOpenSSHExtensions();
- int numOriginal = GenericUtils.size(original);
- List<OpenSSHExtension> result = new ArrayList<OpenSSHExtension>(numOriginal + 2);
- if (numOriginal > 0) {
- result.addAll(original);
- }
-
- for (String name : new String[] { StatVfsExtensionParser.NAME, FstatVfsExtensionParser.NAME}) {
- result.add(new OpenSSHExtension(name, "2"));
- }
-
- return result;
- }
-
- @Override
- protected void executeExtendedCommand(Buffer buffer, int id, String extension) throws IOException {
- if (StatVfsExtensionParser.NAME.equals(extension)
- || FstatVfsExtensionParser.NAME.equals(extension)) {
- String prev = extensionHolder.getAndSet(extension);
- if (prev != null) {
- throw new StreamCorruptedException("executeExtendedCommand(" + extension + ") previous not null: " + prev);
- }
-
- buffer.clear();
- buffer.putByte((byte) SSH_FXP_EXTENDED_REPLY);
- buffer.putInt(id);
- OpenSSHStatExtensionInfo.encode(buffer, expected);
- send(buffer);
- } else {
- super.executeExtendedCommand(buffer, id, extension);
- }
- }
- };
- }
- }));
-
- try(SshClient client = SshClient.setUpDefaultClient()) {
- client.start();
-
- try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
- session.addPasswordIdentity(getCurrentTestName());
- session.auth().verify(5L, TimeUnit.SECONDS);
-
- try(SftpClient sftp = session.createSftpClient()) {
- {
- OpenSSHStatPathExtension pathStat = assertExtensionCreated(sftp, OpenSSHStatPathExtension.class);
- OpenSSHStatExtensionInfo actual = pathStat.stat(srcPath);
- String invokedExtension = extensionHolder.getAndSet(null);
- assertEquals("Mismatched invoked extension", pathStat.getName(), invokedExtension);
- assertOpenSSHStatExtensionInfoEquals(invokedExtension, expected, actual);
- }
-
- try(CloseableHandle handle = sftp.open(srcPath)) {
- OpenSSHStatHandleExtension handleStat = assertExtensionCreated(sftp, OpenSSHStatHandleExtension.class);
- OpenSSHStatExtensionInfo actual = handleStat.stat(handle);
- String invokedExtension = extensionHolder.getAndSet(null);
- assertEquals("Mismatched invoked extension", handleStat.getName(), invokedExtension);
- assertOpenSSHStatExtensionInfoEquals(invokedExtension, expected, actual);
- }
- }
- }
- }
- }
-
- private static void assertOpenSSHStatExtensionInfoEquals(String extension, OpenSSHStatExtensionInfo expected, OpenSSHStatExtensionInfo actual) throws Exception {
- Field[] fields = expected.getClass().getFields();
- for (Field f : fields) {
- String name = f.getName();
- int mod = f.getModifiers();
- if (Modifier.isStatic(mod)) {
- continue;
- }
- Object expValue = f.get(expected), actValue = f.get(actual);
- assertEquals(extension + "[" + name + "]", expValue, actValue);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHExtensionsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHExtensionsTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHExtensionsTest.java
new file mode 100644
index 0000000..b6910af
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHExtensionsTest.java
@@ -0,0 +1,221 @@
+/*
+ * 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.extensions.openssh.impl;
+
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXP_EXTENDED_REPLY;
+
+import java.io.IOException;
+import java.io.StreamCorruptedException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.subsystem.sftp.AbstractSftpClientTestSupport;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHFsyncExtension;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatExtensionInfo;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatHandleExtension;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatPathExtension;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.AbstractOpenSSHExtensionParser.OpenSSHExtension;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.FstatVfsExtensionParser;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.StatVfsExtensionParser;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.subsystem.sftp.SftpSubsystem;
+import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class OpenSSHExtensionsTest extends AbstractSftpClientTestSupport {
+ public OpenSSHExtensionsTest() throws IOException {
+ super();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ setupServer();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ tearDownServer();
+ }
+
+ @Test
+ public void testFsync() throws IOException {
+ Path targetPath = detectTargetFolder().toPath();
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
+ Path srcFile = assertHierarchyTargetFolderExists(lclSftp).resolve(getCurrentTestName() + ".txt");
+ byte[] expected=(getClass().getName() + "#" + getCurrentTestName()).getBytes(StandardCharsets.UTF_8);
+
+ Path parentPath = targetPath.getParent();
+ String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
+ try(SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(SftpClient sftp = session.createSftpClient()) {
+ OpenSSHFsyncExtension fsync = assertExtensionCreated(sftp, OpenSSHFsyncExtension.class);
+ try(CloseableHandle fileHandle = sftp.open(srcPath, SftpClient.OpenMode.Write, SftpClient.OpenMode.Create)) {
+ sftp.write(fileHandle, 0L, expected);
+ fsync.fsync(fileHandle);
+
+ byte[] actual = Files.readAllBytes(srcFile);
+ assertArrayEquals("Mismatched written data", expected, actual);
+ }
+ }
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
+ @Test
+ public void testStat() throws Exception {
+ Path targetPath = detectTargetFolder().toPath();
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
+ Path srcFile = assertHierarchyTargetFolderExists(lclSftp).resolve(getCurrentTestName() + ".txt");
+ Files.write(srcFile, (getClass().getName() + "#" + getCurrentTestName()).getBytes(StandardCharsets.UTF_8), IoUtils.EMPTY_OPEN_OPTIONS);
+ Path parentPath = targetPath.getParent();
+ String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
+
+ final AtomicReference<String> extensionHolder = new AtomicReference<String>(null);
+ final OpenSSHStatExtensionInfo expected = new OpenSSHStatExtensionInfo();
+ {
+ expected.f_bavail = Short.MAX_VALUE;
+ expected.f_bfree = Integer.MAX_VALUE;
+ expected.f_blocks = Short.MAX_VALUE;
+ expected.f_bsize = IoUtils.DEFAULT_COPY_SIZE;
+ expected.f_favail = Long.MAX_VALUE;
+ expected.f_ffree = Byte.MAX_VALUE;
+ expected.f_files = 3777347L;
+ expected.f_flag = OpenSSHStatExtensionInfo.SSH_FXE_STATVFS_ST_RDONLY;
+ expected.f_frsize = 7365L;
+ expected.f_fsid = 1L;
+ expected.f_namemax = 256;
+ }
+ sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystemFactory() {
+ @Override
+ public Command create() {
+ return new SftpSubsystem(getExecutorService(), isShutdownOnExit(), getUnsupportedAttributePolicy()) {
+ @Override
+ protected List<OpenSSHExtension> resolveOpenSSHExtensions() {
+ List<OpenSSHExtension> original = super.resolveOpenSSHExtensions();
+ int numOriginal = GenericUtils.size(original);
+ List<OpenSSHExtension> result = new ArrayList<OpenSSHExtension>(numOriginal + 2);
+ if (numOriginal > 0) {
+ result.addAll(original);
+ }
+
+ for (String name : new String[] { StatVfsExtensionParser.NAME, FstatVfsExtensionParser.NAME}) {
+ result.add(new OpenSSHExtension(name, "2"));
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void executeExtendedCommand(Buffer buffer, int id, String extension) throws IOException {
+ if (StatVfsExtensionParser.NAME.equals(extension)
+ || FstatVfsExtensionParser.NAME.equals(extension)) {
+ String prev = extensionHolder.getAndSet(extension);
+ if (prev != null) {
+ throw new StreamCorruptedException("executeExtendedCommand(" + extension + ") previous not null: " + prev);
+ }
+
+ buffer.clear();
+ buffer.putByte((byte) SSH_FXP_EXTENDED_REPLY);
+ buffer.putInt(id);
+ OpenSSHStatExtensionInfo.encode(buffer, expected);
+ send(buffer);
+ } else {
+ super.executeExtendedCommand(buffer, id, extension);
+ }
+ }
+ };
+ }
+ }));
+
+ try(SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(SftpClient sftp = session.createSftpClient()) {
+ {
+ OpenSSHStatPathExtension pathStat = assertExtensionCreated(sftp, OpenSSHStatPathExtension.class);
+ OpenSSHStatExtensionInfo actual = pathStat.stat(srcPath);
+ String invokedExtension = extensionHolder.getAndSet(null);
+ assertEquals("Mismatched invoked extension", pathStat.getName(), invokedExtension);
+ assertOpenSSHStatExtensionInfoEquals(invokedExtension, expected, actual);
+ }
+
+ try(CloseableHandle handle = sftp.open(srcPath)) {
+ OpenSSHStatHandleExtension handleStat = assertExtensionCreated(sftp, OpenSSHStatHandleExtension.class);
+ OpenSSHStatExtensionInfo actual = handleStat.stat(handle);
+ String invokedExtension = extensionHolder.getAndSet(null);
+ assertEquals("Mismatched invoked extension", handleStat.getName(), invokedExtension);
+ assertOpenSSHStatExtensionInfoEquals(invokedExtension, expected, actual);
+ }
+ }
+ }
+ }
+ }
+
+ private static void assertOpenSSHStatExtensionInfoEquals(String extension, OpenSSHStatExtensionInfo expected, OpenSSHStatExtensionInfo actual) throws Exception {
+ Field[] fields = expected.getClass().getFields();
+ for (Field f : fields) {
+ String name = f.getName();
+ int mod = f.getModifiers();
+ if (Modifier.isStatic(mod)) {
+ continue;
+ }
+ Object expValue = f.get(expected), actValue = f.get(actual);
+ assertEquals(extension + "[" + name + "]", expValue, actValue);
+ }
+ }
+}
[2/2] mina-sshd git commit: [SSHD-516] Add support for
"space-available" extension
Posted by lg...@apache.org.
[SSHD-516] Add support for "space-available" extension
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/ea46a25d
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/ea46a25d
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/ea46a25d
Branch: refs/heads/master
Commit: ea46a25d2817c1e68cf65e5d1b6e6bd82fd8b820
Parents: adb313e
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Wed Jul 15 14:52:02 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Wed Jul 15 14:52:02 2015 +0300
----------------------------------------------------------------------
.../extensions/BuiltinSftpClientExtensions.java | 7 +
.../extensions/SpaceAvailableExtension.java | 33 +++
.../impl/SpaceAvailableExtensionImpl.java | 53 +++++
.../sshd/common/file/root/RootedFileSystem.java | 4 +
.../file/root/RootedFileSystemProvider.java | 99 ++++----
.../common/subsystem/sftp/SftpConstants.java | 1 +
.../extensions/SpaceAvailableExtensionInfo.java | 130 +++++++++++
.../server/subsystem/sftp/SftpSubsystem.java | 44 +++-
.../sftp/AbstractSftpClientTestSupport.java | 5 +-
.../sshd/client/subsystem/sftp/SftpTest.java | 50 ----
.../AbstractCheckFileExtensionTest.java | 231 ------------------
.../AbstractMD5HashExtensionTest.java | 178 --------------
.../extensions/CopyDataExtensionImplTest.java | 200 ----------------
.../impl/AbstractCheckFileExtensionTest.java | 233 +++++++++++++++++++
.../impl/AbstractMD5HashExtensionTest.java | 180 ++++++++++++++
.../impl/CopyDataExtensionImplTest.java | 201 ++++++++++++++++
.../impl/CopyFileExtensionImplTest.java | 109 +++++++++
.../impl/SpaceAvailableExtensionImplTest.java | 108 +++++++++
.../openssh/OpenSSHExtensionsTest.java | 217 -----------------
.../openssh/impl/OpenSSHExtensionsTest.java | 221 ++++++++++++++++++
20 files changed, 1372 insertions(+), 932 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/BuiltinSftpClientExtensions.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/BuiltinSftpClientExtensions.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/BuiltinSftpClientExtensions.java
index a45f7b4..21da24c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/BuiltinSftpClientExtensions.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/BuiltinSftpClientExtensions.java
@@ -32,6 +32,7 @@ import org.apache.sshd.client.subsystem.sftp.extensions.impl.CopyDataExtensionIm
import org.apache.sshd.client.subsystem.sftp.extensions.impl.CopyFileExtensionImpl;
import org.apache.sshd.client.subsystem.sftp.extensions.impl.MD5FileExtensionImpl;
import org.apache.sshd.client.subsystem.sftp.extensions.impl.MD5HandleExtensionImpl;
+import org.apache.sshd.client.subsystem.sftp.extensions.impl.SpaceAvailableExtensionImpl;
import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHFsyncExtension;
import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatHandleExtension;
import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatPathExtension;
@@ -85,6 +86,12 @@ public enum BuiltinSftpClientExtensions implements SftpClientExtensionFactory {
return new CheckFileHandleExtensionImpl(client, raw, ParserUtils.supportedExtensions(parsed));
}
},
+ SPACE_AVAILABLE(SftpConstants.EXT_SPACE_AVAILABLE, SpaceAvailableExtension.class) {
+ @Override // co-variant return
+ public SpaceAvailableExtension create(SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions, Map<String,?> parsed) {
+ return new SpaceAvailableExtensionImpl(client, raw, ParserUtils.supportedExtensions(parsed));
+ }
+ },
OPENSSH_FSYNC(FsyncExtensionParser.NAME, OpenSSHFsyncExtension.class) {
@Override // co-variant return
public OpenSSHFsyncExtension create(SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions, Map<String,?> parsed) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/SpaceAvailableExtension.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/SpaceAvailableExtension.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/SpaceAvailableExtension.java
new file mode 100644
index 0000000..bec900e
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/SpaceAvailableExtension.java
@@ -0,0 +1,33 @@
+/*
+ * 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.extensions;
+
+import java.io.IOException;
+
+import org.apache.sshd.common.subsystem.sftp.extensions.SpaceAvailableExtensionInfo;
+
+/**
+ * Implements the "space-availble" extension
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt">DRAFT 09 section 9.2</A>
+ */
+public interface SpaceAvailableExtension extends SftpClientExtension {
+ SpaceAvailableExtensionInfo available(String path) throws IOException;
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/SpaceAvailableExtensionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/SpaceAvailableExtensionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/SpaceAvailableExtensionImpl.java
new file mode 100644
index 0000000..17cc627
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/SpaceAvailableExtensionImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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.extensions.impl;
+
+import java.io.IOException;
+import java.io.StreamCorruptedException;
+import java.util.Collection;
+
+import org.apache.sshd.client.subsystem.sftp.RawSftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.extensions.SpaceAvailableExtension;
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.subsystem.sftp.extensions.SpaceAvailableExtensionInfo;
+import org.apache.sshd.common.util.buffer.Buffer;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SpaceAvailableExtensionImpl extends AbstractSftpClientExtension implements SpaceAvailableExtension {
+ public SpaceAvailableExtensionImpl(SftpClient client, RawSftpClient raw, Collection<String> extra) {
+ super(SftpConstants.EXT_SPACE_AVAILABLE, client, raw, extra);
+ }
+
+ @Override
+ public SpaceAvailableExtensionInfo available(String path) throws IOException {
+ Buffer buffer = getCommandBuffer(path);
+ buffer.putString(path);
+ buffer = checkExtendedReplyBuffer(receive(sendExtendedCommand(buffer)));
+
+ if (buffer == null) {
+ throw new StreamCorruptedException("Missing extended reply data");
+ }
+
+ return new SpaceAvailableExtensionInfo(buffer);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystem.java b/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystem.java
index 0140cfe..a9f5529 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystem.java
@@ -43,6 +43,10 @@ public class RootedFileSystem extends BaseFileSystem<RootedPath> {
this.rootFs = root.getFileSystem();
}
+ public FileSystem getRootFileSystem() {
+ return rootFs;
+ }
+
public Path getRoot() {
return rootPath;
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
index 2869417..c835868 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
@@ -34,6 +34,7 @@ import java.nio.file.FileSystem;
import java.nio.file.FileSystemAlreadyExistsException;
import java.nio.file.FileSystemException;
import java.nio.file.FileSystemNotFoundException;
+import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption;
import java.nio.file.Path;
@@ -72,46 +73,37 @@ public class RootedFileSystemProvider extends FileSystemProvider {
@Override
public FileSystem newFileSystem(URI uri, Map<String, ?> env) throws IOException {
- Path path = uriToPath(uri);
- Path localPath2 = ensureDirectory(path).toRealPath();
+ return newFileSystem(uri, uriToPath(uri), env);
+ }
+
+ @Override
+ public FileSystem getFileSystem(URI uri) {
+ return getFileSystem(uriToPath(uri));
+ }
+
+ @Override
+ public FileSystem newFileSystem(Path path, Map<String, ?> env) throws IOException {
+ return newFileSystem(path, path, env);
+ }
+ protected FileSystem newFileSystem(Object src, Path path, Map<String, ?> env) throws IOException {
+ Path root = ensureDirectory(path).toRealPath();
RootedFileSystem rootedFs=null;
synchronized (fileSystems) {
- if (!this.fileSystems.containsKey(localPath2)) {
+ if (!this.fileSystems.containsKey(root)) {
rootedFs = new RootedFileSystem(this, path, env);
- this.fileSystems.put(localPath2, rootedFs);
+ this.fileSystems.put(root, rootedFs);
}
}
// do all the throwing outside the synchronized block to minimize its lock time
if (rootedFs == null) {
- throw new FileSystemAlreadyExistsException("newFileSystem(" + uri + ") already mapped " + localPath2);
+ throw new FileSystemAlreadyExistsException("newFileSystem(" + src + ") already mapped " + root);
}
return rootedFs;
}
- @Override
- public FileSystem getFileSystem(URI uri) {
- try {
- FileSystem fileSystem = getFileSystem(uriToPath(uri));
- if (fileSystem == null) {
- throw new FileSystemNotFoundException(uri.toString());
- }
-
- return fileSystem;
- } catch(IOException e) {
- FileSystemNotFoundException err = new FileSystemNotFoundException(uri.toString());
- err.initCause(e);
- throw err;
- }
- }
-
- @Override
- public FileSystem newFileSystem(Path path, Map<String, ?> env) throws IOException {
- return new RootedFileSystem(this, ensureDirectory(path), env);
- }
-
protected Path uriToPath(URI uri) {
String scheme = uri.getScheme(), expected = getScheme();
if ((scheme == null) || (!scheme.equalsIgnoreCase(expected))) {
@@ -232,7 +224,6 @@ public class RootedFileSystemProvider extends FileSystemProvider {
Path r = unroot(link);
FileSystemProvider p = provider(r);
return root(link.getFileSystem(), p.readSymbolicLink(r));
-
}
@Override
@@ -268,34 +259,40 @@ public class RootedFileSystemProvider extends FileSystemProvider {
@Override
public FileStore getFileStore(Path path) throws IOException {
- FileSystem fileSystem = getFileSystem(path);
- if (fileSystem == null) {
- throw new FileSystemNotFoundException(path.toString());
- }
-
- Iterable<FileStore> stores = fileSystem.getFileStores();
- if (stores == null) {
- throw new FileSystemException(path.toString(), path.toString(), "No stores");
- }
-
- for (FileStore s : stores) {
- return s;
- }
-
- throw new FileSystemException(path.toString(), path.toString(), "empty stores");
+ RootedFileSystem fileSystem = getFileSystem(path);
+ Path root = fileSystem.getRoot();
+ return Files.getFileStore(root);
}
- protected RootedFileSystem getFileSystem(Path path) throws IOException {
- try {
- Path real = path.toRealPath();
- synchronized (fileSystems) {
- return fileSystems.get(real);
+ protected RootedFileSystem getFileSystem(Path path) throws FileSystemNotFoundException {
+ Path real = unroot(path, false);
+ Path rootInstance = null;
+ RootedFileSystem fsInstance = null;
+ synchronized (fileSystems) {
+ for (Map.Entry<Path,RootedFileSystem> fse : fileSystems.entrySet()) {
+ Path root = fse.getKey();
+ RootedFileSystem fs = fse.getValue();
+ if (real.equals(root)) {
+ return fs; // we were lucky to have the root
+ }
+
+ if (!real.startsWith(root)) {
+ continue;
+ }
+
+ // if already have a candidate prefer the longer match since both are prefixes of the real path
+ if ((rootInstance == null) || (rootInstance.getNameCount() < root.getNameCount())) {
+ rootInstance = root;
+ fsInstance = fs;
+ }
}
- } catch (IOException e) {
- FileSystemNotFoundException err = new FileSystemNotFoundException(path.toString());
- err.initCause(e);
- throw err;
}
+
+ if (fsInstance == null) {
+ throw new FileSystemNotFoundException(path.toString());
+ }
+
+ return fsInstance;
}
@Override
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
index e719de5..44abceb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
@@ -237,6 +237,7 @@ public final class SftpConstants {
public static final int MIN_CHKFILE_BLOCKSIZE = 256;
public static final String EXT_CHKFILE_RESPONSE = "check-file";
public static final String EXT_COPYDATA = "copy-data";
+ public static final String EXT_SPACE_AVAILABLE = "space-available";
private SftpConstants() {
throw new UnsupportedOperationException("No instance");
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/SpaceAvailableExtensionInfo.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/SpaceAvailableExtensionInfo.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/SpaceAvailableExtensionInfo.java
new file mode 100644
index 0000000..003116c
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/SpaceAvailableExtensionInfo.java
@@ -0,0 +1,130 @@
+/*
+ * 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.extensions;
+
+import java.io.IOException;
+import java.nio.file.FileStore;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt">DRAFT 09 section 9.2</A>
+ */
+public class SpaceAvailableExtensionInfo implements Cloneable {
+ public long bytesOnDevice;
+ public long unusedBytesOnDevice;
+ public long bytesAvailableToUser;
+ public long unusedBytesAvailableToUser;
+ public int bytesPerAllocationUnit;
+
+ public SpaceAvailableExtensionInfo() {
+ super();
+ }
+
+ public SpaceAvailableExtensionInfo(Buffer buffer) {
+ decode(buffer, this);
+ }
+
+ public SpaceAvailableExtensionInfo(FileStore store) throws IOException {
+ bytesOnDevice = store.getTotalSpace();
+
+ long unallocated = store.getUnallocatedSpace(), usable = store.getUsableSpace();
+ unusedBytesOnDevice = Math.max(unallocated, usable);
+
+ // the rest are intentionally left zero indicating "UNKNOWN"
+ }
+
+ @Override
+ public int hashCode() {
+ return GenericUtils.hashCode(bytesOnDevice)
+ + GenericUtils.hashCode(unusedBytesOnDevice)
+ + GenericUtils.hashCode(bytesAvailableToUser)
+ + GenericUtils.hashCode(unusedBytesAvailableToUser)
+ + bytesPerAllocationUnit
+ ;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ SpaceAvailableExtensionInfo other = (SpaceAvailableExtensionInfo) obj;
+ if ((this.bytesOnDevice == other.bytesOnDevice)
+ && (this.unusedBytesOnDevice == other.unusedBytesOnDevice)
+ && (this.bytesAvailableToUser == other.bytesAvailableToUser)
+ && (this.unusedBytesAvailableToUser == other.unusedBytesAvailableToUser)
+ && (this.bytesPerAllocationUnit == other.bytesPerAllocationUnit)) {
+ return true;
+ } else {
+ return false; // debug breakpoint
+ }
+ }
+
+ @Override
+ public SpaceAvailableExtensionInfo clone() {
+ try {
+ return getClass().cast(super.clone());
+ } catch(CloneNotSupportedException e) {
+ throw new RuntimeException("Failed to close " + toString() + ": " + e.getMessage());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "bytesOnDevice=" + bytesOnDevice
+ + ",unusedBytesOnDevice=" + unusedBytesOnDevice
+ + ",bytesAvailableToUser=" + bytesAvailableToUser
+ + ",unusedBytesAvailableToUser=" + unusedBytesAvailableToUser
+ + ",bytesPerAllocationUnit=" + bytesPerAllocationUnit
+ ;
+ }
+
+ public static SpaceAvailableExtensionInfo decode(Buffer buffer) {
+ SpaceAvailableExtensionInfo info = new SpaceAvailableExtensionInfo();
+ decode(buffer, info);
+ return info;
+ }
+
+ public static void decode(Buffer buffer, SpaceAvailableExtensionInfo info) {
+ info.bytesOnDevice = buffer.getLong();
+ info.unusedBytesOnDevice = buffer.getLong();
+ info.bytesAvailableToUser = buffer.getLong();
+ info.unusedBytesAvailableToUser = buffer.getLong();
+ info.bytesPerAllocationUnit = buffer.getInt();
+ }
+
+ public static void encode(Buffer buffer, SpaceAvailableExtensionInfo info) {
+ buffer.putLong(info.bytesOnDevice);
+ buffer.putLong(info.unusedBytesOnDevice);
+ buffer.putLong(info.bytesAvailableToUser);
+ buffer.putLong(info.unusedBytesAvailableToUser);
+ buffer.putInt(info.bytesPerAllocationUnit & 0xFFFFFFFFL);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
index 8f861ca..f840709 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
@@ -36,6 +36,7 @@ import java.nio.file.CopyOption;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.FileSystemLoopException;
import java.nio.file.FileSystems;
@@ -89,6 +90,7 @@ import org.apache.sshd.common.digest.Digest;
import org.apache.sshd.common.file.FileSystemAware;
import org.apache.sshd.common.random.Random;
import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.subsystem.sftp.extensions.SpaceAvailableExtensionInfo;
import org.apache.sshd.common.subsystem.sftp.extensions.openssh.AbstractOpenSSHExtensionParser.OpenSSHExtension;
import org.apache.sshd.common.subsystem.sftp.extensions.openssh.FsyncExtensionParser;
import org.apache.sshd.common.util.GenericUtils;
@@ -173,9 +175,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
*/
public static final Set<String> DEFAULT_SUPPORTED_CLIENT_EXTENSIONS =
// TODO text-seek - see http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-13.txt
- // TODO space-available - see http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt
// TODO home-directory - see http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt
- // TODO check-file-handle/check-file-name - see http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt section 9.1.2
Collections.unmodifiableSet(
GenericUtils.asSortedSet(String.CASE_INSENSITIVE_ORDER,
Arrays.asList(
@@ -185,7 +185,8 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
SftpConstants.EXT_MD5HASH_HANDLE,
SftpConstants.EXT_CHKFILE_HANDLE,
SftpConstants.EXT_CHKFILE_NAME,
- SftpConstants.EXT_COPYDATA
+ SftpConstants.EXT_COPYDATA,
+ SftpConstants.EXT_SPACE_AVAILABLE
)));
/**
@@ -744,6 +745,9 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
case FsyncExtensionParser.NAME:
doOpenSSHFsync(buffer, id);
break;
+ case SftpConstants.EXT_SPACE_AVAILABLE:
+ doSpaceAvailable(buffer, id);
+ break;
default:
log.info("Received unsupported SSH_FXP_EXTENDED({})", extension);
sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OP_UNSUPPORTED, "Command SSH_FXP_EXTENDED(" + extension + ") is unsupported or not implemented");
@@ -751,6 +755,40 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
}
}
+ protected void doSpaceAvailable(Buffer buffer, int id) throws IOException {
+ String path = buffer.getString();
+ SpaceAvailableExtensionInfo info;
+ try {
+ info = doSpaceAvailable(id, path);
+ } catch(IOException | RuntimeException e) {
+ sendStatus(BufferUtils.clear(buffer), id, e);
+ return;
+ }
+
+ buffer.clear();
+ buffer.putByte((byte) SSH_FXP_EXTENDED_REPLY);
+ buffer.putInt(id);
+ SpaceAvailableExtensionInfo.encode(buffer, info);
+ send(buffer);
+ }
+
+ protected SpaceAvailableExtensionInfo doSpaceAvailable(int id, String path) throws IOException {
+ Path file = resolveFile(path);
+ Path abs = file.toAbsolutePath();
+ Path nrm = abs.normalize();
+ if (log.isDebugEnabled()) {
+ log.debug("doSpaceAvailable(id={}) path={}[{}]", Integer.valueOf(id), path, nrm);
+ }
+
+ FileStore store = Files.getFileStore(nrm);
+ if (log.isTraceEnabled()) {
+ log.trace("doSpaceAvailable(id={}) path={}[{}] - {}[{}]",
+ Integer.valueOf(id), path, nrm, store.name(), store.type());
+ }
+
+ return new SpaceAvailableExtensionInfo(store);
+ }
+
protected void doTextSeek(Buffer buffer, int id) throws IOException {
String handle = buffer.getString();
long line = buffer.getLong();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClientTestSupport.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClientTestSupport.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClientTestSupport.java
index d4b7294..cb820d4 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClientTestSupport.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClientTestSupport.java
@@ -45,16 +45,17 @@ import org.apache.sshd.util.Utils;
public abstract class AbstractSftpClientTestSupport extends BaseTestSupport {
protected SshServer sshd;
protected int port;
+ protected final FileSystem rootFileSystem;
protected final FileSystemFactory fileSystemFactory;
protected AbstractSftpClientTestSupport() throws IOException {
Path targetPath = detectTargetFolder().toPath();
Path parentPath = targetPath.getParent();
- final FileSystem fileSystem = new RootedFileSystemProvider().newFileSystem(parentPath, Collections.<String,Object>emptyMap());
+ rootFileSystem = new RootedFileSystemProvider().newFileSystem(parentPath, Collections.<String,Object>emptyMap());
fileSystemFactory = new FileSystemFactory() {
@Override
public FileSystem createFileSystem(Session session) throws IOException {
- return fileSystem;
+ return rootFileSystem;
}
};
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
index 472d01a..f6e85cf 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
@@ -32,7 +32,6 @@ import java.io.OutputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
-import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.util.Collection;
import java.util.EnumSet;
@@ -44,11 +43,9 @@ import java.util.Vector;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.sshd.client.SftpException;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.client.subsystem.sftp.extensions.BuiltinSftpClientExtensions;
-import org.apache.sshd.client.subsystem.sftp.extensions.CopyFileExtension;
import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtension;
import org.apache.sshd.common.Factory;
import org.apache.sshd.common.FactoryManager;
@@ -567,53 +564,6 @@ public class SftpTest extends AbstractSftpClientTestSupport {
}
@Test
- public void testCopyFileExtension() throws Exception {
- Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName());
- Utils.deleteRecursive(lclSftp);
-
- byte[] data = (getClass().getName() + "#" + getCurrentTestName()).getBytes(StandardCharsets.UTF_8);
- Path srcFile = assertHierarchyTargetFolderExists(lclSftp).resolve("src.txt");
- Files.write(srcFile, data, IoUtils.EMPTY_OPEN_OPTIONS);
-
- Path parentPath = targetPath.getParent();
- String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
- Path dstFile = lclSftp.resolve("dst.txt");
- String dstPath = Utils.resolveRelativeRemotePath(parentPath, dstFile);
-
- LinkOption[] options = IoUtils.getLinkOptions(false);
- assertFalse("Destination file unexpectedly exists", Files.exists(dstFile, options));
-
- try(SshClient client = SshClient.setUpDefaultClient()) {
- client.start();
-
- try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
- session.addPasswordIdentity(getCurrentTestName());
- session.auth().verify(5L, TimeUnit.SECONDS);
-
- try(SftpClient sftp = session.createSftpClient()) {
- CopyFileExtension ext = assertExtensionCreated(sftp, CopyFileExtension.class);
- ext.copyFile(srcPath, dstPath, false);
- assertTrue("Source file not preserved", Files.exists(srcFile, options));
- assertTrue("Destination file not created", Files.exists(dstFile, options));
-
- byte[] actual = Files.readAllBytes(dstFile);
- assertArrayEquals("Mismatched copied data", data, actual);
-
- try {
- ext.copyFile(srcPath, dstPath, false);
- fail("Unexpected success to overwrite existing destination: " + dstFile);
- } catch(IOException e) {
- assertTrue("Not an SftpException", e instanceof SftpException);
- }
- }
- } finally {
- client.stop();
- }
- }
- }
-
- @Test
public void testServerExtensionsDeclarations() throws Exception {
try(SshClient client = SshClient.setUpDefaultClient()) {
client.start();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/AbstractCheckFileExtensionTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/AbstractCheckFileExtensionTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/AbstractCheckFileExtensionTest.java
deleted file mode 100644
index 6a075a7..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/AbstractCheckFileExtensionTest.java
+++ /dev/null
@@ -1,231 +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.client.subsystem.sftp.extensions;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.sshd.client.SftpException;
-import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.client.subsystem.sftp.AbstractSftpClientTestSupport;
-import org.apache.sshd.client.subsystem.sftp.SftpClient;
-import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.NamedResource;
-import org.apache.sshd.common.digest.BuiltinDigests;
-import org.apache.sshd.common.digest.Digest;
-import org.apache.sshd.common.subsystem.sftp.SftpConstants;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.Pair;
-import org.apache.sshd.common.util.buffer.BufferUtils;
-import org.apache.sshd.common.util.io.IoUtils;
-import org.apache.sshd.util.Utils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
-public class AbstractCheckFileExtensionTest extends AbstractSftpClientTestSupport {
- private static final Collection<Integer> DATA_SIZES =
- Collections.unmodifiableList(
- Arrays.asList(
- Integer.valueOf(Byte.MAX_VALUE),
- Integer.valueOf(SftpConstants.MIN_CHKFILE_BLOCKSIZE),
- Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
- Integer.valueOf(Byte.SIZE *IoUtils.DEFAULT_COPY_SIZE)
- ));
- private static final Collection<Integer> BLOCK_SIZES =
- Collections.unmodifiableList(
- Arrays.asList(
- Integer.valueOf(0),
- Integer.valueOf(SftpConstants.MIN_CHKFILE_BLOCKSIZE),
- Integer.valueOf(1024),
- Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE)
- ));
- @SuppressWarnings("synthetic-access")
- private static final Collection<Object[]> PARAMETERS =
- Collections.unmodifiableCollection(new LinkedList<Object[]>() {
- private static final long serialVersionUID = 1L; // we're not serializing it
-
- {
- for (NamedFactory<?> factory : BuiltinDigests.VALUES) {
- String algorithm = factory.getName();
- for (Number dataSize : DATA_SIZES) {
- for (Number blockSize : BLOCK_SIZES) {
- add(new Object[] { algorithm, dataSize, blockSize });
- }
- }
- }
- }
- });
-
- @Parameters(name = "{0} - dataSize={1}, blockSize={2}")
- public static Collection<Object[]> parameters() {
- return PARAMETERS;
- }
-
- private final String algorithm;
- private final int dataSize, blockSize;
-
- public AbstractCheckFileExtensionTest(String algorithm, int dataSize, int blockSize) throws IOException {
- this.algorithm = algorithm;
- this.dataSize = dataSize;
- this.blockSize = blockSize;
- }
-
- @Before
- public void setUp() throws Exception {
- setupServer();
- }
-
- @After
- public void tearDown() throws Exception {
- tearDownServer();
- }
-
- @Test
- public void testCheckFileExtension() throws Exception {
- testCheckFileExtension(algorithm, dataSize, blockSize);
- }
-
- private void testCheckFileExtension(String expectedAlgorithm, int inputDataSize, int hashBlockSize) throws Exception {
- NamedFactory<? extends Digest> factory = BuiltinDigests.fromFactoryName(expectedAlgorithm);
- Digest digest = null;
- if (blockSize == 0) {
- digest = factory.create();
- digest.init();
- }
-
- byte[] seed = (getClass().getName() + "#" + getCurrentTestName()
- + "-" + expectedAlgorithm
- + "-" + inputDataSize + "/" + hashBlockSize
- + System.getProperty("line.separator"))
- .getBytes(StandardCharsets.UTF_8)
- ;
-
- try(ByteArrayOutputStream baos=new ByteArrayOutputStream(inputDataSize + seed.length)) {
- while (baos.size() < inputDataSize) {
- baos.write(seed);
-
- if (digest != null) {
- digest.update(seed);
- }
- }
-
- testCheckFileExtension(factory, baos.toByteArray(), hashBlockSize, (digest == null) ? null : digest.digest());
- }
- }
-
- private void testCheckFileExtension(NamedFactory<? extends Digest> factory, byte[] data, int hashBlockSize, byte[] expectedHash) throws Exception {
- Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
- Path srcFile = assertHierarchyTargetFolderExists(lclSftp).resolve(factory.getName() + "-data-" + data.length + "-" + hashBlockSize + ".txt");
- Files.write(srcFile, data, IoUtils.EMPTY_OPEN_OPTIONS);
-
- List<String> algorithms = new ArrayList<String>(BuiltinDigests.VALUES.size());
- // put the selected algorithm 1st and then the rest
- algorithms.add(factory.getName());
- for (NamedFactory<? extends Digest> f : BuiltinDigests.VALUES) {
- if (f == factory) {
- continue;
- }
-
- algorithms.add(f.getName());
- }
-
- Path parentPath = targetPath.getParent();
- String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
- String srcFolder = Utils.resolveRelativeRemotePath(parentPath, srcFile.getParent());
-
- try(SshClient client = SshClient.setUpDefaultClient()) {
- client.start();
-
- try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
- session.addPasswordIdentity(getCurrentTestName());
- session.auth().verify(5L, TimeUnit.SECONDS);
-
- try(SftpClient sftp = session.createSftpClient()) {
- CheckFileNameExtension file = assertExtensionCreated(sftp, CheckFileNameExtension.class);
- try {
- Pair<String,?> result = file.checkFileName(srcFolder, algorithms, 0L, 0L, hashBlockSize);
- fail("Unexpected success to hash folder=" + srcFolder + ": " + result.getFirst());
- } catch(IOException e) { // expected - not allowed to hash a folder
- assertTrue("Not an SftpException", e instanceof SftpException);
- }
-
- CheckFileHandleExtension hndl = assertExtensionCreated(sftp, CheckFileHandleExtension.class);
- try(CloseableHandle dirHandle = sftp.openDir(srcFolder)) {
- try {
- Pair<String,?> result = hndl.checkFileHandle(dirHandle, algorithms, 0L, 0L, hashBlockSize);
- fail("Unexpected handle success on folder=" + srcFolder + ": " + result.getFirst());
- } catch(IOException e) { // expected - not allowed to hash a folder
- assertTrue("Not an SftpException", e instanceof SftpException);
- }
- }
-
- validateHashResult(file, file.checkFileName(srcPath, algorithms, 0L, 0L, hashBlockSize), algorithms.get(0), expectedHash);
- try(CloseableHandle fileHandle = sftp.open(srcPath, SftpClient.OpenMode.Read)) {
- validateHashResult(hndl, hndl.checkFileHandle(fileHandle, algorithms, 0L, 0L, hashBlockSize), algorithms.get(0), expectedHash);
- }
- }
- } finally {
- client.stop();
- }
- }
- }
-
- private void validateHashResult(NamedResource hasher, Pair<String,Collection<byte[]>> result, String expectedAlgorithm, byte[] expectedHash) {
- String name = hasher.getName();
- assertNotNull("No result for hash=" + name, result);
- assertEquals("Mismatched hash algorithms for " + name, expectedAlgorithm, result.getFirst());
-
- if (GenericUtils.length(expectedHash) > 0) {
- Collection<byte[]> values = result.getSecond();
- assertEquals("Mismatched hash values count for " + name, 1, GenericUtils.size(values));
-
- byte[] actualHash = values.iterator().next();
- if (!Arrays.equals(expectedHash, actualHash)) {
- fail("Mismatched hashes for " + name
- + ": expected=" + BufferUtils.printHex(':', expectedHash)
- + ", actual=" + BufferUtils.printHex(':', expectedHash));
- }
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/AbstractMD5HashExtensionTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/AbstractMD5HashExtensionTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/AbstractMD5HashExtensionTest.java
deleted file mode 100644
index 08b8b5a..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/AbstractMD5HashExtensionTest.java
+++ /dev/null
@@ -1,178 +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.client.subsystem.sftp.extensions;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.sshd.client.SftpException;
-import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.client.subsystem.sftp.AbstractSftpClientTestSupport;
-import org.apache.sshd.client.subsystem.sftp.SftpClient;
-import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
-import org.apache.sshd.common.digest.BuiltinDigests;
-import org.apache.sshd.common.digest.Digest;
-import org.apache.sshd.common.subsystem.sftp.SftpConstants;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.buffer.BufferUtils;
-import org.apache.sshd.common.util.io.IoUtils;
-import org.apache.sshd.util.Utils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
-public class AbstractMD5HashExtensionTest extends AbstractSftpClientTestSupport {
- private static final List<Integer> DATA_SIZES =
- Collections.unmodifiableList(
- Arrays.asList(
- Integer.valueOf(Byte.MAX_VALUE),
- Integer.valueOf(SftpConstants.MD5_QUICK_HASH_SIZE),
- Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
- Integer.valueOf(Byte.SIZE * IoUtils.DEFAULT_COPY_SIZE)
- ));
-
- @Parameters(name = "dataSize={0}")
- public static Collection<Object[]> parameters() {
- return parameterize(DATA_SIZES);
- }
-
- private final int size;
-
- public AbstractMD5HashExtensionTest(int size) throws IOException {
- this.size = size;
- }
-
- @Before
- public void setUp() throws Exception {
- setupServer();
- }
-
- @After
- public void tearDown() throws Exception {
- tearDownServer();
- }
-
- @Test
- public void testMD5HashExtension() throws Exception {
- testMD5HashExtension(size);
- }
-
- private void testMD5HashExtension(int dataSize) throws Exception {
- byte[] seed = (getClass().getName() + "#" + getCurrentTestName() + "-" + dataSize + System.getProperty("line.separator")).getBytes(StandardCharsets.UTF_8);
- try(ByteArrayOutputStream baos=new ByteArrayOutputStream(dataSize + seed.length)) {
- while (baos.size() < dataSize) {
- baos.write(seed);
- }
-
- testMD5HashExtension(baos.toByteArray());
- }
- }
-
- private void testMD5HashExtension(byte[] data) throws Exception {
- Digest digest = BuiltinDigests.md5.create();
- digest.init();
- digest.update(data);
-
- byte[] expectedHash = digest.digest();
- byte[] quickHash = expectedHash;
- if (data.length > SftpConstants.MD5_QUICK_HASH_SIZE) {
- byte[] quickData = new byte[SftpConstants.MD5_QUICK_HASH_SIZE];
- System.arraycopy(data, 0, quickData, 0, quickData.length);
- digest = BuiltinDigests.md5.create();
- digest.init();
- digest.update(quickData);
- quickHash = digest.digest();
- }
-
- Path targetPath = detectTargetFolder().toPath();
- Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
- Path srcFile = assertHierarchyTargetFolderExists(lclSftp).resolve("data-" + data.length + ".txt");
- Files.write(srcFile, data, IoUtils.EMPTY_OPEN_OPTIONS);
-
- Path parentPath = targetPath.getParent();
- String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
- String srcFolder = Utils.resolveRelativeRemotePath(parentPath, srcFile.getParent());
-
- try(SshClient client = SshClient.setUpDefaultClient()) {
- client.start();
-
- try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
- session.addPasswordIdentity(getCurrentTestName());
- session.auth().verify(5L, TimeUnit.SECONDS);
-
- try(SftpClient sftp = session.createSftpClient()) {
- MD5FileExtension file = assertExtensionCreated(sftp, MD5FileExtension.class);
- try {
- byte[] actual = file.getHash(srcFolder, 0L, 0L, quickHash);
- fail("Unexpected file success on folder=" + srcFolder + ": " + BufferUtils.printHex(':', actual));
- } catch(IOException e) { // expected - not allowed to hash a folder
- assertTrue("Not an SftpException for file hash on " + srcFolder, e instanceof SftpException);
- }
-
- MD5HandleExtension hndl = assertExtensionCreated(sftp, MD5HandleExtension.class);
- try(CloseableHandle dirHandle = sftp.openDir(srcFolder)) {
- try {
- byte[] actual = hndl.getHash(dirHandle, 0L, 0L, quickHash);
- fail("Unexpected handle success on folder=" + srcFolder + ": " + BufferUtils.printHex(':', actual));
- } catch(IOException e) { // expected - not allowed to hash a folder
- assertTrue("Not an SftpException for handle hash on " + srcFolder, e instanceof SftpException);
- }
- }
-
- try(CloseableHandle fileHandle = sftp.open(srcPath, SftpClient.OpenMode.Read)) {
- for (byte[] qh : new byte[][] { GenericUtils.EMPTY_BYTE_ARRAY, quickHash }) {
- for (boolean useFile : new boolean[] { true, false }) {
- byte[] actualHash = useFile ? file.getHash(srcPath, 0L, 0L, qh) : hndl.getHash(fileHandle, 0L, 0L, qh);
- String type = useFile ? file.getClass().getSimpleName() : hndl.getClass().getSimpleName();
- if (!Arrays.equals(expectedHash, actualHash)) {
- fail("Mismatched hash for quick=" + BufferUtils.printHex(':', qh)
- + " using " + type + " on " + srcFile
- + ": expected=" + BufferUtils.printHex(':', expectedHash)
- + ", actual=" + BufferUtils.printHex(':', actualHash));
- }
- }
- }
- }
- }
- } finally {
- client.stop();
- }
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/CopyDataExtensionImplTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/CopyDataExtensionImplTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/CopyDataExtensionImplTest.java
deleted file mode 100644
index afea6df..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/CopyDataExtensionImplTest.java
+++ /dev/null
@@ -1,200 +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.client.subsystem.sftp.extensions;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.client.subsystem.sftp.AbstractSftpClientTestSupport;
-import org.apache.sshd.client.subsystem.sftp.SftpClient;
-import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
-import org.apache.sshd.common.Factory;
-import org.apache.sshd.common.random.Random;
-import org.apache.sshd.common.subsystem.sftp.SftpConstants;
-import org.apache.sshd.common.util.io.IoUtils;
-import org.apache.sshd.util.Utils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.MethodSorters;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
-public class CopyDataExtensionImplTest extends AbstractSftpClientTestSupport {
- private static final List<Object[]> PARAMETERS =
- Collections.unmodifiableList(
- Arrays.<Object[]>asList(
- new Object[] {
- Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
- Integer.valueOf(0),
- Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
- Long.valueOf(0L)
- },
- new Object[] {
- Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
- Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE / 2),
- Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE / 4),
- Long.valueOf(0L)
- },
- new Object[] {
- Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
- Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE / 2),
- Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE / 4),
- Long.valueOf(IoUtils.DEFAULT_COPY_SIZE / 2)
- },
- new Object[] {
- Integer.valueOf(Byte.MAX_VALUE),
- Integer.valueOf(Byte.MAX_VALUE / 2),
- Integer.valueOf(Byte.MAX_VALUE), // attempt to read more than available
- Long.valueOf(0L)
- }
- ));
-
- @Parameters(name = "size={0}, readOffset={1}, readLength={2}, writeOffset={3}")
- public static Collection<Object[]> parameters() {
- return PARAMETERS;
- }
-
- private int size, srcOffset, length;
- private long dstOffset;
-
- public CopyDataExtensionImplTest(int size, int srcOffset, int length, long dstOffset) throws IOException {
- this.size = size;
- this.srcOffset = srcOffset;
- this.length = length;
- this.dstOffset = dstOffset;
- }
-
- @Before
- public void setUp() throws Exception {
- setupServer();
- }
-
- @After
- public void tearDown() throws Exception {
- tearDownServer();
- }
-
- @Test
- public void testCopyDataExtension() throws Exception {
- testCopyDataExtension(size, srcOffset, length, dstOffset);
- }
-
- private void testCopyDataExtension(int dataSize, int readOffset, int readLength, long writeOffset) throws Exception {
- byte[] seed = (getClass().getName() + "#" + getCurrentTestName()
- + "-" + dataSize
- + "-" + readOffset + "/" + readLength + "/" + writeOffset
- + System.getProperty("line.separator"))
- .getBytes(StandardCharsets.UTF_8)
- ;
- try(ByteArrayOutputStream baos=new ByteArrayOutputStream(dataSize + seed.length)) {
- while (baos.size() < dataSize) {
- baos.write(seed);
- }
-
- testCopyDataExtension(baos.toByteArray(), readOffset, readLength, writeOffset);
- }
- }
-
- private void testCopyDataExtension(byte[] data, int readOffset, int readLength, long writeOffset) throws Exception {
- Path targetPath = detectTargetFolder().toPath();
- Path parentPath = targetPath.getParent();
- Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
- LinkOption[] options = IoUtils.getLinkOptions(false);
- String baseName = readOffset + "-" + readLength + "-" + writeOffset;
- Path srcFile = assertHierarchyTargetFolderExists(lclSftp, options).resolve(baseName + "-src.txt");
- Files.write(srcFile, data, IoUtils.EMPTY_OPEN_OPTIONS);
- String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
-
- Path dstFile = srcFile.getParent().resolve(baseName + "-dst.txt");
- if (Files.exists(dstFile, options)) {
- Files.delete(dstFile);
- }
- String dstPath = Utils.resolveRelativeRemotePath(parentPath, dstFile);
-
- try(SshClient client = SshClient.setUpDefaultClient()) {
- client.start();
-
- if (writeOffset > 0L) {
- Factory<? extends Random> factory = client.getRandomFactory();
- Random randomizer = factory.create();
- long totalLength = writeOffset + readLength;
- byte[] workBuf = new byte[(int) Math.min(totalLength, IoUtils.DEFAULT_COPY_SIZE)];
- try(OutputStream output = Files.newOutputStream(dstFile, IoUtils.EMPTY_OPEN_OPTIONS)) {
- while(totalLength > 0L) {
- randomizer.fill(workBuf);
- output.write(workBuf);
- totalLength -= workBuf.length;
- }
- }
- }
-
- try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
- session.addPasswordIdentity(getCurrentTestName());
- session.auth().verify(5L, TimeUnit.SECONDS);
-
- try(SftpClient sftp = session.createSftpClient()) {
- CopyDataExtension ext = assertExtensionCreated(sftp, CopyDataExtension.class);
- try(CloseableHandle readHandle = sftp.open(srcPath, SftpClient.OpenMode.Read);
- CloseableHandle writeHandle = sftp.open(dstPath, SftpClient.OpenMode.Write, SftpClient.OpenMode.Create)) {
- ext.copyData(readHandle, readOffset, readLength, writeHandle, writeOffset);
- }
- }
- } finally {
- client.stop();
- }
- }
-
- int available = data.length, required = readOffset + readLength;
- if (required > available) {
- required = available;
- }
- byte[] expected = new byte[required - readOffset];
- System.arraycopy(data, readOffset, expected, 0, expected.length);
-
- byte[] actual = new byte[expected.length];
- try(FileChannel channel = FileChannel.open(dstFile, IoUtils.EMPTY_OPEN_OPTIONS)) {
- int readLen = channel.read(ByteBuffer.wrap(actual), writeOffset);
- assertEquals("Mismatched read data size", expected.length, readLen);
- }
- assertArrayEquals("Mismatched copy data", expected, actual);
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractCheckFileExtensionTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractCheckFileExtensionTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractCheckFileExtensionTest.java
new file mode 100644
index 0000000..5662cf7
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractCheckFileExtensionTest.java
@@ -0,0 +1,233 @@
+/*
+ * 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.extensions.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.client.SftpException;
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.subsystem.sftp.AbstractSftpClientTestSupport;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
+import org.apache.sshd.client.subsystem.sftp.extensions.CheckFileHandleExtension;
+import org.apache.sshd.client.subsystem.sftp.extensions.CheckFileNameExtension;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.digest.BuiltinDigests;
+import org.apache.sshd.common.digest.Digest;
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Pair;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+public class AbstractCheckFileExtensionTest extends AbstractSftpClientTestSupport {
+ private static final Collection<Integer> DATA_SIZES =
+ Collections.unmodifiableList(
+ Arrays.asList(
+ Integer.valueOf(Byte.MAX_VALUE),
+ Integer.valueOf(SftpConstants.MIN_CHKFILE_BLOCKSIZE),
+ Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
+ Integer.valueOf(Byte.SIZE *IoUtils.DEFAULT_COPY_SIZE)
+ ));
+ private static final Collection<Integer> BLOCK_SIZES =
+ Collections.unmodifiableList(
+ Arrays.asList(
+ Integer.valueOf(0),
+ Integer.valueOf(SftpConstants.MIN_CHKFILE_BLOCKSIZE),
+ Integer.valueOf(1024),
+ Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE)
+ ));
+ @SuppressWarnings("synthetic-access")
+ private static final Collection<Object[]> PARAMETERS =
+ Collections.unmodifiableCollection(new LinkedList<Object[]>() {
+ private static final long serialVersionUID = 1L; // we're not serializing it
+
+ {
+ for (NamedFactory<?> factory : BuiltinDigests.VALUES) {
+ String algorithm = factory.getName();
+ for (Number dataSize : DATA_SIZES) {
+ for (Number blockSize : BLOCK_SIZES) {
+ add(new Object[] { algorithm, dataSize, blockSize });
+ }
+ }
+ }
+ }
+ });
+
+ @Parameters(name = "{0} - dataSize={1}, blockSize={2}")
+ public static Collection<Object[]> parameters() {
+ return PARAMETERS;
+ }
+
+ private final String algorithm;
+ private final int dataSize, blockSize;
+
+ public AbstractCheckFileExtensionTest(String algorithm, int dataSize, int blockSize) throws IOException {
+ this.algorithm = algorithm;
+ this.dataSize = dataSize;
+ this.blockSize = blockSize;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ setupServer();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ tearDownServer();
+ }
+
+ @Test
+ public void testCheckFileExtension() throws Exception {
+ testCheckFileExtension(algorithm, dataSize, blockSize);
+ }
+
+ private void testCheckFileExtension(String expectedAlgorithm, int inputDataSize, int hashBlockSize) throws Exception {
+ NamedFactory<? extends Digest> factory = BuiltinDigests.fromFactoryName(expectedAlgorithm);
+ Digest digest = null;
+ if (blockSize == 0) {
+ digest = factory.create();
+ digest.init();
+ }
+
+ byte[] seed = (getClass().getName() + "#" + getCurrentTestName()
+ + "-" + expectedAlgorithm
+ + "-" + inputDataSize + "/" + hashBlockSize
+ + System.getProperty("line.separator"))
+ .getBytes(StandardCharsets.UTF_8)
+ ;
+
+ try(ByteArrayOutputStream baos=new ByteArrayOutputStream(inputDataSize + seed.length)) {
+ while (baos.size() < inputDataSize) {
+ baos.write(seed);
+
+ if (digest != null) {
+ digest.update(seed);
+ }
+ }
+
+ testCheckFileExtension(factory, baos.toByteArray(), hashBlockSize, (digest == null) ? null : digest.digest());
+ }
+ }
+
+ private void testCheckFileExtension(NamedFactory<? extends Digest> factory, byte[] data, int hashBlockSize, byte[] expectedHash) throws Exception {
+ Path targetPath = detectTargetFolder().toPath();
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
+ Path srcFile = assertHierarchyTargetFolderExists(lclSftp).resolve(factory.getName() + "-data-" + data.length + "-" + hashBlockSize + ".txt");
+ Files.write(srcFile, data, IoUtils.EMPTY_OPEN_OPTIONS);
+
+ List<String> algorithms = new ArrayList<String>(BuiltinDigests.VALUES.size());
+ // put the selected algorithm 1st and then the rest
+ algorithms.add(factory.getName());
+ for (NamedFactory<? extends Digest> f : BuiltinDigests.VALUES) {
+ if (f == factory) {
+ continue;
+ }
+
+ algorithms.add(f.getName());
+ }
+
+ Path parentPath = targetPath.getParent();
+ String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
+ String srcFolder = Utils.resolveRelativeRemotePath(parentPath, srcFile.getParent());
+
+ try(SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(SftpClient sftp = session.createSftpClient()) {
+ CheckFileNameExtension file = assertExtensionCreated(sftp, CheckFileNameExtension.class);
+ try {
+ Pair<String,?> result = file.checkFileName(srcFolder, algorithms, 0L, 0L, hashBlockSize);
+ fail("Unexpected success to hash folder=" + srcFolder + ": " + result.getFirst());
+ } catch(IOException e) { // expected - not allowed to hash a folder
+ assertTrue("Not an SftpException", e instanceof SftpException);
+ }
+
+ CheckFileHandleExtension hndl = assertExtensionCreated(sftp, CheckFileHandleExtension.class);
+ try(CloseableHandle dirHandle = sftp.openDir(srcFolder)) {
+ try {
+ Pair<String,?> result = hndl.checkFileHandle(dirHandle, algorithms, 0L, 0L, hashBlockSize);
+ fail("Unexpected handle success on folder=" + srcFolder + ": " + result.getFirst());
+ } catch(IOException e) { // expected - not allowed to hash a folder
+ assertTrue("Not an SftpException", e instanceof SftpException);
+ }
+ }
+
+ validateHashResult(file, file.checkFileName(srcPath, algorithms, 0L, 0L, hashBlockSize), algorithms.get(0), expectedHash);
+ try(CloseableHandle fileHandle = sftp.open(srcPath, SftpClient.OpenMode.Read)) {
+ validateHashResult(hndl, hndl.checkFileHandle(fileHandle, algorithms, 0L, 0L, hashBlockSize), algorithms.get(0), expectedHash);
+ }
+ }
+ } finally {
+ client.stop();
+ }
+ }
+ }
+
+ private void validateHashResult(NamedResource hasher, Pair<String,Collection<byte[]>> result, String expectedAlgorithm, byte[] expectedHash) {
+ String name = hasher.getName();
+ assertNotNull("No result for hash=" + name, result);
+ assertEquals("Mismatched hash algorithms for " + name, expectedAlgorithm, result.getFirst());
+
+ if (GenericUtils.length(expectedHash) > 0) {
+ Collection<byte[]> values = result.getSecond();
+ assertEquals("Mismatched hash values count for " + name, 1, GenericUtils.size(values));
+
+ byte[] actualHash = values.iterator().next();
+ if (!Arrays.equals(expectedHash, actualHash)) {
+ fail("Mismatched hashes for " + name
+ + ": expected=" + BufferUtils.printHex(':', expectedHash)
+ + ", actual=" + BufferUtils.printHex(':', expectedHash));
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ea46a25d/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractMD5HashExtensionTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractMD5HashExtensionTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractMD5HashExtensionTest.java
new file mode 100644
index 0000000..87f1510
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractMD5HashExtensionTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.extensions.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.client.SftpException;
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.subsystem.sftp.AbstractSftpClientTestSupport;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
+import org.apache.sshd.client.subsystem.sftp.extensions.MD5FileExtension;
+import org.apache.sshd.client.subsystem.sftp.extensions.MD5HandleExtension;
+import org.apache.sshd.common.digest.BuiltinDigests;
+import org.apache.sshd.common.digest.Digest;
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+public class AbstractMD5HashExtensionTest extends AbstractSftpClientTestSupport {
+ private static final List<Integer> DATA_SIZES =
+ Collections.unmodifiableList(
+ Arrays.asList(
+ Integer.valueOf(Byte.MAX_VALUE),
+ Integer.valueOf(SftpConstants.MD5_QUICK_HASH_SIZE),
+ Integer.valueOf(IoUtils.DEFAULT_COPY_SIZE),
+ Integer.valueOf(Byte.SIZE * IoUtils.DEFAULT_COPY_SIZE)
+ ));
+
+ @Parameters(name = "dataSize={0}")
+ public static Collection<Object[]> parameters() {
+ return parameterize(DATA_SIZES);
+ }
+
+ private final int size;
+
+ public AbstractMD5HashExtensionTest(int size) throws IOException {
+ this.size = size;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ setupServer();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ tearDownServer();
+ }
+
+ @Test
+ public void testMD5HashExtension() throws Exception {
+ testMD5HashExtension(size);
+ }
+
+ private void testMD5HashExtension(int dataSize) throws Exception {
+ byte[] seed = (getClass().getName() + "#" + getCurrentTestName() + "-" + dataSize + System.getProperty("line.separator")).getBytes(StandardCharsets.UTF_8);
+ try(ByteArrayOutputStream baos=new ByteArrayOutputStream(dataSize + seed.length)) {
+ while (baos.size() < dataSize) {
+ baos.write(seed);
+ }
+
+ testMD5HashExtension(baos.toByteArray());
+ }
+ }
+
+ private void testMD5HashExtension(byte[] data) throws Exception {
+ Digest digest = BuiltinDigests.md5.create();
+ digest.init();
+ digest.update(data);
+
+ byte[] expectedHash = digest.digest();
+ byte[] quickHash = expectedHash;
+ if (data.length > SftpConstants.MD5_QUICK_HASH_SIZE) {
+ byte[] quickData = new byte[SftpConstants.MD5_QUICK_HASH_SIZE];
+ System.arraycopy(data, 0, quickData, 0, quickData.length);
+ digest = BuiltinDigests.md5.create();
+ digest.init();
+ digest.update(quickData);
+ quickHash = digest.digest();
+ }
+
+ Path targetPath = detectTargetFolder().toPath();
+ Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName());
+ Path srcFile = assertHierarchyTargetFolderExists(lclSftp).resolve("data-" + data.length + ".txt");
+ Files.write(srcFile, data, IoUtils.EMPTY_OPEN_OPTIONS);
+
+ Path parentPath = targetPath.getParent();
+ String srcPath = Utils.resolveRelativeRemotePath(parentPath, srcFile);
+ String srcFolder = Utils.resolveRelativeRemotePath(parentPath, srcFile.getParent());
+
+ try(SshClient client = SshClient.setUpDefaultClient()) {
+ client.start();
+
+ try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
+ session.addPasswordIdentity(getCurrentTestName());
+ session.auth().verify(5L, TimeUnit.SECONDS);
+
+ try(SftpClient sftp = session.createSftpClient()) {
+ MD5FileExtension file = assertExtensionCreated(sftp, MD5FileExtension.class);
+ try {
+ byte[] actual = file.getHash(srcFolder, 0L, 0L, quickHash);
+ fail("Unexpected file success on folder=" + srcFolder + ": " + BufferUtils.printHex(':', actual));
+ } catch(IOException e) { // expected - not allowed to hash a folder
+ assertTrue("Not an SftpException for file hash on " + srcFolder, e instanceof SftpException);
+ }
+
+ MD5HandleExtension hndl = assertExtensionCreated(sftp, MD5HandleExtension.class);
+ try(CloseableHandle dirHandle = sftp.openDir(srcFolder)) {
+ try {
+ byte[] actual = hndl.getHash(dirHandle, 0L, 0L, quickHash);
+ fail("Unexpected handle success on folder=" + srcFolder + ": " + BufferUtils.printHex(':', actual));
+ } catch(IOException e) { // expected - not allowed to hash a folder
+ assertTrue("Not an SftpException for handle hash on " + srcFolder, e instanceof SftpException);
+ }
+ }
+
+ try(CloseableHandle fileHandle = sftp.open(srcPath, SftpClient.OpenMode.Read)) {
+ for (byte[] qh : new byte[][] { GenericUtils.EMPTY_BYTE_ARRAY, quickHash }) {
+ for (boolean useFile : new boolean[] { true, false }) {
+ byte[] actualHash = useFile ? file.getHash(srcPath, 0L, 0L, qh) : hndl.getHash(fileHandle, 0L, 0L, qh);
+ String type = useFile ? file.getClass().getSimpleName() : hndl.getClass().getSimpleName();
+ if (!Arrays.equals(expectedHash, actualHash)) {
+ fail("Mismatched hash for quick=" + BufferUtils.printHex(':', qh)
+ + " using " + type + " on " + srcFile
+ + ": expected=" + BufferUtils.printHex(':', expectedHash)
+ + ", actual=" + BufferUtils.printHex(':', actualHash));
+ }
+ }
+ }
+ }
+ }
+ } finally {
+ client.stop();
+ }
+ }
+ }
+}