You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2018/04/16 11:47:56 UTC
[09/30] mina-sshd git commit: [SSHD-815] Extract SFTP in its own
module
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/NewlineParser.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/NewlineParser.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/NewlineParser.java
new file mode 100644
index 0000000..2ad7ddb
--- /dev/null
+++ b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/NewlineParser.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;
+
+import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.subsystem.sftp.extensions.NewlineParser.Newline;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.BufferUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class NewlineParser extends AbstractParser<Newline> {
+ /**
+ * The "newline" extension information as per
+ * <A HREF="http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt">DRAFT 09 Section 4.3</A>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+ public static class Newline implements Cloneable, Serializable {
+ private static final long serialVersionUID = 2010656704254497899L;
+ private String newline;
+
+ public Newline() {
+ this(null);
+ }
+
+ public Newline(String newline) {
+ this.newline = newline;
+ }
+
+ public String getNewline() {
+ return newline;
+ }
+
+ public void setNewline(String newline) {
+ this.newline = newline;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(getNewline());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (obj.getClass() != getClass()) {
+ return false;
+ }
+
+ return Objects.equals(((Newline) obj).getNewline(), getNewline());
+ }
+
+ @Override
+ public Newline clone() {
+ try {
+ return getClass().cast(super.clone());
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException("Failed to clone " + toString() + ": " + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ String nl = getNewline();
+ if (GenericUtils.isEmpty(nl)) {
+ return nl;
+ } else {
+ return BufferUtils.toHex(':', nl.getBytes(StandardCharsets.UTF_8));
+ }
+ }
+ }
+
+ public static final NewlineParser INSTANCE = new NewlineParser();
+
+ public NewlineParser() {
+ super(SftpConstants.EXT_NEWLINE);
+ }
+
+ @Override
+ public Newline parse(byte[] input, int offset, int len) {
+ return parse(new String(input, offset, len, StandardCharsets.UTF_8));
+ }
+
+ public Newline parse(String value) {
+ return new Newline(value);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java
new file mode 100644
index 0000000..e565ab4
--- /dev/null
+++ b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.subsystem.sftp.extensions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+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;
+
+/**
+ * @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 - section 3.4</A>
+ */
+public final class ParserUtils {
+ public static final Collection<ExtensionParser<?>> BUILT_IN_PARSERS =
+ Collections.unmodifiableList(
+ Arrays.<ExtensionParser<?>>asList(
+ VendorIdParser.INSTANCE,
+ NewlineParser.INSTANCE,
+ VersionsParser.INSTANCE,
+ SupportedParser.INSTANCE,
+ Supported2Parser.INSTANCE,
+ AclSupportedParser.INSTANCE,
+ // OpenSSH extensions
+ PosixRenameExtensionParser.INSTANCE,
+ StatVfsExtensionParser.INSTANCE,
+ FstatVfsExtensionParser.INSTANCE,
+ HardLinkExtensionParser.INSTANCE,
+ FsyncExtensionParser.INSTANCE
+ ));
+
+ private static final Map<String, ExtensionParser<?>> PARSERS_MAP;
+
+ static {
+ PARSERS_MAP = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ for (ExtensionParser<?> p : BUILT_IN_PARSERS) {
+ PARSERS_MAP.put(p.getName(), p);
+ }
+ }
+
+ private ParserUtils() {
+ throw new UnsupportedOperationException("No instance");
+ }
+
+ /**
+ * @param parser The {@link ExtensionParser} to register
+ * @return The replaced parser (by name) - {@code null} if no previous parser
+ * for this extension name
+ */
+ public static ExtensionParser<?> registerParser(ExtensionParser<?> parser) {
+ Objects.requireNonNull(parser, "No parser instance");
+
+ synchronized (PARSERS_MAP) {
+ return PARSERS_MAP.put(parser.getName(), parser);
+ }
+ }
+
+ /**
+ * @param name The extension name - ignored if {@code null}/empty
+ * @return The removed {@link ExtensionParser} - {@code null} if none registered
+ * for this extension name
+ */
+ public static ExtensionParser<?> unregisterParser(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ }
+
+ synchronized (PARSERS_MAP) {
+ return PARSERS_MAP.remove(name);
+ }
+ }
+
+ /**
+ * @param name The extension name - ignored if {@code null}/empty
+ * @return The registered {@link ExtensionParser} - {@code null} if none registered
+ * for this extension name
+ */
+ public static ExtensionParser<?> getRegisteredParser(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ }
+
+ synchronized (PARSERS_MAP) {
+ return PARSERS_MAP.get(name);
+ }
+ }
+
+ public static Set<String> getRegisteredParsersNames() {
+ synchronized (PARSERS_MAP) {
+ if (PARSERS_MAP.isEmpty()) {
+ return Collections.emptySet();
+ } else { // return a copy in order to avoid concurrent modification issues
+ return GenericUtils.asSortedSet(String.CASE_INSENSITIVE_ORDER, PARSERS_MAP.keySet());
+ }
+ }
+ }
+
+ public static List<ExtensionParser<?>> getRegisteredParsers() {
+ synchronized (PARSERS_MAP) {
+ if (PARSERS_MAP.isEmpty()) {
+ return Collections.emptyList();
+ } else { // return a copy in order to avoid concurrent modification issues
+ return new ArrayList<>(PARSERS_MAP.values());
+ }
+ }
+ }
+
+ public static Set<String> supportedExtensions(Map<String, ?> parsed) {
+ if (GenericUtils.isEmpty(parsed)) {
+ return Collections.emptySet();
+ }
+
+ Supported sup = (Supported) parsed.get(SupportedParser.INSTANCE.getName());
+ Collection<String> extra = (sup == null) ? null : sup.extensionNames;
+ Supported2 sup2 = (Supported2) parsed.get(Supported2Parser.INSTANCE.getName());
+ Collection<String> extra2 = (sup2 == null) ? null : sup2.extensionNames;
+ if (GenericUtils.isEmpty(extra)) {
+ return GenericUtils.asSortedSet(String.CASE_INSENSITIVE_ORDER, extra2);
+ } else if (GenericUtils.isEmpty(extra2)) {
+ return GenericUtils.asSortedSet(String.CASE_INSENSITIVE_ORDER, extra);
+ }
+
+ Set<String> result = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
+ result.addAll(extra);
+ result.addAll(extra2);
+ return result;
+ }
+
+ /**
+ * @param extensions The received extensions in encoded form
+ * @return A {@link Map} of all the successfully decoded extensions
+ * where key=extension name (same as in the original map), value=the
+ * decoded extension value. Extensions for which there is no registered
+ * parser are <U>ignored</U>
+ * @see #getRegisteredParser(String)
+ * @see ExtensionParser#parse(byte[])
+ */
+ public static Map<String, Object> parse(Map<String, byte[]> extensions) {
+ if (GenericUtils.isEmpty(extensions)) {
+ return Collections.emptyMap();
+ }
+
+ Map<String, Object> data = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ extensions.forEach((name, value) -> {
+ Object result = parse(name, value);
+ if (result == null) {
+ return;
+ }
+ data.put(name, result);
+ });
+
+ return data;
+ }
+
+ public static Object parse(String name, byte... encoded) {
+ ExtensionParser<?> parser = getRegisteredParser(name);
+ if (parser == null) {
+ return null;
+ } else {
+ return parser.parse(encoded);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/SpaceAvailableExtensionInfo.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/SpaceAvailableExtensionInfo.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/SpaceAvailableExtensionInfo.java
new file mode 100644
index 0000000..16dc184
--- /dev/null
+++ b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/SpaceAvailableExtensionInfo.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.subsystem.sftp.extensions;
+
+import java.io.IOException;
+import java.nio.file.FileStore;
+
+import org.apache.sshd.common.util.NumberUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt">DRAFT 09 section 9.2</A>
+ */
+public class SpaceAvailableExtensionInfo implements Cloneable {
+ // CHECKSTYLE:OFF
+ public long bytesOnDevice;
+ public long unusedBytesOnDevice;
+ public long bytesAvailableToUser;
+ public long unusedBytesAvailableToUser;
+ public int bytesPerAllocationUnit;
+ // CHECKSTYLE:ON
+
+ public SpaceAvailableExtensionInfo() {
+ super();
+ }
+
+ public SpaceAvailableExtensionInfo(Buffer buffer) {
+ decode(buffer, this);
+ }
+
+ public SpaceAvailableExtensionInfo(FileStore store) throws IOException {
+ bytesOnDevice = store.getTotalSpace();
+
+ long unallocated = store.getUnallocatedSpace();
+ long usable = store.getUsableSpace();
+ unusedBytesOnDevice = Math.max(unallocated, usable);
+
+ // the rest are intentionally left zero indicating "UNKNOWN"
+ }
+
+ @Override
+ public int hashCode() {
+ return NumberUtils.hashCode(bytesOnDevice, unusedBytesOnDevice,
+ bytesAvailableToUser, unusedBytesAvailableToUser,
+ bytesPerAllocationUnit);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ SpaceAvailableExtensionInfo other = (SpaceAvailableExtensionInfo) obj;
+ return this.bytesOnDevice == other.bytesOnDevice
+ && this.unusedBytesOnDevice == other.unusedBytesOnDevice
+ && this.bytesAvailableToUser == other.bytesAvailableToUser
+ && this.unusedBytesAvailableToUser == other.unusedBytesAvailableToUser
+ && this.bytesPerAllocationUnit == other.bytesPerAllocationUnit;
+ }
+
+ @Override
+ public SpaceAvailableExtensionInfo clone() {
+ try {
+ return getClass().cast(super.clone());
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException("Failed to close " + toString() + ": " + e.getMessage());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "bytesOnDevice=" + bytesOnDevice
+ + ",unusedBytesOnDevice=" + unusedBytesOnDevice
+ + ",bytesAvailableToUser=" + bytesAvailableToUser
+ + ",unusedBytesAvailableToUser=" + unusedBytesAvailableToUser
+ + ",bytesPerAllocationUnit=" + bytesPerAllocationUnit;
+ }
+
+ public static SpaceAvailableExtensionInfo decode(Buffer buffer) {
+ SpaceAvailableExtensionInfo info = new SpaceAvailableExtensionInfo();
+ decode(buffer, info);
+ return info;
+ }
+
+ public static void decode(Buffer buffer, SpaceAvailableExtensionInfo info) {
+ info.bytesOnDevice = buffer.getLong();
+ info.unusedBytesOnDevice = buffer.getLong();
+ info.bytesAvailableToUser = buffer.getLong();
+ info.unusedBytesAvailableToUser = buffer.getLong();
+ info.bytesPerAllocationUnit = buffer.getInt();
+ }
+
+ public static void encode(Buffer buffer, SpaceAvailableExtensionInfo info) {
+ buffer.putLong(info.bytesOnDevice);
+ buffer.putLong(info.unusedBytesOnDevice);
+ buffer.putLong(info.bytesAvailableToUser);
+ buffer.putLong(info.unusedBytesAvailableToUser);
+ buffer.putInt(info.bytesPerAllocationUnit & 0xFFFFFFFFL);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/Supported2Parser.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/Supported2Parser.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/Supported2Parser.java
new file mode 100644
index 0000000..6259a7c
--- /dev/null
+++ b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/Supported2Parser.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.subsystem.sftp.extensions;
+
+import java.util.Collection;
+
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.subsystem.sftp.extensions.Supported2Parser.Supported2;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+
+/**
+ * Parses the "supported2" extension as defined in
+ * <A HREF="https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#page-10">DRAFT 13 section 5.4</A>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class Supported2Parser extends AbstractParser<Supported2> {
+ /**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#page-10">DRAFT 13 section 5.4</A>
+ */
+ public static class Supported2 {
+ // CHECKSTYLE:OFF
+ public int supportedAttributeMask;
+ public int supportedAttributeBits;
+ public int supportedOpenFlags;
+ public int supportedAccessMask;
+ public int maxReadSize;
+ public short supportedOpenBlockVector;
+ public short supportedBlock;
+ // uint32 attrib-extension-count
+ public Collection<String> attribExtensionNames;
+ // uint32 extension-count
+ public Collection<String> extensionNames;
+ // CHECKSTYLE:ON
+
+ @Override
+ public String toString() {
+ return "attrsMask=0x" + Integer.toHexString(supportedAttributeMask)
+ + ",attrsBits=0x" + Integer.toHexString(supportedAttributeBits)
+ + ",openFlags=0x" + Integer.toHexString(supportedOpenFlags)
+ + ",accessMask=0x" + Integer.toHexString(supportedAccessMask)
+ + ",maxRead=" + maxReadSize
+ + ",openBlock=0x" + Integer.toHexString(supportedOpenBlockVector & 0xFFFF)
+ + ",block=" + Integer.toHexString(supportedBlock & 0xFFFF)
+ + ",attribs=" + attribExtensionNames
+ + ",exts=" + extensionNames;
+ }
+ }
+
+ public static final Supported2Parser INSTANCE = new Supported2Parser();
+
+ public Supported2Parser() {
+ super(SftpConstants.EXT_SUPPORTED2);
+ }
+
+ @Override
+ public Supported2 parse(byte[] input, int offset, int len) {
+ return parse(new ByteArrayBuffer(input, offset, len));
+ }
+
+ public Supported2 parse(Buffer buffer) {
+ Supported2 sup2 = new Supported2();
+ sup2.supportedAttributeMask = buffer.getInt();
+ sup2.supportedAttributeBits = buffer.getInt();
+ sup2.supportedOpenFlags = buffer.getInt();
+ sup2.supportedAccessMask = buffer.getInt();
+ sup2.maxReadSize = buffer.getInt();
+ sup2.supportedOpenBlockVector = buffer.getShort();
+ sup2.supportedBlock = buffer.getShort();
+ sup2.attribExtensionNames = buffer.getStringList(true);
+ sup2.extensionNames = buffer.getStringList(true);
+ return sup2;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/SupportedParser.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/SupportedParser.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/SupportedParser.java
new file mode 100644
index 0000000..4c80463
--- /dev/null
+++ b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/SupportedParser.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.subsystem.sftp.extensions;
+
+import java.util.Collection;
+
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.subsystem.sftp.extensions.SupportedParser.Supported;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+
+/**
+ * Parses the "supported" extension as defined in
+ * <A HREF="http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-05.txt">DRAFT 05 - section 4.4</A>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SupportedParser extends AbstractParser<Supported> {
+ /**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ * @see <A HREF="http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-05.txt">DRAFT 05 - section 4.4</A>
+ */
+ public static class Supported {
+ // CHECKSTYLE:OFF
+ public int supportedAttributeMask;
+ public int supportedAttributeBits;
+ public int supportedOpenFlags;
+ public int supportedAccessMask;
+ public int maxReadSize;
+ public Collection<String> extensionNames;
+ // CHECKSTYLE:ON
+
+ @Override
+ public String toString() {
+ return "attrsMask=0x" + Integer.toHexString(supportedAttributeMask)
+ + ",attrsBits=0x" + Integer.toHexString(supportedAttributeBits)
+ + ",openFlags=0x" + Integer.toHexString(supportedOpenFlags)
+ + ",accessMask=0x" + Integer.toHexString(supportedAccessMask)
+ + ",maxReadSize=" + maxReadSize
+ + ",extensions=" + extensionNames;
+ }
+ }
+
+ public static final SupportedParser INSTANCE = new SupportedParser();
+
+ public SupportedParser() {
+ super(SftpConstants.EXT_SUPPORTED);
+ }
+
+ @Override
+ public Supported parse(byte[] input, int offset, int len) {
+ return parse(new ByteArrayBuffer(input, offset, len));
+ }
+
+ public Supported parse(Buffer buffer) {
+ Supported sup = new Supported();
+ sup.supportedAttributeMask = buffer.getInt();
+ sup.supportedAttributeBits = buffer.getInt();
+ sup.supportedOpenFlags = buffer.getInt();
+ sup.supportedAccessMask = buffer.getInt();
+ sup.maxReadSize = buffer.getInt();
+ sup.extensionNames = buffer.getStringList(false);
+ return sup;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/VendorIdParser.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/VendorIdParser.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/VendorIdParser.java
new file mode 100644
index 0000000..1917d7d
--- /dev/null
+++ b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/VendorIdParser.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.subsystem.sftp.extensions;
+
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.subsystem.sftp.extensions.VendorIdParser.VendorId;
+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>
+ */
+public class VendorIdParser extends AbstractParser<VendorId> {
+ /**
+ * The "vendor-id" information as per
+ * <A HREF="http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt">DRAFT 09 - section 4.4</A>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+ public static class VendorId {
+ // CHECKSTYLE:OFF
+ public String vendorName;
+ public String productName;
+ public String productVersion;
+ public long productBuildNumber;
+ // CHECKSTYLE:ON
+
+ @Override
+ public String toString() {
+ return vendorName + "-" + productName + "-" + productVersion + "-" + productBuildNumber;
+ }
+ }
+
+ public static final VendorIdParser INSTANCE = new VendorIdParser();
+
+ public VendorIdParser() {
+ super(SftpConstants.EXT_VENDOR_ID);
+ }
+
+ @Override
+ public VendorId parse(byte[] input, int offset, int len) {
+ return parse(new ByteArrayBuffer(input, offset, len));
+ }
+
+ public VendorId parse(Buffer buffer) {
+ VendorId id = new VendorId();
+ id.vendorName = buffer.getString();
+ id.productName = buffer.getString();
+ id.productVersion = buffer.getString();
+ id.productBuildNumber = buffer.getLong();
+ return id;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/VersionsParser.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/VersionsParser.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/VersionsParser.java
new file mode 100644
index 0000000..51b31f6
--- /dev/null
+++ b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/VersionsParser.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.subsystem.sftp.extensions;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.subsystem.sftp.extensions.VersionsParser.Versions;
+import org.apache.sshd.common.util.GenericUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class VersionsParser extends AbstractParser<Versions> {
+ /**
+ * The "versions" extension data as per
+ * <A HREF="http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/draft-ietf-secsh-filexfer-09.txt">DRAFT 09 Section 4.6</A>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+ public static class Versions {
+ public static final char SEP = ',';
+
+ private List<String> versions;
+
+ public Versions() {
+ this(null);
+ }
+
+ public Versions(List<String> versions) {
+ this.versions = versions;
+ }
+
+ public List<String> getVersions() {
+ return versions;
+ }
+
+ public void setVersions(List<String> versions) {
+ this.versions = versions;
+ }
+
+ @Override
+ public String toString() {
+ return GenericUtils.join(getVersions(), ',');
+ }
+ }
+
+ public static final VersionsParser INSTANCE = new VersionsParser();
+
+ public VersionsParser() {
+ super(SftpConstants.EXT_VERSIONS);
+ }
+
+ @Override
+ public Versions parse(byte[] input, int offset, int len) {
+ return parse(new String(input, offset, len, StandardCharsets.UTF_8));
+ }
+
+ public Versions parse(String value) {
+ String[] comps = GenericUtils.split(value, Versions.SEP);
+ return new Versions(GenericUtils.isEmpty(comps) ? Collections.emptyList() : Arrays.asList(comps));
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java
new file mode 100644
index 0000000..8590e64
--- /dev/null
+++ b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java
@@ -0,0 +1,113 @@
+/*
+ * 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.io.Serializable;
+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.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, Serializable {
+ private static final long serialVersionUID = 5902797870154506909L;
+ 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");
+ 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;
+ return Objects.equals(getName(), other.getName())
+ && Objects.equals(getVersion(), other.getVersion());
+ }
+
+ @Override
+ public OpenSSHExtension clone() {
+ try {
+ return getClass().cast(super.clone());
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException("Unexpected clone exception " + toString() + ": " + e.getMessage());
+ }
+ }
+
+ @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/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FstatVfsExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FstatVfsExtensionParser.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FstatVfsExtensionParser.java
new file mode 100644
index 0000000..4d13bf4
--- /dev/null
+++ b/sshd-sftp/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/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FsyncExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FsyncExtensionParser.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/FsyncExtensionParser.java
new file mode 100644
index 0000000..e9967ab
--- /dev/null
+++ b/sshd-sftp/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 - section 10</A>
+ */
+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/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/HardLinkExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/HardLinkExtensionParser.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/HardLinkExtensionParser.java
new file mode 100644
index 0000000..6d79a78
--- /dev/null
+++ b/sshd-sftp/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 - section 10</A>
+ */
+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/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/PosixRenameExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/PosixRenameExtensionParser.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/PosixRenameExtensionParser.java
new file mode 100644
index 0000000..151c1ee
--- /dev/null
+++ b/sshd-sftp/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 - section 3.3</A>
+ */
+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/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/StatVfsExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/StatVfsExtensionParser.java b/sshd-sftp/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/StatVfsExtensionParser.java
new file mode 100644
index 0000000..be0fd8a
--- /dev/null
+++ b/sshd-sftp/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 - section 3.4</A>
+ */
+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/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/AbstractSftpEventListenerAdapter.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/AbstractSftpEventListenerAdapter.java b/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/AbstractSftpEventListenerAdapter.java
new file mode 100644
index 0000000..6895bae
--- /dev/null
+++ b/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/AbstractSftpEventListenerAdapter.java
@@ -0,0 +1,258 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.server.subsystem.sftp;
+
+import java.io.IOException;
+import java.nio.file.CopyOption;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * A no-op implementation of {@link SftpEventListener} for those who wish to
+ * implement only a small number of methods. By default, all non-overridden methods
+ * simply log at TRACE level their invocation parameters
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractSftpEventListenerAdapter extends AbstractLoggingBean implements SftpEventListener {
+ protected AbstractSftpEventListenerAdapter() {
+ super();
+ }
+
+ @Override
+ public void initialized(ServerSession session, int version) {
+ if (log.isTraceEnabled()) {
+ log.trace("initialized(" + session + ") version: " + version);
+ }
+ }
+
+ @Override
+ public void destroying(ServerSession session) {
+ if (log.isTraceEnabled()) {
+ log.trace("destroying(" + session + ")");
+ }
+ }
+
+ @Override
+ public void opening(ServerSession session, String remoteHandle, Handle localHandle) throws IOException {
+ if (log.isTraceEnabled()) {
+ Path path = localHandle.getFile();
+ log.trace("opening(" + session + ")[" + remoteHandle + "] " + (Files.isDirectory(path) ? "directory" : "file") + " " + path);
+ }
+ }
+
+ @Override
+ public void open(ServerSession session, String remoteHandle, Handle localHandle) {
+ if (log.isTraceEnabled()) {
+ Path path = localHandle.getFile();
+ log.trace("open(" + session + ")[" + remoteHandle + "] " + (Files.isDirectory(path) ? "directory" : "file") + " " + path);
+ }
+ }
+
+ @Override
+ public void read(ServerSession session, String remoteHandle, DirectoryHandle localHandle, Map<String, Path> entries)
+ throws IOException {
+ int numEntries = GenericUtils.size(entries);
+ if (log.isDebugEnabled()) {
+ log.debug("read(" + session + ")[" + localHandle.getFile() + "] " + numEntries + " entries");
+ }
+
+ if ((numEntries > 0) && log.isTraceEnabled()) {
+ entries.forEach((key, value) ->
+ log.trace("read(" + session + ")[" + localHandle.getFile() + "] " + key + " - " + value));
+ }
+ }
+
+ @Override
+ public void reading(ServerSession session, String remoteHandle, FileHandle localHandle,
+ long offset, byte[] data, int dataOffset, int dataLen)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("reading(" + session + ")[" + localHandle.getFile() + "] offset=" + offset + ", requested=" + dataLen);
+ }
+ }
+
+ @Override
+ public void read(ServerSession session, String remoteHandle, FileHandle localHandle,
+ long offset, byte[] data, int dataOffset, int dataLen, int readLen, Throwable thrown)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("read(" + session + ")[" + localHandle.getFile() + "] offset=" + offset
+ + ", requested=" + dataLen + ", read=" + readLen
+ + ((thrown == null) ? "" : (": " + thrown.getClass().getSimpleName() + ": " + thrown.getMessage())));
+ }
+ }
+
+ @Override
+ public void writing(ServerSession session, String remoteHandle, FileHandle localHandle,
+ long offset, byte[] data, int dataOffset, int dataLen)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("write(" + session + ")[" + localHandle.getFile() + "] offset=" + offset + ", requested=" + dataLen);
+ }
+ }
+
+ @Override
+ public void written(ServerSession session, String remoteHandle, FileHandle localHandle,
+ long offset, byte[] data, int dataOffset, int dataLen, Throwable thrown)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("written(" + session + ")[" + localHandle.getFile() + "] offset=" + offset + ", requested=" + dataLen
+ + ((thrown == null) ? "" : (": " + thrown.getClass().getSimpleName() + ": " + thrown.getMessage())));
+ }
+ }
+
+ @Override
+ public void blocking(ServerSession session, String remoteHandle, FileHandle localHandle, long offset, long length, int mask)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("blocking(" + session + ")[" + localHandle.getFile() + "]"
+ + " offset=" + offset + ", length=" + length + ", mask=0x" + Integer.toHexString(mask));
+ }
+ }
+
+ @Override
+ public void blocked(ServerSession session, String remoteHandle, FileHandle localHandle,
+ long offset, long length, int mask, Throwable thrown)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("blocked(" + session + ")[" + localHandle.getFile() + "]"
+ + " offset=" + offset + ", length=" + length + ", mask=0x" + Integer.toHexString(mask)
+ + ((thrown == null) ? "" : (": " + thrown.getClass().getSimpleName() + ": " + thrown.getMessage())));
+ }
+ }
+
+ @Override
+ public void unblocking(ServerSession session, String remoteHandle, FileHandle localHandle, long offset, long length)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("unblocking(" + session + ")[" + localHandle.getFile() + "] offset=" + offset + ", length=" + length);
+ }
+ }
+
+ @Override
+ public void unblocked(ServerSession session, String remoteHandle, FileHandle localHandle,
+ long offset, long length, Throwable thrown)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("unblocked(" + session + ")[" + localHandle.getFile() + "]"
+ + " offset=" + offset + ", length=" + length
+ + ((thrown == null) ? "" : (": " + thrown.getClass().getSimpleName() + ": " + thrown.getMessage())));
+ }
+ }
+
+ @Override
+ public void close(ServerSession session, String remoteHandle, Handle localHandle) {
+ if (log.isTraceEnabled()) {
+ Path path = localHandle.getFile();
+ log.trace("close(" + session + ")[" + remoteHandle + "] " + (Files.isDirectory(path) ? "directory" : "file") + " " + path);
+ }
+ }
+
+ @Override
+ public void creating(ServerSession session, Path path, Map<String, ?> attrs)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("creating(" + session + ") " + (Files.isDirectory(path) ? "directory" : "file") + " " + path);
+ }
+ }
+
+ @Override
+ public void created(ServerSession session, Path path, Map<String, ?> attrs, Throwable thrown)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("created(" + session + ") " + (Files.isDirectory(path) ? "directory" : "file") + " " + path
+ + ((thrown == null) ? "" : (": " + thrown.getClass().getSimpleName() + ": " + thrown.getMessage())));
+ }
+ }
+
+ @Override
+ public void moving(ServerSession session, Path srcPath, Path dstPath, Collection<CopyOption> opts)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("moving(" + session + ")[" + opts + "]" + srcPath + " => " + dstPath);
+ }
+ }
+
+ @Override
+ public void moved(ServerSession session, Path srcPath, Path dstPath, Collection<CopyOption> opts, Throwable thrown)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("moved(" + session + ")[" + opts + "]" + srcPath + " => " + dstPath
+ + ((thrown == null) ? "" : (": " + thrown.getClass().getSimpleName() + ": " + thrown.getMessage())));
+ }
+ }
+
+ @Override
+ public void removing(ServerSession session, Path path)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("removing(" + session + ") " + path);
+ }
+ }
+
+ @Override
+ public void removed(ServerSession session, Path path, Throwable thrown)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("removed(" + session + ") " + path
+ + ((thrown == null) ? "" : (": " + thrown.getClass().getSimpleName() + ": " + thrown.getMessage())));
+ }
+ }
+
+ @Override
+ public void linking(ServerSession session, Path source, Path target, boolean symLink)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("linking(" + session + ")[" + symLink + "]" + source + " => " + target);
+ }
+ }
+
+ @Override
+ public void linked(ServerSession session, Path source, Path target, boolean symLink, Throwable thrown)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("linked(" + session + ")[" + symLink + "]" + source + " => " + target
+ + ((thrown == null) ? "" : (": " + thrown.getClass().getSimpleName() + ": " + thrown.getMessage())));
+ }
+ }
+
+ @Override
+ public void modifyingAttributes(ServerSession session, Path path, Map<String, ?> attrs)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("modifyingAttributes(" + session + ") " + path + ": " + attrs);
+ }
+ }
+
+ @Override
+ public void modifiedAttributes(ServerSession session, Path path, Map<String, ?> attrs, Throwable thrown)
+ throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("modifiedAttributes(" + session + ") " + path
+ + ((thrown == null) ? "" : (": " + thrown.getClass().getSimpleName() + ": " + thrown.getMessage())));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/AbstractSftpEventListenerManager.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/AbstractSftpEventListenerManager.java b/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/AbstractSftpEventListenerManager.java
new file mode 100644
index 0000000..11508b3
--- /dev/null
+++ b/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/AbstractSftpEventListenerManager.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.server.subsystem.sftp;
+
+import java.util.Collection;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.apache.sshd.common.util.EventListenerUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractSftpEventListenerManager implements SftpEventListenerManager {
+ private final Collection<SftpEventListener> sftpEventListeners = new CopyOnWriteArraySet<>();
+ private final SftpEventListener sftpEventListenerProxy;
+
+ protected AbstractSftpEventListenerManager() {
+ sftpEventListenerProxy = EventListenerUtils.proxyWrapper(SftpEventListener.class, getClass().getClassLoader(), sftpEventListeners);
+ }
+
+ public Collection<SftpEventListener> getRegisteredListeners() {
+ return sftpEventListeners;
+ }
+
+ @Override
+ public SftpEventListener getSftpEventListenerProxy() {
+ return sftpEventListenerProxy;
+ }
+
+ @Override
+ public boolean addSftpEventListener(SftpEventListener listener) {
+ return sftpEventListeners.add(SftpEventListener.validateListener(listener));
+ }
+
+ @Override
+ public boolean removeSftpEventListener(SftpEventListener listener) {
+ if (listener == null) {
+ return false;
+ }
+
+ return sftpEventListeners.remove(SftpEventListener.validateListener(listener));
+ }
+}