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 10:09:52 UTC
mina-sshd git commit: [SSHD-524] Add support for
"statvfs/fstatvs@openssh.com" client SFTP extensions
Repository: mina-sshd
Updated Branches:
refs/heads/master 5da0d1a86 -> adb313ebc
[SSHD-524] Add support for "statvfs/fstatvs@openssh.com" client SFTP extensions
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/adb313eb
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/adb313eb
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/adb313eb
Branch: refs/heads/master
Commit: adb313ebc66262e47f40b045e500a5d691741b5e
Parents: 5da0d1a
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Wed Jul 15 11:09:40 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Wed Jul 15 11:09:40 2015 +0300
----------------------------------------------------------------------
.../sshd/client/subsystem/sftp/SftpClient.java | 4 +
.../sshd/client/subsystem/sftp/SftpCommand.java | 42 +++-
.../extensions/BuiltinSftpClientExtensions.java | 18 ++
.../impl/AbstractCheckFileExtension.java | 11 +-
.../impl/AbstractMD5HashExtension.java | 8 +-
.../impl/AbstractSftpClientExtension.java | 57 +++++
.../openssh/OpenSSHStatExtensionInfo.java | 160 ++++++++++++++
.../openssh/OpenSSHStatHandleExtension.java | 33 +++
.../openssh/OpenSSHStatPathExtension.java | 33 +++
.../AbstractOpenSSHStatCommandExtension.java | 57 +++++
.../openssh/impl/OpenSSHFsyncExtensionImpl.java | 2 +-
.../impl/OpenSSHStatHandleExtensionImpl.java | 44 ++++
.../impl/OpenSSHStatPathExtensionImpl.java | 43 ++++
.../apache/sshd/common/util/GenericUtils.java | 6 +
.../server/subsystem/sftp/SftpSubsystem.java | 66 ++++--
.../sshd/client/subsystem/sftp/SftpTest.java | 12 +-
.../sftp/extensions/OpenSSHExtensionsTest.java | 92 --------
.../openssh/OpenSSHExtensionsTest.java | 217 +++++++++++++++++++
18 files changed, 770 insertions(+), 135 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java
index fb73149..9a9a12b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java
@@ -81,6 +81,10 @@ public interface SftpClient extends SubsystemClient {
this.id = ValidateUtils.checkNotNullAndNotEmpty(id, "No handle ID", GenericUtils.EMPTY_OBJECT_ARRAY).clone();
}
+ public int length() {
+ return id.length;
+ }
+
/**
* @return A <U>cloned</U> instance of the identifier in order to
* avoid inadvertent modifications to the handle contents
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java
index 64e7578..1371d7d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpCommand.java
@@ -23,6 +23,8 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
import java.nio.channels.Channel;
import java.util.Arrays;
import java.util.Collections;
@@ -31,8 +33,11 @@ import java.util.TreeMap;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatExtensionInfo;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatPathExtension;
import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.subsystem.sftp.extensions.ParserUtils;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.StatVfsExtensionParser;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.BufferUtils;
@@ -160,7 +165,7 @@ public class SftpCommand implements Channel {
public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
String[] comps = GenericUtils.split(args, ' ');
// ignore all flag
- String pathArg = GenericUtils.isEmpty(comps) ? null : comps[comps.length - 1];
+ String pathArg = GenericUtils.isEmpty(comps) ? null : GenericUtils.trimToEmpty(comps[comps.length - 1]);
String cwd = getCurrentRemoteDirectory();
if (GenericUtils.isEmpty(pathArg) || (pathArg.charAt(0) == '-')) {
pathArg = cwd;
@@ -220,8 +225,8 @@ public class SftpCommand implements Channel {
String[] comps = GenericUtils.split(args, ' ');
ValidateUtils.checkTrue(GenericUtils.length(comps) == 2, "Invalid number of arguments: %s", args);
- String oldPath = resolveRemotePath(comps[0]);
- String newPath = resolveRemotePath(comps[1]);
+ String oldPath = resolveRemotePath(GenericUtils.trimToEmpty(comps[0]));
+ String newPath = resolveRemotePath(GenericUtils.trimToEmpty(comps[1]));
SftpClient sftp = getClient();
sftp.rename(oldPath, newPath);
return false;
@@ -230,6 +235,37 @@ public class SftpCommand implements Channel {
new CommandExecutor() {
@Override
public String getName() {
+ return StatVfsExtensionParser.NAME;
+ }
+
+ @Override
+ public boolean executeCommand(String args, BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
+ String[] comps = GenericUtils.split(args, ' ');
+ ValidateUtils.checkTrue(GenericUtils.length(comps) == 1, "Invalid number of arguments: %s", args);
+
+ SftpClient sftp = getClient();
+ OpenSSHStatPathExtension ext = sftp.getExtension(OpenSSHStatPathExtension.class);
+ ValidateUtils.checkTrue(ext.isSupported(), "Extension not supported by server: %s", ext.getName());
+
+ OpenSSHStatExtensionInfo info = ext.stat(GenericUtils.trimToEmpty(comps[0]));
+ Field[] fields = info.getClass().getFields();
+ for (Field f : fields) {
+ String name = f.getName();
+ int mod = f.getModifiers();
+ if (Modifier.isStatic(mod)) {
+ continue;
+ }
+
+ Object value = f.get(info);
+ stdout.append('\t').append(name).append(": ").println(value);
+ }
+
+ return false;
+ }
+ },
+ new CommandExecutor() {
+ @Override
+ public String getName() {
return "help";
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/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 f1db773..a45f7b4 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
@@ -33,11 +33,17 @@ import org.apache.sshd.client.subsystem.sftp.extensions.impl.CopyFileExtensionIm
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.openssh.OpenSSHFsyncExtension;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatHandleExtension;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatPathExtension;
import org.apache.sshd.client.subsystem.sftp.extensions.openssh.impl.OpenSSHFsyncExtensionImpl;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.impl.OpenSSHStatHandleExtensionImpl;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.impl.OpenSSHStatPathExtensionImpl;
import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.subsystem.sftp.SftpConstants;
import org.apache.sshd.common.subsystem.sftp.extensions.ParserUtils;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.FstatVfsExtensionParser;
import org.apache.sshd.common.subsystem.sftp.extensions.openssh.FsyncExtensionParser;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.StatVfsExtensionParser;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -84,6 +90,18 @@ public enum BuiltinSftpClientExtensions implements SftpClientExtensionFactory {
public OpenSSHFsyncExtension create(SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions, Map<String,?> parsed) {
return new OpenSSHFsyncExtensionImpl(client, raw, extensions);
}
+ },
+ OPENSSH_STAT_HANDLE(FstatVfsExtensionParser.NAME, OpenSSHStatHandleExtension.class) {
+ @Override // co-variant return
+ public OpenSSHStatHandleExtension create(SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions, Map<String,?> parsed) {
+ return new OpenSSHStatHandleExtensionImpl(client, raw, extensions);
+ }
+ },
+ OPENSSH_STAT_PATH(StatVfsExtensionParser.NAME, OpenSSHStatPathExtension.class) {
+ @Override // co-variant return
+ public OpenSSHStatPathExtension create(SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions, Map<String,?> parsed) {
+ return new OpenSSHStatPathExtensionImpl(client, raw, extensions);
+ }
};
private final String name;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractCheckFileExtension.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractCheckFileExtension.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractCheckFileExtension.java
index d5bb304..fa4ca35 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractCheckFileExtension.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractCheckFileExtension.java
@@ -41,13 +41,8 @@ public abstract class AbstractCheckFileExtension extends AbstractSftpClientExten
}
protected Pair<String,Collection<byte[]>> doGetHash(Object target, Collection<String> algorithms, long offset, long length, int blockSize) throws IOException {
- Buffer buffer = getCommandBuffer(Byte.MAX_VALUE);
- String opcode = getName();
- if (target instanceof CharSequence) {
- buffer.putString(target.toString());
- } else {
- buffer.putBytes((byte[]) target);
- }
+ Buffer buffer = getCommandBuffer(target, Byte.MAX_VALUE);
+ putTarget(buffer, target);
buffer.putString(GenericUtils.join(algorithms, ','));
buffer.putLong(offset);
buffer.putLong(length);
@@ -55,7 +50,7 @@ public abstract class AbstractCheckFileExtension extends AbstractSftpClientExten
if (log.isDebugEnabled()) {
log.debug("doGetHash({})[{}] - offset={}, length={}, block-size={}",
- opcode, (target instanceof CharSequence) ? target : BufferUtils.printHex(BufferUtils.EMPTY_HEX_SEPARATOR, (byte[]) target),
+ getName(), (target instanceof CharSequence) ? target : BufferUtils.printHex(BufferUtils.EMPTY_HEX_SEPARATOR, (byte[]) target),
Long.valueOf(offset), Long.valueOf(length), Integer.valueOf(blockSize));
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractMD5HashExtension.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractMD5HashExtension.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractMD5HashExtension.java
index 03d5350..8c8a5d5 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractMD5HashExtension.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractMD5HashExtension.java
@@ -38,13 +38,9 @@ public abstract class AbstractMD5HashExtension extends AbstractSftpClientExtensi
}
protected byte[] doGetHash(Object target, long offset, long length, byte[] quickHash) throws IOException {
- Buffer buffer = getCommandBuffer(Long.SIZE + 2 * (Long.SIZE / Byte.SIZE) + (Integer.SIZE / Byte.SIZE) + GenericUtils.length(quickHash));
+ Buffer buffer = getCommandBuffer(target, Long.SIZE + 2 * (Long.SIZE / Byte.SIZE) + (Integer.SIZE / Byte.SIZE) + GenericUtils.length(quickHash));
String opcode = getName();
- if (target instanceof CharSequence) {
- buffer.putString(target.toString());
- } else {
- buffer.putBytes((byte[]) target);
- }
+ putTarget(buffer, target);
buffer.putLong(offset);
buffer.putLong(length);
buffer.putBytes((quickHash == null) ? GenericUtils.EMPTY_BYTE_ARRAY : quickHash);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractSftpClientExtension.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractSftpClientExtension.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractSftpClientExtension.java
index 0778c2c..a7eb6d0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractSftpClientExtension.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractSftpClientExtension.java
@@ -22,10 +22,12 @@ package org.apache.sshd.client.subsystem.sftp.extensions.impl;
import java.io.IOException;
import java.io.StreamCorruptedException;
import java.util.Collection;
+import java.util.Map;
import org.apache.sshd.client.SftpException;
import org.apache.sshd.client.subsystem.sftp.RawSftpClient;
import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient.Handle;
import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtension;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.subsystem.sftp.SftpConstants;
@@ -48,6 +50,10 @@ public abstract class AbstractSftpClientExtension extends AbstractLoggingBean im
this(name, client, raw, GenericUtils.isEmpty(extras) ? false : extras.contains(name));
}
+ protected AbstractSftpClientExtension(String name, SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions) {
+ this(name, client, raw, GenericUtils.isEmpty(extensions) ? false : extensions.containsKey(name));
+ }
+
protected AbstractSftpClientExtension(String name, SftpClient client, RawSftpClient raw, boolean supported) {
this.name = ValidateUtils.checkNotNullAndNotEmpty(name, "No extension name", GenericUtils.EMPTY_OBJECT_ARRAY);
this.client = ValidateUtils.checkNotNull(client, "No client instance", GenericUtils.EMPTY_OBJECT_ARRAY);
@@ -99,6 +105,57 @@ public abstract class AbstractSftpClientExtension extends AbstractLoggingBean im
}
/**
+ * @param buffer The {@link Buffer}
+ * @param target A target path {@link String} or {@link Handle} or {@code byte[])
+ * to be encoded in the buffer
+ * @return The updated buffer
+ * @throws UnsupportedOperationException If target is not one of the above
+ * supported types
+ */
+ public Buffer putTarget(Buffer buffer, Object target) {
+ if (target instanceof CharSequence) {
+ buffer.putString(target.toString());
+ } else if (target instanceof byte[]) {
+ buffer.putBytes((byte[]) target);
+ } else if (target instanceof Handle) {
+ buffer.putBytes(((Handle) target).getIdentifier());
+ } else {
+ throw new UnsupportedOperationException("Unknown target type: " + target);
+ }
+
+ return buffer;
+ }
+
+ /**
+ * @param target A target path {@link String} or {@link Handle} or {@code byte[])
+ * to be encoded in the buffer
+ * @return A {@link Buffer} with the extension name set
+ * @see #getCommandBuffer(Object, int)
+ */
+ protected Buffer getCommandBuffer(Object target) {
+ return getCommandBuffer(target, 0);
+ }
+
+ /**
+ * @param target A target path {@link String} or {@link Handle} or {@code byte[])
+ * to be encoded in the buffer
+ * @param extraSize Extra size - beyond the path/handle to be allocated
+ * @return A {@link Buffer} with the extension name set
+ * @see #getCommandBuffer(int)
+ */
+ protected Buffer getCommandBuffer(Object target, int extraSize) {
+ if (target instanceof CharSequence) {
+ return getCommandBuffer((Integer.SIZE / Byte.SIZE) + ((CharSequence) target).length() + extraSize);
+ } else if (target instanceof byte[]) {
+ return getCommandBuffer((Integer.SIZE / Byte.SIZE) + ((byte[]) target).length + extraSize);
+ } else if (target instanceof Handle) {
+ return getCommandBuffer((Integer.SIZE / Byte.SIZE) + ((Handle) target).length() + extraSize);
+ } else {
+ return getCommandBuffer(extraSize);
+ }
+ }
+
+ /**
* @param extraSize Extra size - besides the extension name
* @return A {@link Buffer} with the extension name set
*/
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHStatExtensionInfo.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHStatExtensionInfo.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHStatExtensionInfo.java
new file mode 100644
index 0000000..6213505
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHStatExtensionInfo.java
@@ -0,0 +1,160 @@
+/*
+ * 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 org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+
+/**
+ * Response for the "statvfs@openssh.com" and "fstatvfs@openssh.com"
+ * extension commands.
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/usr.bin/ssh/PROTOCOL?rev=1.28&content-type=text/plain">OpenSSH section 3.4</A>
+ */
+public class OpenSSHStatExtensionInfo implements Cloneable {
+ // The values of the f_flag bitmask
+ public static final long SSH_FXE_STATVFS_ST_RDONLY = 0x1; /* read-only */
+ public static final long SSH_FXE_STATVFS_ST_NOSUID = 0x2; /* no setuid */
+
+ public long f_bsize; /* file system block size */
+ public long f_frsize; /* fundamental fs block size */
+ public long f_blocks; /* number of blocks (unit f_frsize) */
+ public long f_bfree; /* free blocks in file system */
+ public long f_bavail; /* free blocks for non-root */
+ public long f_files; /* total file inodes */
+ public long f_ffree; /* free file inodes */
+ public long f_favail; /* free file inodes for to non-root */
+ public long f_fsid; /* file system id */
+ public long f_flag; /* bit mask of f_flag values */
+ public long f_namemax; /* maximum filename length */
+
+ public OpenSSHStatExtensionInfo() {
+ super();
+ }
+
+ public OpenSSHStatExtensionInfo(Buffer buffer) {
+ decode(buffer, this);
+ }
+
+ @Override
+ public int hashCode() {
+ return GenericUtils.hashCode(this.f_bsize)
+ + GenericUtils.hashCode(this.f_frsize)
+ + GenericUtils.hashCode(this.f_blocks)
+ + GenericUtils.hashCode(this.f_bfree)
+ + GenericUtils.hashCode(this.f_bavail)
+ + GenericUtils.hashCode(this.f_files)
+ + GenericUtils.hashCode(this.f_ffree)
+ + GenericUtils.hashCode(this.f_favail)
+ + GenericUtils.hashCode(this.f_fsid)
+ + GenericUtils.hashCode(this.f_flag)
+ + GenericUtils.hashCode(this.f_namemax)
+ ;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ OpenSSHStatExtensionInfo other = (OpenSSHStatExtensionInfo) obj;
+ if ((this.f_bsize == other.f_bsize)
+ && (this.f_frsize == other.f_frsize)
+ && (this.f_blocks == other.f_blocks)
+ && (this.f_bfree == other.f_bfree)
+ && (this.f_bavail == other.f_bavail)
+ && (this.f_files == other.f_files)
+ && (this.f_ffree == other.f_ffree)
+ && (this.f_favail == other.f_favail)
+ && (this.f_fsid == other.f_fsid)
+ && (this.f_flag == other.f_flag)
+ && (this.f_namemax == other.f_namemax)) {
+ return true;
+ } else {
+ return false; // debug breakpoint
+ }
+ }
+
+ @Override
+ public OpenSSHStatExtensionInfo clone() {
+ try {
+ return getClass().cast(super.clone());
+ } catch(CloneNotSupportedException e) {
+ throw new RuntimeException("Failed to close " + toString() + ": " + e.getMessage());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "f_bsize=" + f_bsize
+ + ",f_frsize=" + f_frsize
+ + ",f_blocks=" + f_blocks
+ + ",f_bfree=" + f_bfree
+ + ",f_bavail=" + f_bavail
+ + ",f_files=" + f_files
+ + ",f_ffree=" + f_ffree
+ + ",f_favail=" + f_favail
+ + ",f_fsid=" + f_fsid
+ + ",f_flag=0x" + Long.toHexString(f_flag)
+ + ",f_namemax=" + f_namemax
+ ;
+ }
+
+ public static void encode(Buffer buffer, OpenSSHStatExtensionInfo info) {
+ buffer.putLong(info.f_bsize);
+ buffer.putLong(info.f_frsize);
+ buffer.putLong(info.f_blocks);
+ buffer.putLong(info.f_bfree);
+ buffer.putLong(info.f_bavail);
+ buffer.putLong(info.f_files);
+ buffer.putLong(info.f_ffree);
+ buffer.putLong(info.f_favail);
+ buffer.putLong(info.f_fsid);
+ buffer.putLong(info.f_flag);
+ buffer.putLong(info.f_namemax);
+ }
+
+ public static OpenSSHStatExtensionInfo decode(Buffer buffer) {
+ OpenSSHStatExtensionInfo info = new OpenSSHStatExtensionInfo();
+ decode(buffer, info);
+ return info;
+ }
+
+ public static void decode(Buffer buffer, OpenSSHStatExtensionInfo info) {
+ info.f_bsize = buffer.getLong();
+ info.f_frsize = buffer.getLong();
+ info.f_blocks = buffer.getLong();
+ info.f_bfree = buffer.getLong();
+ info.f_bavail = buffer.getLong();
+ info.f_files = buffer.getLong();
+ info.f_ffree = buffer.getLong();
+ info.f_favail = buffer.getLong();
+ info.f_fsid = buffer.getLong();
+ info.f_flag = buffer.getLong();
+ info.f_namemax = buffer.getLong();
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHStatHandleExtension.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHStatHandleExtension.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHStatHandleExtension.java
new file mode 100644
index 0000000..e36067e
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHStatHandleExtension.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.openssh;
+
+import java.io.IOException;
+
+import org.apache.sshd.client.subsystem.sftp.SftpClient.Handle;
+import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtension;
+
+/**
+ * Implements the "fstatvfs@openssh.com" extension command
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface OpenSSHStatHandleExtension extends SftpClientExtension {
+ OpenSSHStatExtensionInfo stat(Handle handle) throws IOException;
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHStatPathExtension.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHStatPathExtension.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHStatPathExtension.java
new file mode 100644
index 0000000..a2450af
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHStatPathExtension.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.openssh;
+
+import java.io.IOException;
+
+import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtension;
+
+/**
+ * Implements the "statvfs@openssh.com" extension command
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/usr.bin/ssh/PROTOCOL?rev=1.28&content-type=text/plain">OpenSSH section 3.4</A>
+ */
+public interface OpenSSHStatPathExtension extends SftpClientExtension {
+ OpenSSHStatExtensionInfo stat(String path) throws IOException;
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/AbstractOpenSSHStatCommandExtension.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/AbstractOpenSSHStatCommandExtension.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/AbstractOpenSSHStatCommandExtension.java
new file mode 100644
index 0000000..51b6817
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/AbstractOpenSSHStatCommandExtension.java
@@ -0,0 +1,57 @@
+/*
+ * 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 java.io.IOException;
+import java.io.StreamCorruptedException;
+import java.util.Map;
+
+import org.apache.sshd.client.subsystem.sftp.RawSftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.extensions.impl.AbstractSftpClientExtension;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatExtensionInfo;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractOpenSSHStatCommandExtension extends AbstractSftpClientExtension {
+ protected AbstractOpenSSHStatCommandExtension(String name, SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions) {
+ super(name, client, raw, extensions);
+ }
+
+ protected OpenSSHStatExtensionInfo doGetStat(Object target) throws IOException {
+ Buffer buffer = getCommandBuffer(target);
+ putTarget(buffer, target);
+
+ if (log.isDebugEnabled()) {
+ log.debug("doGetStat({})[{}]", getName(),
+ (target instanceof CharSequence) ? target : BufferUtils.printHex(BufferUtils.EMPTY_HEX_SEPARATOR, (byte[]) target));
+ }
+
+ buffer = checkExtendedReplyBuffer(receive(sendExtendedCommand(buffer)));
+ if (buffer == null) {
+ throw new StreamCorruptedException("Missing extended reply data");
+ }
+
+ return new OpenSSHStatExtensionInfo(buffer);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHFsyncExtensionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHFsyncExtensionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHFsyncExtensionImpl.java
index a6cfabd..5032fc0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHFsyncExtensionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHFsyncExtensionImpl.java
@@ -36,7 +36,7 @@ import org.apache.sshd.common.util.buffer.Buffer;
*/
public class OpenSSHFsyncExtensionImpl extends AbstractSftpClientExtension implements OpenSSHFsyncExtension {
public OpenSSHFsyncExtensionImpl(SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions) {
- super(FsyncExtensionParser.NAME, client, raw, (GenericUtils.size(extensions) > 0) && extensions.containsKey(FsyncExtensionParser.NAME));
+ super(FsyncExtensionParser.NAME, client, raw, extensions);
}
@Override
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHStatHandleExtensionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHStatHandleExtensionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHStatHandleExtensionImpl.java
new file mode 100644
index 0000000..ec0ab90
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHStatHandleExtensionImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.client.subsystem.sftp.extensions.openssh.impl;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.sshd.client.subsystem.sftp.RawSftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient.Handle;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatExtensionInfo;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatHandleExtension;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.FstatVfsExtensionParser;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class OpenSSHStatHandleExtensionImpl extends AbstractOpenSSHStatCommandExtension implements OpenSSHStatHandleExtension {
+ public OpenSSHStatHandleExtensionImpl(SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions) {
+ super(FstatVfsExtensionParser.NAME, client, raw, extensions);
+ }
+
+ @Override
+ public OpenSSHStatExtensionInfo stat(Handle handle) throws IOException {
+ return doGetStat(handle.getIdentifier());
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHStatPathExtensionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHStatPathExtensionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHStatPathExtensionImpl.java
new file mode 100644
index 0000000..7ed085c
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHStatPathExtensionImpl.java
@@ -0,0 +1,43 @@
+/*
+ * 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 java.io.IOException;
+import java.util.Map;
+
+import org.apache.sshd.client.subsystem.sftp.RawSftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatExtensionInfo;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatPathExtension;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.StatVfsExtensionParser;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class OpenSSHStatPathExtensionImpl extends AbstractOpenSSHStatCommandExtension implements OpenSSHStatPathExtension {
+ public OpenSSHStatPathExtensionImpl(SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions) {
+ super(StatVfsExtensionParser.NAME, client, raw, extensions);
+ }
+
+ @Override
+ public OpenSSHStatExtensionInfo stat(String path) throws IOException {
+ return doGetStat(path);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
index fd3cefb..568019d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
@@ -415,4 +415,10 @@ public final class GenericUtils {
current.addSuppressed(extra);
return current;
}
+
+ // TODO in JDK-8 use Long.hashCode(long)
+ public static int hashCode(long value) {
+ return (int)(value ^ (value >>> 32));
+ }
+
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/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 a12811f..8f861ca 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
@@ -201,6 +201,18 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
new OpenSSHExtension(FsyncExtensionParser.NAME, "1")
));
+ public static final List<String> DEFAULT_OPEN_SSH_EXTENSIONS_NAMES =
+ Collections.unmodifiableList(new ArrayList<String>(DEFAULT_OPEN_SSH_EXTENSIONS.size()) {
+ private static final long serialVersionUID = 1L; // we're not serializing it
+
+ {
+ for (OpenSSHExtension ext : DEFAULT_OPEN_SSH_EXTENSIONS) {
+ add(ext.getName());
+ }
+ }
+
+ });
+
static {
StringBuilder sb = new StringBuilder(2 * (1 + (HIGHER_SFTP_IMPL - LOWER_SFTP_IMPL)));
for (int v = LOWER_SFTP_IMPL; v <= HIGHER_SFTP_IMPL; v++) {
@@ -2179,30 +2191,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
}
protected List<OpenSSHExtension> appendOpenSSHExtensions(Buffer buffer) {
- String value = FactoryManagerUtils.getString(session, OPENSSH_EXTENSIONS_PROP);
- List<OpenSSHExtension> extList=Collections.emptyList();
- if (value != null) {
- String[] pairs = GenericUtils.split(value, ',');
- int numExts = GenericUtils.length(pairs);
- if (numExts > 0) {
- extList = new ArrayList<OpenSSHExtension>(numExts);
- for (String nvp : pairs) {
- nvp = GenericUtils.trimToEmpty(nvp);
- if (GenericUtils.isEmpty(nvp)) {
- continue;
- }
-
- int pos = nvp.indexOf('=');
- ValidateUtils.checkTrue((pos > 0) && (pos < (nvp.length() - 1)), "Malformed OpenSSH extension spec: %s", nvp);
- String name = GenericUtils.trimToEmpty(nvp.substring(0, pos));
- String version = GenericUtils.trimToEmpty(nvp.substring(pos + 1));
- extList.add(new OpenSSHExtension(name, ValidateUtils.checkNotNullAndNotEmpty(version, "No version specified for OpenSSH extension %s", name)));
- }
- }
- } else {
- extList = DEFAULT_OPEN_SSH_EXTENSIONS;
- }
-
+ List<OpenSSHExtension> extList = resolveOpenSSHExtensions();
if (GenericUtils.isEmpty(extList)) {
return extList;
}
@@ -2215,6 +2204,35 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
return extList;
}
+ protected List<OpenSSHExtension> resolveOpenSSHExtensions() {
+ String value = FactoryManagerUtils.getString(session, OPENSSH_EXTENSIONS_PROP);
+ if (value == null) { // No override
+ return DEFAULT_OPEN_SSH_EXTENSIONS;
+ }
+
+ String[] pairs = GenericUtils.split(value, ',');
+ int numExts = GenericUtils.length(pairs);
+ if (numExts <= 0) { // User does not want to report ANY extensions
+ return Collections.emptyList();
+ }
+
+ List<OpenSSHExtension> extList = new ArrayList<OpenSSHExtension>(numExts);
+ for (String nvp : pairs) {
+ nvp = GenericUtils.trimToEmpty(nvp);
+ if (GenericUtils.isEmpty(nvp)) {
+ continue;
+ }
+
+ int pos = nvp.indexOf('=');
+ ValidateUtils.checkTrue((pos > 0) && (pos < (nvp.length() - 1)), "Malformed OpenSSH extension spec: %s", nvp);
+ String name = GenericUtils.trimToEmpty(nvp.substring(0, pos));
+ String version = GenericUtils.trimToEmpty(nvp.substring(pos + 1));
+ extList.add(new OpenSSHExtension(name, ValidateUtils.checkNotNullAndNotEmpty(version, "No version specified for OpenSSH extension %s", name)));
+ }
+
+ return extList;
+ }
+
protected Collection<String> getSupportedClientExtensions() {
String value = FactoryManagerUtils.getString(session, CLIENT_EXTENSIONS_PROP);
if (value == null) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/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 d39a6f3..472d01a 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
@@ -655,10 +655,20 @@ public class SftpTest extends AbstractSftpClientTestSupport {
for (BuiltinSftpClientExtensions type : BuiltinSftpClientExtensions.VALUES) {
String extensionName = type.getName();
+ boolean isOpenSSHExtension = extensionName.endsWith("@openssh.com");
SftpClientExtension instance = sftp.getExtension(extensionName);
+
assertNotNull("Extension not implemented:" + extensionName, instance);
assertEquals("Mismatched instance name", extensionName, instance.getName());
- assertTrue("Extension not supported: " + extensionName, instance.isSupported());
+
+ if (instance.isSupported()) {
+ if (isOpenSSHExtension) {
+ assertTrue("Unlisted default OpenSSH extension: " + extensionName, SftpSubsystem.DEFAULT_OPEN_SSH_EXTENSIONS_NAMES.contains(extensionName));
+ }
+ } else {
+ assertTrue("Unsupported non-OpenSSH extension: " + extensionName, isOpenSSHExtension);
+ assertFalse("Unsupported default OpenSSH extension: " + extensionName, SftpSubsystem.DEFAULT_OPEN_SSH_EXTENSIONS_NAMES.contains(extensionName));
+ }
}
}
} finally {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/OpenSSHExtensionsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/OpenSSHExtensionsTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/OpenSSHExtensionsTest.java
deleted file mode 100644
index 8b019a9..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/OpenSSHExtensionsTest.java
+++ /dev/null
@@ -1,92 +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.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-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.openssh.OpenSSHFsyncExtension;
-import org.apache.sshd.common.subsystem.sftp.SftpConstants;
-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();
- }
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/adb313eb/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
new file mode 100644
index 0000000..f44aaf3
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHExtensionsTest.java
@@ -0,0 +1,217 @@
+/*
+ * 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);
+ }
+ }
+}