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/12 08:37:25 UTC
mina-sshd git commit: [SSHD-536] Add support for SFTP
fsync@openssh.com extension
Repository: mina-sshd
Updated Branches:
refs/heads/master e08cbe1aa -> 45549d1e8
[SSHD-536] Add support for SFTP fsync@openssh.com 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/45549d1e
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/45549d1e
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/45549d1e
Branch: refs/heads/master
Commit: 45549d1e85151fa6986f62c2dc2375d475fdafb1
Parents: e08cbe1
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Sun Jul 12 09:37:13 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Sun Jul 12 09:37:13 2015 +0300
----------------------------------------------------------------------
.../sshd/client/subsystem/sftp/SftpCommand.java | 2 +-
.../extensions/BuiltinSftpClientExtensions.java | 9 ++
.../impl/AbstractCheckFileExtension.java | 4 +-
.../impl/AbstractMD5HashExtension.java | 4 +-
.../impl/AbstractSftpClientExtension.java | 12 ++
.../extensions/impl/CopyDataExtensionImpl.java | 11 +-
.../extensions/impl/CopyFileExtensionImpl.java | 9 +-
.../openssh/OpenSSHFsyncExtension.java | 34 ++++++
.../openssh/impl/OpenSSHFsyncExtensionImpl.java | 49 ++++++++
.../subsystem/sftp/extensions/ParserUtils.java | 14 ++-
.../openssh/AbstractOpenSSHExtensionParser.java | 115 +++++++++++++++++++
.../openssh/FstatVfsExtensionParser.java | 32 ++++++
.../openssh/FsyncExtensionParser.java | 33 ++++++
.../openssh/HardLinkExtensionParser.java | 33 ++++++
.../openssh/PosixRenameExtensionParser.java | 33 ++++++
.../openssh/StatVfsExtensionParser.java | 33 ++++++
.../server/subsystem/sftp/SftpSubsystem.java | 97 +++++++++++++++-
.../sshd/client/subsystem/sftp/SftpTest.java | 12 +-
.../sftp/extensions/OpenSSHExtensionsTest.java | 95 +++++++++++++++
19 files changed, 604 insertions(+), 27 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/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 4a7f783..64e7578 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
@@ -88,7 +88,7 @@ public class SftpCommand implements Channel {
ValidateUtils.checkTrue(GenericUtils.isEmpty(args), "Unexpected arguments: %s", args);
SftpClient sftp = getClient();
Map<String,byte[]> extensions = sftp.getServerExtensions();
- Map<String,?> parsed = ParserUtils.parse(null);
+ Map<String,?> parsed = ParserUtils.parse(extensions);
for (Map.Entry<String,byte[]> ee : extensions.entrySet()) {
String name = ee.getKey();
byte[] value = ee.getValue();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/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 467ef78..f1db773 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,9 +32,12 @@ 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.openssh.OpenSSHFsyncExtension;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.impl.OpenSSHFsyncExtensionImpl;
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.FsyncExtensionParser;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -75,6 +78,12 @@ public enum BuiltinSftpClientExtensions implements SftpClientExtensionFactory {
public CheckFileHandleExtension create(SftpClient client, RawSftpClient raw, Map<String,byte[]> extensions, Map<String,?> parsed) {
return new CheckFileHandleExtensionImpl(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) {
+ return new OpenSSHFsyncExtensionImpl(client, raw, extensions);
+ }
};
private final String name;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/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 a31f8e5..d5bb304 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
@@ -31,7 +31,6 @@ import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.Pair;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferUtils;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -42,9 +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 = new ByteArrayBuffer();
+ Buffer buffer = getCommandBuffer(Byte.MAX_VALUE);
String opcode = getName();
- buffer.putString(opcode);
if (target instanceof CharSequence) {
buffer.putString(target.toString());
} else {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/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 b7c138b..03d5350 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
@@ -28,7 +28,6 @@ import org.apache.sshd.client.subsystem.sftp.SftpClient;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferUtils;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -39,9 +38,8 @@ public abstract class AbstractMD5HashExtension extends AbstractSftpClientExtensi
}
protected byte[] doGetHash(Object target, long offset, long length, byte[] quickHash) throws IOException {
- Buffer buffer = new ByteArrayBuffer();
+ Buffer buffer = getCommandBuffer(Long.SIZE + 2 * (Long.SIZE / Byte.SIZE) + (Integer.SIZE / Byte.SIZE) + GenericUtils.length(quickHash));
String opcode = getName();
- buffer.putString(opcode);
if (target instanceof CharSequence) {
buffer.putString(target.toString());
} else {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/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 14eef9c..0778c2c 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
@@ -32,6 +32,7 @@ import org.apache.sshd.common.subsystem.sftp.SftpConstants;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
@@ -98,6 +99,17 @@ public abstract class AbstractSftpClientExtension extends AbstractLoggingBean im
}
/**
+ * @param extraSize Extra size - besides the extension name
+ * @return A {@link Buffer} with the extension name set
+ */
+ protected Buffer getCommandBuffer(int extraSize) {
+ String opcode = getName();
+ Buffer buffer = new ByteArrayBuffer((Integer.SIZE / Byte.SIZE) + GenericUtils.length(opcode) + extraSize + Byte.SIZE);
+ buffer.putString(opcode);
+ return buffer;
+ }
+
+ /**
* @param buffer The {@link Buffer} to check
* @return The {@link Buffer} if this is an {@link SftpConstants#SSH_FXP_EXTENDED_REPLY},
* or {@code null} if this is a {@link SftpConstants#SSH_FXP_STATUS} carrying
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImpl.java
index 8d28bbb..318d813 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyDataExtensionImpl.java
@@ -29,7 +29,6 @@ import org.apache.sshd.client.subsystem.sftp.extensions.CopyDataExtension;
import org.apache.sshd.common.subsystem.sftp.SftpConstants;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -42,13 +41,9 @@ public class CopyDataExtensionImpl extends AbstractSftpClientExtension implement
@Override
public void copyData(Handle readHandle, long readOffset, long readLength, Handle writeHandle, long writeOffset) throws IOException {
byte[] srcId = readHandle.getIdentifier(), dstId = writeHandle.getIdentifier();
- String opcode = getName();
- Buffer buffer = new ByteArrayBuffer((Integer.SIZE / Byte.SIZE) + GenericUtils.length(opcode)
- + (Integer.SIZE / Byte.SIZE) + GenericUtils.length(srcId)
- + (Integer.SIZE / Byte.SIZE) + GenericUtils.length(dstId)
- + (3 * (Long.SIZE + (Integer.SIZE / Byte.SIZE)))
- + Byte.SIZE);
- buffer.putString(opcode);
+ Buffer buffer = getCommandBuffer((Integer.SIZE / Byte.SIZE) + GenericUtils.length(srcId)
+ + (Integer.SIZE / Byte.SIZE) + GenericUtils.length(dstId)
+ + (3 * (Long.SIZE + (Integer.SIZE / Byte.SIZE))));
buffer.putBytes(srcId);
buffer.putLong(readOffset);
buffer.putLong(readLength);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyFileExtensionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyFileExtensionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyFileExtensionImpl.java
index 7186df6..28d7b18 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyFileExtensionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/CopyFileExtensionImpl.java
@@ -28,7 +28,6 @@ import org.apache.sshd.client.subsystem.sftp.extensions.CopyFileExtension;
import org.apache.sshd.common.subsystem.sftp.SftpConstants;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
-import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -40,11 +39,9 @@ public class CopyFileExtensionImpl extends AbstractSftpClientExtension implement
@Override
public void copyFile(String src, String dst, boolean overwriteDestination) throws IOException {
- Buffer buffer = new ByteArrayBuffer((Integer.SIZE / Byte.SIZE) + GenericUtils.length(getName())
- + (Integer.SIZE / Byte.SIZE) + GenericUtils.length(src)
- + (Integer.SIZE / Byte.SIZE) + GenericUtils.length(dst)
- + 1 /* override destination */);
- buffer.putString(getName());
+ Buffer buffer = getCommandBuffer((Integer.SIZE / Byte.SIZE) + GenericUtils.length(src)
+ + (Integer.SIZE / Byte.SIZE) + GenericUtils.length(dst)
+ + 1 /* override destination */);
buffer.putString(src);
buffer.putString(dst);
buffer.putBoolean(overwriteDestination);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHFsyncExtension.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHFsyncExtension.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHFsyncExtension.java
new file mode 100644
index 0000000..fdfc05b
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/OpenSSHFsyncExtension.java
@@ -0,0 +1,34 @@
+/*
+ * 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 "fsync@openssh.com" extension
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="https://github.com/openssh/openssh-portable/blob/master/PROTOCOL">OpenSSH</A> section 10
+ */
+public interface OpenSSHFsyncExtension extends SftpClientExtension {
+ void fsync(Handle fileHandle) throws IOException;
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/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
new file mode 100644
index 0000000..a6cfabd
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHFsyncExtensionImpl.java
@@ -0,0 +1,49 @@
+/*
+ * 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.impl.AbstractSftpClientExtension;
+import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHFsyncExtension;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.FsyncExtensionParser;
+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>
+ */
+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));
+ }
+
+ @Override
+ public void fsync(Handle fileHandle) throws IOException {
+ byte[] handle = fileHandle.getIdentifier();
+ Buffer buffer = getCommandBuffer((Integer.SIZE / Byte.SIZE) + GenericUtils.length(handle));
+ buffer.putBytes(handle);
+ sendAndCheckExtendedCommandStatus(buffer);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java
index f883c89..94c7151 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java
@@ -31,11 +31,17 @@ import java.util.TreeSet;
import org.apache.sshd.common.subsystem.sftp.extensions.Supported2Parser.Supported2;
import org.apache.sshd.common.subsystem.sftp.extensions.SupportedParser.Supported;
+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.HardLinkExtensionParser;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.PosixRenameExtensionParser;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.StatVfsExtensionParser;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="https://github.com/openssh/openssh-portable/blob/master/PROTOCOL">OpenSSH</A> section 3.4
*/
public final class ParserUtils {
public static final Collection<ExtensionParser<?>> BUILT_IN_PARSERS =
@@ -45,7 +51,13 @@ public final class ParserUtils {
NewlineParser.INSTANCE,
VersionsParser.INSTANCE,
SupportedParser.INSTANCE,
- Supported2Parser.INSTANCE
+ Supported2Parser.INSTANCE,
+ // OpenSSH extensions
+ PosixRenameExtensionParser.INSTANCE,
+ StatVfsExtensionParser.INSTANCE,
+ FstatVfsExtensionParser.INSTANCE,
+ HardLinkExtensionParser.INSTANCE,
+ FsyncExtensionParser.INSTANCE
));
private static final Map<String,ExtensionParser<?>> parsersMap = new TreeMap<String,ExtensionParser<?>>(String.CASE_INSENSITIVE_ORDER) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java
new file mode 100644
index 0000000..0b3735c
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java
@@ -0,0 +1,115 @@
+/*
+ * 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.openssh;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.subsystem.sftp.extensions.AbstractParser;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.AbstractOpenSSHExtensionParser.OpenSSHExtension;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * Base class for various {@code XXX@openssh.com} extension data reports
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractOpenSSHExtensionParser extends AbstractParser<OpenSSHExtension> {
+ public static class OpenSSHExtension implements NamedResource, Cloneable {
+ private final String name;
+ private String version;
+
+ public OpenSSHExtension(String name) {
+ this(name, null);
+ }
+
+ public OpenSSHExtension(String name, String version) {
+ this.name = ValidateUtils.checkNotNullAndNotEmpty(name, "No extension name", GenericUtils.EMPTY_OBJECT_ARRAY);
+ this.version = version;
+ }
+
+ @Override
+ public final String getName() {
+ return name;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getName(), getVersion());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ OpenSSHExtension other = (OpenSSHExtension) obj;
+ if (Objects.equals(getName(), other.getName())
+ && Objects.equals(getVersion(), other.getVersion())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public OpenSSHExtension clone() {
+ try {
+ return getClass().cast(super.clone());
+ } catch(CloneNotSupportedException e) {
+ throw new RuntimeException("Unexpected clone exception: " + e.getLocalizedMessage());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getName() + " " + getVersion();
+ }
+ }
+
+ protected AbstractOpenSSHExtensionParser(String name) {
+ super(name);
+ }
+
+ @Override
+ public OpenSSHExtension parse(byte[] input, int offset, int len) {
+ return parse(new String(input, offset, len, StandardCharsets.UTF_8));
+ }
+
+ public OpenSSHExtension parse(String version) {
+ return new OpenSSHExtension(getName(), version);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FstatVfsExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FstatVfsExtensionParser.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FstatVfsExtensionParser.java
new file mode 100644
index 0000000..88eaa61
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FstatVfsExtensionParser.java
@@ -0,0 +1,32 @@
+/*
+ * 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.openssh;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class FstatVfsExtensionParser extends AbstractOpenSSHExtensionParser {
+ public static final String NAME = "fstatvfs@openssh.com";
+ public static final FstatVfsExtensionParser INSTANCE = new FstatVfsExtensionParser();
+
+ public FstatVfsExtensionParser() {
+ super(NAME);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FsyncExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FsyncExtensionParser.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FsyncExtensionParser.java
new file mode 100644
index 0000000..e8dbd38
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FsyncExtensionParser.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.common.subsystem.sftp.extensions.openssh;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="https://github.com/openssh/openssh-portable/blob/master/PROTOCOL">OpenSSH</A> section 10
+ */
+public class FsyncExtensionParser extends AbstractOpenSSHExtensionParser {
+ public static final String NAME = "fsync@openssh.com";
+ public static final FsyncExtensionParser INSTANCE = new FsyncExtensionParser();
+
+ public FsyncExtensionParser() {
+ super(NAME);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/HardLinkExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/HardLinkExtensionParser.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/HardLinkExtensionParser.java
new file mode 100644
index 0000000..2bbfb02
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/HardLinkExtensionParser.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.common.subsystem.sftp.extensions.openssh;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="https://github.com/openssh/openssh-portable/blob/master/PROTOCOL">OpenSSH</A> section 10
+ */
+public class HardLinkExtensionParser extends AbstractOpenSSHExtensionParser {
+ public static final String NAME = "hardlink@openssh.com";
+ public static final HardLinkExtensionParser INSTANCE = new HardLinkExtensionParser();
+
+ public HardLinkExtensionParser() {
+ super(NAME);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/PosixRenameExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/PosixRenameExtensionParser.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/PosixRenameExtensionParser.java
new file mode 100644
index 0000000..9871914
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/PosixRenameExtensionParser.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.common.subsystem.sftp.extensions.openssh;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="https://github.com/openssh/openssh-portable/blob/master/PROTOCOL">OpenSSH</A> section 3.3
+ */
+public class PosixRenameExtensionParser extends AbstractOpenSSHExtensionParser {
+ public static final String NAME = "posix-rename@openssh.com";
+ public static final PosixRenameExtensionParser INSTANCE = new PosixRenameExtensionParser();
+
+ public PosixRenameExtensionParser() {
+ super(NAME);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/StatVfsExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/StatVfsExtensionParser.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/StatVfsExtensionParser.java
new file mode 100644
index 0000000..83f4b03
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/StatVfsExtensionParser.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.common.subsystem.sftp.extensions.openssh;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="https://github.com/openssh/openssh-portable/blob/master/PROTOCOL">OpenSSH</A> section 3.4
+ */
+public class StatVfsExtensionParser extends AbstractOpenSSHExtensionParser {
+ public static final String NAME = "statvfs@openssh.com";
+ public static final StatVfsExtensionParser INSTANCE = new StatVfsExtensionParser();
+
+ public StatVfsExtensionParser() {
+ super(NAME);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/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 3f1bb4c..add23fe 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
@@ -88,6 +88,8 @@ 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.openssh.FsyncExtensionParser;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.AbstractOpenSSHExtensionParser.OpenSSHExtension;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.Int2IntFunction;
import org.apache.sshd.common.util.OsUtils;
@@ -184,6 +186,19 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
SftpConstants.EXT_COPYDATA
)));
+ /**
+ * Comma-separated list of which {@code OpenSSH} extensions are reported and
+ * what version is reported for each - format: {@code name=version}. If empty
+ * value set, then no such extensions are reported. Otherwise, the
+ * {@link DEFAULT_OPEN_SSH_EXTENSIONS} are used
+ */
+ public static final String OPENSSH_EXTENSIONS_PROP = "sftp-openssh-extensions";
+ public static final List<OpenSSHExtension> DEFAULT_OPEN_SSH_EXTENSIONS =
+ Collections.unmodifiableList(
+ Arrays.asList(
+ new OpenSSHExtension(FsyncExtensionParser.NAME, "1")
+ ));
+
static {
StringBuilder sb = new StringBuilder(2 * (1 + (HIGHER_SFTP_IMPL - LOWER_SFTP_IMPL)));
for (int v = LOWER_SFTP_IMPL; v <= HIGHER_SFTP_IMPL; v++) {
@@ -313,7 +328,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
protected class FileHandle extends Handle {
private final int access;
- private final FileChannel channel;
+ private final FileChannel fileChannel;
private long pos;
private final List<FileLock> locks = new ArrayList<>();
@@ -373,10 +388,14 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
channel = FileChannel.open(file, options);
setAttributes(file, attrs);
}
- this.channel = channel;
+ this.fileChannel = channel;
this.pos = 0;
}
+ public final FileChannel getFileChannel() {
+ return fileChannel;
+ }
+
public int getAccessMask() {
return access;
}
@@ -386,6 +405,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
}
public int read(byte[] data, int doff, int length, long offset) throws IOException {
+ FileChannel channel = getFileChannel();
if (pos != offset) {
channel.position(offset);
pos = offset;
@@ -400,6 +420,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
}
public void write(byte[] data, int doff, int length, long offset) throws IOException {
+ FileChannel channel = getFileChannel();
if (pos != offset) {
channel.position(offset);
pos = offset;
@@ -410,11 +431,13 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
@Override
public void close() throws IOException {
+ FileChannel channel = getFileChannel();
channel.close();
}
public void lock(long offset, long length, int mask) throws IOException {
- long size = length == 0 ? channel.size() - offset : length;
+ FileChannel channel = getFileChannel();
+ long size = (length == 0L) ? channel.size() - offset : length;
FileLock lock = channel.tryLock(offset, size, false);
synchronized (locks) {
locks.add(lock);
@@ -422,7 +445,8 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
}
public boolean unlock(long offset, long length) throws IOException {
- long size = length == 0 ? channel.size() - offset : length;
+ FileChannel channel = getFileChannel();
+ long size = (length == 0) ? channel.size() - offset : length;
FileLock lock = null;
for (Iterator<FileLock> iterator = locks.iterator(); iterator.hasNext();) {
FileLock l = iterator.next();
@@ -703,6 +727,9 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
case SftpConstants.EXT_CHKFILE_NAME:
doCheckFileHash(buffer, id, extension);
break;
+ case FsyncExtensionParser.NAME:
+ doOpenSSHFsync(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");
@@ -734,6 +761,30 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
throw new UnsupportedOperationException("doTextSeek(" + fileHandle + ")");
}
+ // see https://github.com/openssh/openssh-portable/blob/master/PROTOCOL section 10
+ protected void doOpenSSHFsync(Buffer buffer, int id) throws IOException {
+ String handle = buffer.getString();
+ try {
+ doOpenSSHFsync(id, handle);
+ } catch(IOException | RuntimeException e) {
+ sendStatus(BufferUtils.clear(buffer), id, e);
+ return;
+ }
+
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
+ }
+
+ protected void doOpenSSHFsync(int id, String handle) throws IOException {
+ Handle h = handles.get(handle);
+ if (log.isDebugEnabled()) {
+ log.debug("doOpenSSHFsync({})[{}]", handle, h);
+ }
+
+ FileHandle fileHandle = validateHandle(handle, h, FileHandle.class);
+ FileChannel channel = fileHandle.getFileChannel();
+ channel.force(false);
+ }
+
protected void doCheckFileHash(Buffer buffer, int id, String targetType) throws IOException {
String target = buffer.getString();
String algList = buffer.getString();
@@ -2091,6 +2142,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
appendVersionsExtension(buffer, supportedVersions);
appendNewlineExtension(buffer, System.getProperty("line.separator"));
appendVendorIdExtension(buffer, VersionProperties.getVersionProperties());
+ appendOpenSSHExtensions(buffer);
/* TODO updateAvailableExtensions(extensions, appendAclSupportedExtension(...)
buffer.putString("acl-supported");
@@ -2104,6 +2156,43 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
appendSupported2Extension(buffer, extras);
}
+ 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;
+ }
+
+ if (GenericUtils.isEmpty(extList)) {
+ return extList;
+ }
+
+ for (OpenSSHExtension ext : extList) {
+ buffer.putString(ext.getName());
+ buffer.putString(ext.getVersion());
+ }
+
+ 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/45549d1e/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 f975d25..81d1525 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
@@ -57,6 +57,7 @@ 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.Supported2Parser.Supported2;
import org.apache.sshd.common.subsystem.sftp.extensions.SupportedParser.Supported;
+import org.apache.sshd.common.subsystem.sftp.extensions.openssh.AbstractOpenSSHExtensionParser.OpenSSHExtension;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
@@ -579,7 +580,16 @@ public class SftpTest extends AbstractSftpClientTestSupport {
assertSupportedExtensions(extName, ((Supported2) extValue).extensionNames);
}
}
-
+
+ for (OpenSSHExtension expected : SftpSubsystem.DEFAULT_OPEN_SSH_EXTENSIONS) {
+ String name = expected.getName();
+ Object value = data.get(name);
+ assertNotNull("OpenSSH extension not declared: " + name, value);
+
+ OpenSSHExtension actual = (OpenSSHExtension) value;
+ assertEquals("Mismatched version for OpenSSH extension=" + name, expected.getVersion(), actual.getVersion());
+ }
+
for (BuiltinSftpClientExtensions type : BuiltinSftpClientExtensions.VALUES) {
String extensionName = type.getName();
SftpClientExtension instance = sftp.getExtension(extensionName);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/45549d1e/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
new file mode 100644
index 0000000..a7c8406
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/OpenSSHExtensionsTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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(), getCurrentTestName());
+ Utils.deleteRecursive(lclSftp);
+ Files.createDirectories(lclSftp);
+
+ Path srcFile = 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();
+ }
+ }
+ }
+}