[SSHD-861] Added SftpFileSystemClientSessionInitializer hook in SftpFileSystemProvider
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/e3b8acd7 Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/e3b8acd7 Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/e3b8acd7 Branch: refs/heads/master Commit: e3b8acd7e068fdc586f1f825eb675a335eb42824 Parents: c24635d Author: Lyor Goldstein <[email protected]> Authored: Sun Nov 11 10:43:16 2018 +0200 Committer: Lyor Goldstein <[email protected]> Committed: Sun Nov 11 18:56:28 2018 +0200 ---------------------------------------------------------------------- CHANGES.md | 4 + README.md | 34 +- .../apache/sshd/cli/client/SftpCommandMain.java | 2 +- .../java.nio.file.spi.FileSystemProvider | 2 +- .../sftp/SftpAclFileAttributeView.java | 67 - .../subsystem/sftp/SftpClientFactory.java | 16 +- .../subsystem/sftp/SftpDirectoryStream.java | 65 - .../client/subsystem/sftp/SftpFileStore.java | 105 -- .../client/subsystem/sftp/SftpFileSystem.java | 600 -------- .../subsystem/sftp/SftpFileSystemChannel.java | 37 - .../subsystem/sftp/SftpFileSystemProvider.java | 1312 ----------------- .../sshd/client/subsystem/sftp/SftpPath.java | 43 - .../client/subsystem/sftp/SftpPathIterator.java | 82 -- .../sftp/SftpPosixFileAttributeView.java | 94 -- .../subsystem/sftp/SftpPosixFileAttributes.java | 113 -- .../sftp/fs/SftpAclFileAttributeView.java | 68 + .../subsystem/sftp/fs/SftpDirectoryStream.java | 67 + .../client/subsystem/sftp/fs/SftpFileStore.java | 105 ++ .../subsystem/sftp/fs/SftpFileSystem.java | 604 ++++++++ .../sftp/fs/SftpFileSystemChannel.java | 40 + .../SftpFileSystemClientSessionInitializer.java | 97 ++ .../fs/SftpFileSystemInitializationContext.java | 142 ++ .../sftp/fs/SftpFileSystemProvider.java | 1340 ++++++++++++++++++ .../sshd/client/subsystem/sftp/fs/SftpPath.java | 43 + .../subsystem/sftp/fs/SftpPathIterator.java | 84 ++ .../sftp/fs/SftpPosixFileAttributeView.java | 95 ++ .../sftp/fs/SftpPosixFileAttributes.java | 113 ++ .../impl/AbstractSftpFileAttributeView.java | 6 +- .../sftp/impl/DefaultSftpClientFactory.java | 4 +- .../subsystem/sftp/SftpFileSystemTest.java | 497 ------- .../subsystem/sftp/SftpFileSystemURITest.java | 121 -- .../subsystem/sftp/fs/SftpFileSystemTest.java | 532 +++++++ .../sftp/fs/SftpFileSystemURITest.java | 121 ++ 33 files changed, 3503 insertions(+), 3152 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e3b8acd7/CHANGES.md ---------------------------------------------------------------------- diff --git a/CHANGES.md b/CHANGES.md index f909f44..2a338cc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -27,6 +27,10 @@ user to try and repeat an encrypted private key decoding using a different passw * `SshAgent#getIdentities` returns an `Iterable` rather than a `List` +* `SftpFileSystemProvider` and its associated helper classes have been moved to +`org.apache.sshd.client.subsystem.sftp.fs` package + +* Added `SftpFileSystemClientSessionInitializer` support in `SftpFileSystemProvider` ## Behavioral changes http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e3b8acd7/README.md ---------------------------------------------------------------------- diff --git a/README.md b/README.md index c5edc53..f8bfa56 100644 --- a/README.md +++ b/README.md @@ -957,9 +957,16 @@ system. It is highly recommended to `close()` the mounted file system once no longer necessary in order to release the associated SFTP session sooner rather than later - e.g., via a `try-with-resource` code block. +**Caveat:** Due to URI encoding of the username/password as a basic authentication, the system currently +does not allow colon (`:`) in either one in order to avoid parsing confusion. See [RFC 3986 - section 3.2.1](https://tools.ietf.org/html/rfc3986#section-3.2.1): + +>> Use of the format "user:password" in the userinfo field is +>> deprecated ... Applications may choose to ignore or reject such +>> data when it is received as part of a reference... + #### Configuring the `SftpFileSystemProvider` -When "mounting" a new file system one can provide configuration parameters using either the +When "mounting" a new file system one can provide extra configuration parameters using either the environment map in the [FileSystems#newFileSystem](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystems.html#newFileSystem) method or via the URI query parameters. See the `SftpFileSystemProvider` for the available configuration keys and values. @@ -1005,6 +1012,31 @@ configuration keys and values. ``` +#### Configuring the client session used to create an `SftpFileSystem` + +It is possible to register a `SftpFileSystemClientSessionInitializer` with the provider instead of the default one +and thus better control the `ClientSession` used to generate the file-system instance. The default implementation +simply connects and authenticates before creating a default `SftpFileSystem` instance. Users may wish +to override some options or provide their own - e.g., execute a password-less authentication instead of +the (default) password-based one: + +```java + + SftpFileSystemProvider provider = ... obtain/create a provider ... + provider.setSftpFileSystemClientSessionInitializer(new SftpFileSystemClientSessionInitializer() { + @Override + public void authenticateClientSession( + SftpFileSystemProvider provider, SftpFileSystemInitializationContext context, ClientSession session) + throws IOException { + // Set up password-less login instead of password-based + KeyPair kp = ... obtain a registered key-pair... + session.addPublicKeyIdentity(kp); + return sesssion.auth().verify(context.getMaxAuthTime()); + } + }); + +``` + #### Tracking accessed location via `SftpFileSystemAccessor` One can override the default `SftpFileSystemAccessor` and thus be able to track all opened files and folders http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e3b8acd7/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java ---------------------------------------------------------------------- diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java index e730448..99427ff 100644 --- a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java +++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SftpCommandMain.java @@ -47,9 +47,9 @@ import org.apache.sshd.client.subsystem.sftp.SftpClient; import org.apache.sshd.client.subsystem.sftp.SftpClient.Attributes; import org.apache.sshd.client.subsystem.sftp.SftpClient.DirEntry; import org.apache.sshd.client.subsystem.sftp.SftpClientFactory; -import org.apache.sshd.client.subsystem.sftp.SftpFileSystemProvider; import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatExtensionInfo; import org.apache.sshd.client.subsystem.sftp.extensions.openssh.OpenSSHStatPathExtension; +import org.apache.sshd.client.subsystem.sftp.fs.SftpFileSystemProvider; import org.apache.sshd.common.NamedResource; import org.apache.sshd.common.ServiceFactory; import org.apache.sshd.common.channel.ChannelFactory; http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e3b8acd7/sshd-sftp/src/main/filtered-resources/META-INF/services/java.nio.file.spi.FileSystemProvider ---------------------------------------------------------------------- diff --git a/sshd-sftp/src/main/filtered-resources/META-INF/services/java.nio.file.spi.FileSystemProvider b/sshd-sftp/src/main/filtered-resources/META-INF/services/java.nio.file.spi.FileSystemProvider index 75fea68..6d92ee2 100644 --- a/sshd-sftp/src/main/filtered-resources/META-INF/services/java.nio.file.spi.FileSystemProvider +++ b/sshd-sftp/src/main/filtered-resources/META-INF/services/java.nio.file.spi.FileSystemProvider @@ -17,4 +17,4 @@ ## under the License. ## -org.apache.sshd.client.subsystem.sftp.SftpFileSystemProvider +org.apache.sshd.client.subsystem.sftp.fs.SftpFileSystemProvider http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e3b8acd7/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpAclFileAttributeView.java ---------------------------------------------------------------------- diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpAclFileAttributeView.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpAclFileAttributeView.java deleted file mode 100644 index 7cada6e..0000000 --- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpAclFileAttributeView.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.sshd.client.subsystem.sftp; - -import java.io.IOException; -import java.nio.file.LinkOption; -import java.nio.file.Path; -import java.nio.file.attribute.AclEntry; -import java.nio.file.attribute.AclFileAttributeView; -import java.nio.file.attribute.PosixFileAttributes; -import java.nio.file.attribute.UserPrincipal; -import java.util.List; - -import org.apache.sshd.client.subsystem.sftp.impl.AbstractSftpFileAttributeView; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class SftpAclFileAttributeView extends AbstractSftpFileAttributeView implements AclFileAttributeView { - public SftpAclFileAttributeView(SftpFileSystemProvider provider, Path path, LinkOption... options) { - super(provider, path, options); - } - - @Override - public UserPrincipal getOwner() throws IOException { - PosixFileAttributes v = provider.readAttributes(path, PosixFileAttributes.class, options); - return v.owner(); - } - - @Override - public void setOwner(UserPrincipal owner) throws IOException { - provider.setAttribute(path, "posix", "owner", owner, options); - } - - @Override - public String name() { - return "acl"; - } - - @Override - public List<AclEntry> getAcl() throws IOException { - return readRemoteAttributes().getAcl(); - } - - @Override - public void setAcl(List<AclEntry> acl) throws IOException { - writeRemoteAttributes(new SftpClient.Attributes().acl(acl)); - } - -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e3b8acd7/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClientFactory.java ---------------------------------------------------------------------- diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClientFactory.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClientFactory.java index 5497c91..0672482 100644 --- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClientFactory.java +++ b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClientFactory.java @@ -19,9 +19,9 @@ package org.apache.sshd.client.subsystem.sftp; import java.io.IOException; -import java.nio.file.FileSystem; import org.apache.sshd.client.session.ClientSession; +import org.apache.sshd.client.subsystem.sftp.fs.SftpFileSystem; import org.apache.sshd.client.subsystem.sftp.impl.DefaultSftpClientFactory; /** @@ -67,23 +67,23 @@ public interface SftpClientFactory { */ SftpClient createSftpClient(ClientSession session, SftpVersionSelector selector) throws IOException; - default FileSystem createSftpFileSystem(ClientSession session) throws IOException { + default SftpFileSystem createSftpFileSystem(ClientSession session) throws IOException { return createSftpFileSystem(session, SftpVersionSelector.CURRENT); } - default FileSystem createSftpFileSystem(ClientSession session, int version) throws IOException { + default SftpFileSystem createSftpFileSystem(ClientSession session, int version) throws IOException { return createSftpFileSystem(session, SftpVersionSelector.fixedVersionSelector(version)); } - default FileSystem createSftpFileSystem(ClientSession session, SftpVersionSelector selector) throws IOException { + default SftpFileSystem createSftpFileSystem(ClientSession session, SftpVersionSelector selector) throws IOException { return createSftpFileSystem(session, selector, SftpClient.DEFAULT_READ_BUFFER_SIZE, SftpClient.DEFAULT_WRITE_BUFFER_SIZE); } - default FileSystem createSftpFileSystem(ClientSession session, int version, int readBufferSize, int writeBufferSize) throws IOException { + default SftpFileSystem createSftpFileSystem(ClientSession session, int version, int readBufferSize, int writeBufferSize) throws IOException { return createSftpFileSystem(session, SftpVersionSelector.fixedVersionSelector(version), readBufferSize, writeBufferSize); } - default FileSystem createSftpFileSystem(ClientSession session, int readBufferSize, int writeBufferSize) throws IOException { + default SftpFileSystem createSftpFileSystem(ClientSession session, int readBufferSize, int writeBufferSize) throws IOException { return createSftpFileSystem(session, SftpVersionSelector.CURRENT, readBufferSize, writeBufferSize); } @@ -92,10 +92,10 @@ public interface SftpClientFactory { * @param selector The {@link SftpVersionSelector} to use in order to negotiate the SFTP version * @param readBufferSize Default I/O read buffer size * @param writeBufferSize Default I/O write buffer size - * @return The created {@link FileSystem} instance + * @return The created {@link SftpFileSystem} instance * @throws IOException If failed to create the instance */ - FileSystem createSftpFileSystem( + SftpFileSystem createSftpFileSystem( ClientSession session, SftpVersionSelector selector, int readBufferSize, int writeBufferSize) throws IOException; } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e3b8acd7/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirectoryStream.java ---------------------------------------------------------------------- diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirectoryStream.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirectoryStream.java deleted file mode 100644 index 5f48966..0000000 --- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirectoryStream.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.sshd.client.subsystem.sftp; - -import java.io.IOException; -import java.nio.file.DirectoryStream; -import java.nio.file.Path; -import java.util.Iterator; - -/** - * Implements a remote {@link DirectoryStream} - * - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class SftpDirectoryStream implements DirectoryStream<Path> { - private final SftpClient sftp; - private final Iterable<SftpClient.DirEntry> iter; - private final SftpPath p; - - /** - * @param path The remote {@link SftpPath} - * @throws IOException If failed to initialize the directory access handle - */ - public SftpDirectoryStream(SftpPath path) throws IOException { - SftpFileSystem fs = path.getFileSystem(); - p = path; - sftp = fs.getClient(); - iter = sftp.readDir(path.toString()); - } - - /** - * Client instance used to access the remote directory - * - * @return The {@link SftpClient} instance used to access the remote directory - */ - public final SftpClient getClient() { - return sftp; - } - - @Override - public Iterator<Path> iterator() { - return new SftpPathIterator(p, iter); - } - - @Override - public void close() throws IOException { - sftp.close(); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e3b8acd7/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileStore.java ---------------------------------------------------------------------- diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileStore.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileStore.java deleted file mode 100644 index 8a6f1f1..0000000 --- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileStore.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.sshd.client.subsystem.sftp; - -import java.io.IOException; -import java.nio.file.FileStore; -import java.nio.file.FileSystem; -import java.nio.file.attribute.FileAttributeView; -import java.nio.file.attribute.FileStoreAttributeView; -import java.util.Collection; - -import org.apache.sshd.common.subsystem.sftp.SftpConstants; -import org.apache.sshd.common.util.GenericUtils; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class SftpFileStore extends FileStore { - private final SftpFileSystem fs; - private final String name; - - public SftpFileStore(String name, SftpFileSystem fs) { - this.name = name; - this.fs = fs; - } - - public final SftpFileSystem getFileSystem() { - return fs; - } - - @Override - public String name() { - return name; - } - - @Override - public String type() { - return SftpConstants.SFTP_SUBSYSTEM_NAME; - } - - @Override - public boolean isReadOnly() { - return false; - } - - @Override - public long getTotalSpace() throws IOException { - return Long.MAX_VALUE; // TODO use SFTPv6 space-available extension - } - - @Override - public long getUsableSpace() throws IOException { - return Long.MAX_VALUE; - } - - @Override - public long getUnallocatedSpace() throws IOException { - return Long.MAX_VALUE; - } - - @Override - public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) { - SftpFileSystem sftpFs = getFileSystem(); - SftpFileSystemProvider provider = sftpFs.provider(); - return provider.isSupportedFileAttributeView(sftpFs, type); - } - - @Override - public boolean supportsFileAttributeView(String name) { - if (GenericUtils.isEmpty(name)) { - return false; // debug breakpoint - } - - FileSystem sftpFs = getFileSystem(); - Collection<String> views = sftpFs.supportedFileAttributeViews(); - return !GenericUtils.isEmpty(views) && views.contains(name); - } - - @Override - public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) { - return null; // no special views supported - } - - @Override - public Object getAttribute(String attribute) throws IOException { - return null; // no special attributes supported - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e3b8acd7/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java ---------------------------------------------------------------------- diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java deleted file mode 100644 index ed16a26..0000000 --- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java +++ /dev/null @@ -1,600 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.sshd.client.subsystem.sftp; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.StreamCorruptedException; -import java.nio.charset.Charset; -import java.nio.file.FileStore; -import java.nio.file.FileSystemException; -import java.nio.file.attribute.GroupPrincipal; -import java.nio.file.attribute.UserPrincipal; -import java.nio.file.attribute.UserPrincipalLookupService; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.NavigableMap; -import java.util.NavigableSet; -import java.util.Objects; -import java.util.Queue; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.sshd.client.channel.ClientChannel; -import org.apache.sshd.client.session.ClientSession; -import org.apache.sshd.client.session.ClientSessionHolder; -import org.apache.sshd.client.subsystem.sftp.impl.AbstractSftpClient; -import org.apache.sshd.common.file.util.BaseFileSystem; -import org.apache.sshd.common.subsystem.sftp.SftpConstants; -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.buffer.Buffer; - -public class SftpFileSystem extends BaseFileSystem<SftpPath> implements ClientSessionHolder { - public static final String POOL_SIZE_PROP = "sftp-fs-pool-size"; - public static final int DEFAULT_POOL_SIZE = 8; - - public static final NavigableSet<String> UNIVERSAL_SUPPORTED_VIEWS = - Collections.unmodifiableNavigableSet( - GenericUtils.asSortedSet(String.CASE_INSENSITIVE_ORDER, "basic", "posix", "owner")); - - private final String id; - private final ClientSession clientSession; - private final SftpClientFactory factory; - private final SftpVersionSelector selector; - private final Queue<SftpClient> pool; - private final ThreadLocal<Wrapper> wrappers = new ThreadLocal<>(); - private final int version; - private final Set<String> supportedViews; - private SftpPath defaultDir; - private int readBufferSize = SftpClient.DEFAULT_READ_BUFFER_SIZE; - private int writeBufferSize = SftpClient.DEFAULT_WRITE_BUFFER_SIZE; - private final List<FileStore> stores; - - public SftpFileSystem( - SftpFileSystemProvider provider, String id, ClientSession session, - SftpClientFactory factory, SftpVersionSelector selector) - throws IOException { - super(provider); - this.id = id; - this.clientSession = Objects.requireNonNull(session, "No client session"); - this.factory = factory != null ? factory : SftpClientFactory.instance(); - this.selector = selector; - this.stores = Collections.unmodifiableList(Collections.<FileStore>singletonList(new SftpFileStore(id, this))); - this.pool = new LinkedBlockingQueue<>(session.getIntProperty(POOL_SIZE_PROP, DEFAULT_POOL_SIZE)); - try (SftpClient client = getClient()) { - version = client.getVersion(); - defaultDir = getPath(client.canonicalPath(".")); - } - - if (version >= SftpConstants.SFTP_V4) { - Set<String> views = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); - views.addAll(UNIVERSAL_SUPPORTED_VIEWS); - views.add("acl"); - supportedViews = Collections.unmodifiableSet(views); - } else { - supportedViews = UNIVERSAL_SUPPORTED_VIEWS; - } - } - - public final SftpVersionSelector getSftpVersionSelector() { - return selector; - } - - public final String getId() { - return id; - } - - public final int getVersion() { - return version; - } - - @Override - public SftpFileSystemProvider provider() { - return (SftpFileSystemProvider) super.provider(); - } - - @Override // NOTE: co-variant return - public List<FileStore> getFileStores() { - return this.stores; - } - - public int getReadBufferSize() { - return readBufferSize; - } - - public void setReadBufferSize(int size) { - if (size < SftpClient.MIN_READ_BUFFER_SIZE) { - throw new IllegalArgumentException("Insufficient read buffer size: " + size + ", min.=" + SftpClient.MIN_READ_BUFFER_SIZE); - } - - readBufferSize = size; - } - - public int getWriteBufferSize() { - return writeBufferSize; - } - - public void setWriteBufferSize(int size) { - if (size < SftpClient.MIN_WRITE_BUFFER_SIZE) { - throw new IllegalArgumentException("Insufficient write buffer size: " + size + ", min.=" + SftpClient.MIN_WRITE_BUFFER_SIZE); - } - - writeBufferSize = size; - } - - @Override - protected SftpPath create(String root, List<String> names) { - return new SftpPath(this, root, names); - } - - @Override - public ClientSession getClientSession() { - return clientSession; - } - - @SuppressWarnings("synthetic-access") - public SftpClient getClient() throws IOException { - Wrapper wrapper = wrappers.get(); - if (wrapper == null) { - while (wrapper == null) { - SftpClient client = pool.poll(); - if (client == null) { - ClientSession session = getClientSession(); - client = factory.createSftpClient(session, getSftpVersionSelector()); - } - if (!client.isClosing()) { - wrapper = new Wrapper(client, getReadBufferSize(), getWriteBufferSize()); - } - } - wrappers.set(wrapper); - } else { - wrapper.increment(); - } - return wrapper; - } - - @Override - public void close() throws IOException { - if (isOpen()) { - SftpFileSystemProvider provider = provider(); - String fsId = getId(); - SftpFileSystem fs = provider.removeFileSystem(fsId); - ClientSession session = getClientSession(); - session.close(true); - - if ((fs != null) && (fs != this)) { - throw new FileSystemException(fsId, fsId, "Mismatched FS instance for id=" + fsId); - } - } - } - - @Override - public boolean isOpen() { - ClientSession session = getClientSession(); - return session.isOpen(); - } - - @Override - public Set<String> supportedFileAttributeViews() { - return supportedViews; - } - - @Override - public UserPrincipalLookupService getUserPrincipalLookupService() { - return DefaultUserPrincipalLookupService.INSTANCE; - } - - @Override - public SftpPath getDefaultDir() { - return defaultDir; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "[" + getClientSession() + "]"; - } - - private final class Wrapper extends AbstractSftpClient { - private final SftpClient delegate; - private final AtomicInteger count = new AtomicInteger(1); - private final int readSize; - private final int writeSize; - - private Wrapper(SftpClient delegate, int readSize, int writeSize) { - this.delegate = delegate; - this.readSize = readSize; - this.writeSize = writeSize; - } - - @Override - public int getVersion() { - return delegate.getVersion(); - } - - @Override - public ClientSession getClientSession() { - return delegate.getClientSession(); - } - - @Override - public ClientChannel getClientChannel() { - return delegate.getClientChannel(); - } - - @Override - public NavigableMap<String, byte[]> getServerExtensions() { - return delegate.getServerExtensions(); - } - - @Override - public Charset getNameDecodingCharset() { - return delegate.getNameDecodingCharset(); - } - - @Override - public void setNameDecodingCharset(Charset cs) { - delegate.setNameDecodingCharset(cs); - } - - @Override - public boolean isClosing() { - return false; - } - - @Override - public boolean isOpen() { - return count.get() > 0; - } - - @SuppressWarnings("synthetic-access") - @Override - public void close() throws IOException { - if (count.decrementAndGet() <= 0) { - if (!pool.offer(delegate)) { - delegate.close(); - } - wrappers.set(null); - } - } - - public void increment() { - count.incrementAndGet(); - } - - @Override - public CloseableHandle open(String path, Collection<OpenMode> options) throws IOException { - if (!isOpen()) { - throw new IOException("open(" + path + ")[" + options + "] client is closed"); - } - return delegate.open(path, options); - } - - @Override - public void close(Handle handle) throws IOException { - if (!isOpen()) { - throw new IOException("close(" + handle + ") client is closed"); - } - delegate.close(handle); - } - - @Override - public void remove(String path) throws IOException { - if (!isOpen()) { - throw new IOException("remove(" + path + ") client is closed"); - } - delegate.remove(path); - } - - @Override - public void rename(String oldPath, String newPath, Collection<CopyMode> options) throws IOException { - if (!isOpen()) { - throw new IOException("rename(" + oldPath + " => " + newPath + ")[" + options + "] client is closed"); - } - delegate.rename(oldPath, newPath, options); - } - - @Override - public int read(Handle handle, long fileOffset, byte[] dst, int dstOffset, int len) throws IOException { - if (!isOpen()) { - throw new IOException("read(" + handle + "/" + fileOffset + ")[" + dstOffset + "/" + len + "] client is closed"); - } - return delegate.read(handle, fileOffset, dst, dstOffset, len); - } - - @Override - public void write(Handle handle, long fileOffset, byte[] src, int srcOffset, int len) throws IOException { - if (!isOpen()) { - throw new IOException("write(" + handle + "/" + fileOffset + ")[" + srcOffset + "/" + len + "] client is closed"); - } - delegate.write(handle, fileOffset, src, srcOffset, len); - } - - @Override - public void mkdir(String path) throws IOException { - if (!isOpen()) { - throw new IOException("mkdir(" + path + ") client is closed"); - } - delegate.mkdir(path); - } - - @Override - public void rmdir(String path) throws IOException { - if (!isOpen()) { - throw new IOException("rmdir(" + path + ") client is closed"); - } - delegate.rmdir(path); - } - - @Override - public CloseableHandle openDir(String path) throws IOException { - if (!isOpen()) { - throw new IOException("openDir(" + path + ") client is closed"); - } - return delegate.openDir(path); - } - - @Override - public List<DirEntry> readDir(Handle handle) throws IOException { - if (!isOpen()) { - throw new IOException("readDir(" + handle + ") client is closed"); - } - return delegate.readDir(handle); - } - - @Override - public Iterable<DirEntry> listDir(Handle handle) throws IOException { - if (!isOpen()) { - throw new IOException("readDir(" + handle + ") client is closed"); - } - return delegate.listDir(handle); - } - - @Override - public String canonicalPath(String path) throws IOException { - if (!isOpen()) { - throw new IOException("canonicalPath(" + path + ") client is closed"); - } - return delegate.canonicalPath(path); - } - - @Override - public Attributes stat(String path) throws IOException { - if (!isOpen()) { - throw new IOException("stat(" + path + ") client is closed"); - } - return delegate.stat(path); - } - - @Override - public Attributes lstat(String path) throws IOException { - if (!isOpen()) { - throw new IOException("lstat(" + path + ") client is closed"); - } - return delegate.lstat(path); - } - - @Override - public Attributes stat(Handle handle) throws IOException { - if (!isOpen()) { - throw new IOException("stat(" + handle + ") client is closed"); - } - return delegate.stat(handle); - } - - @Override - public void setStat(String path, Attributes attributes) throws IOException { - if (!isOpen()) { - throw new IOException("setStat(" + path + ")[" + attributes + "] client is closed"); - } - delegate.setStat(path, attributes); - } - - @Override - public void setStat(Handle handle, Attributes attributes) throws IOException { - if (!isOpen()) { - throw new IOException("setStat(" + handle + ")[" + attributes + "] client is closed"); - } - delegate.setStat(handle, attributes); - } - - @Override - public String readLink(String path) throws IOException { - if (!isOpen()) { - throw new IOException("readLink(" + path + ") client is closed"); - } - return delegate.readLink(path); - } - - @Override - public void symLink(String linkPath, String targetPath) throws IOException { - if (!isOpen()) { - throw new IOException("symLink(" + linkPath + " => " + targetPath + ") client is closed"); - } - delegate.symLink(linkPath, targetPath); - } - - @Override - public Iterable<DirEntry> readDir(String path) throws IOException { - if (!isOpen()) { - throw new IOException("readDir(" + path + ") client is closed"); - } - return delegate.readDir(path); - } - - @Override - public InputStream read(String path) throws IOException { - return read(path, readSize); - } - - @Override - public InputStream read(String path, OpenMode... mode) throws IOException { - return read(path, readSize, mode); - } - - @Override - public InputStream read(String path, Collection<OpenMode> mode) throws IOException { - return read(path, readSize, mode); - } - - @Override - public InputStream read(String path, int bufferSize, Collection<OpenMode> mode) throws IOException { - if (!isOpen()) { - throw new IOException("read(" + path + ")[" + mode + "] size=" + bufferSize + ": client is closed"); - } - return delegate.read(path, bufferSize, mode); - } - - @Override - public OutputStream write(String path) throws IOException { - return write(path, writeSize); - } - - @Override - public OutputStream write(String path, OpenMode... mode) throws IOException { - return write(path, writeSize, mode); - } - - @Override - public OutputStream write(String path, Collection<OpenMode> mode) throws IOException { - return write(path, writeSize, mode); - } - - @Override - public OutputStream write(String path, int bufferSize, Collection<OpenMode> mode) throws IOException { - if (!isOpen()) { - throw new IOException("write(" + path + ")[" + mode + "] size=" + bufferSize + ": client is closed"); - } - return delegate.write(path, bufferSize, mode); - } - - @Override - public void link(String linkPath, String targetPath, boolean symbolic) throws IOException { - if (!isOpen()) { - throw new IOException("link(" + linkPath + " => " + targetPath + "] symbolic=" + symbolic + ": client is closed"); - } - delegate.link(linkPath, targetPath, symbolic); - } - - @Override - public void lock(Handle handle, long offset, long length, int mask) throws IOException { - if (!isOpen()) { - throw new IOException("lock(" + handle + ")[offset=" + offset + ", length=" + length + ", mask=0x" + Integer.toHexString(mask) + "] client is closed"); - } - delegate.lock(handle, offset, length, mask); - } - - @Override - public void unlock(Handle handle, long offset, long length) throws IOException { - if (!isOpen()) { - throw new IOException("unlock" + handle + ")[offset=" + offset + ", length=" + length + "] client is closed"); - } - delegate.unlock(handle, offset, length); - } - - @Override - public int send(int cmd, Buffer buffer) throws IOException { - if (!isOpen()) { - throw new IOException("send(cmd=" + SftpConstants.getCommandMessageName(cmd) + ") client is closed"); - } - - if (delegate instanceof RawSftpClient) { - return ((RawSftpClient) delegate).send(cmd, buffer); - } else { - throw new StreamCorruptedException("send(cmd=" + SftpConstants.getCommandMessageName(cmd) + ") delegate is not a " + RawSftpClient.class.getSimpleName()); - } - } - - @Override - public Buffer receive(int id) throws IOException { - if (!isOpen()) { - throw new IOException("receive(id=" + id + ") client is closed"); - } - - if (delegate instanceof RawSftpClient) { - return ((RawSftpClient) delegate).receive(id); - } else { - throw new StreamCorruptedException("receive(id=" + id + ") delegate is not a " + RawSftpClient.class.getSimpleName()); - } - } - } - - public static class DefaultUserPrincipalLookupService extends UserPrincipalLookupService { - public static final DefaultUserPrincipalLookupService INSTANCE = new DefaultUserPrincipalLookupService(); - - public DefaultUserPrincipalLookupService() { - super(); - } - - @Override - public UserPrincipal lookupPrincipalByName(String name) throws IOException { - return new DefaultUserPrincipal(name); - } - - @Override - public GroupPrincipal lookupPrincipalByGroupName(String group) throws IOException { - return new DefaultGroupPrincipal(group); - } - } - - public static class DefaultUserPrincipal implements UserPrincipal { - - private final String name; - - public DefaultUserPrincipal(String name) { - this.name = Objects.requireNonNull(name, "name is null"); - } - - @Override - public final String getName() { - return name; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DefaultUserPrincipal that = (DefaultUserPrincipal) o; - return Objects.equals(this.getName(), that.getName()); - } - - @Override - public int hashCode() { - return Objects.hashCode(getName()); - } - - @Override - public String toString() { - return getName(); - } - } - - public static class DefaultGroupPrincipal extends DefaultUserPrincipal implements GroupPrincipal { - public DefaultGroupPrincipal(String name) { - super(name); - } - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e3b8acd7/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemChannel.java ---------------------------------------------------------------------- diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemChannel.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemChannel.java deleted file mode 100644 index 40948bf..0000000 --- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemChannel.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.sshd.client.subsystem.sftp; - -import java.io.IOException; -import java.util.Collection; -import java.util.Objects; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class SftpFileSystemChannel extends SftpRemotePathChannel { - public SftpFileSystemChannel(SftpPath p, Collection<SftpClient.OpenMode> modes) throws IOException { - this(Objects.requireNonNull(p, "No target path").toString(), p.getFileSystem(), modes); - } - - public SftpFileSystemChannel(String remotePath, SftpFileSystem fs, Collection<SftpClient.OpenMode> modes) throws IOException { - super(remotePath, Objects.requireNonNull(fs, "No SFTP file system").getClient(), true, modes); - } -}
