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:d...@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:d...@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:d...@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:d...@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:d...@mina.apache.org">Apache MINA SSHD Project</a> + */ +public class Supported2Parser extends AbstractParser<Supported2> { + /** + * @author <a href="mailto:d...@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:d...@mina.apache.org">Apache MINA SSHD Project</a> + */ +public class SupportedParser extends AbstractParser<Supported> { + /** + * @author <a href="mailto:d...@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:d...@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:d...@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:d...@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:d...@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 x...@openssh.com} extension data reports + * + * @author <a href="mailto:d...@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:d...@mina.apache.org">Apache MINA SSHD Project</a> + */ +public class FstatVfsExtensionParser extends AbstractOpenSSHExtensionParser { + public static final String NAME = "fstat...@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:d...@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 = "fs...@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:d...@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 = "hardl...@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:d...@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-ren...@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:d...@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 = "stat...@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:d...@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:d...@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)); + } +}