You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2018/04/16 11:48:15 UTC
[28/30] mina-sshd git commit: [SSHD-815] Extract SFTP in its own
module
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirEntryIterator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirEntryIterator.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirEntryIterator.java
deleted file mode 100644
index abf3a1d..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirEntryIterator.java
+++ /dev/null
@@ -1,194 +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.Closeable;
-import java.io.IOException;
-import java.nio.channels.Channel;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.apache.sshd.client.subsystem.sftp.SftpClient.DirEntry;
-import org.apache.sshd.client.subsystem.sftp.SftpClient.Handle;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.logging.AbstractLoggingBean;
-
-/**
- * Iterates over the available directory entries for a given path. <B>Note:</B>
- * if the iteration is carried out until no more entries are available, then
- * no need to close the iterator. Otherwise, it is recommended to close it so
- * as to release the internal handle.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class SftpDirEntryIterator extends AbstractLoggingBean implements Iterator<DirEntry>, Channel {
- private final AtomicReference<Boolean> eolIndicator = new AtomicReference<>();
- private final AtomicBoolean open = new AtomicBoolean(true);
- private final SftpClient client;
- private final String dirPath;
- private final boolean closeOnFinished;
- private Handle dirHandle;
- private List<DirEntry> dirEntries;
- private int index;
-
- /**
- * @param client The {@link SftpClient} instance to use for the iteration
- * @param path The remote directory path
- * @throws IOException If failed to gain access to the remote directory path
- */
- public SftpDirEntryIterator(SftpClient client, String path) throws IOException {
- this(client, path, client.openDir(path), true);
- }
-
- /**
- * @param client The {@link SftpClient} instance to use for the iteration
- * @param dirHandle The directory {@link Handle} to use for listing the entries
- */
- public SftpDirEntryIterator(SftpClient client, Handle dirHandle) {
- this(client, Objects.toString(dirHandle, null), dirHandle, false);
- }
-
- /**
- * @param client The {@link SftpClient} instance to use for the iteration
- * @param path A hint as to the remote directory path - used only for logging
- * @param dirHandle The directory {@link Handle} to use for listing the entries
- * @param closeOnFinished If {@code true} then close the directory handle when
- * all entries have been exhausted
- */
- public SftpDirEntryIterator(SftpClient client, String path, Handle dirHandle, boolean closeOnFinished) {
- this.client = Objects.requireNonNull(client, "No SFTP client instance");
- this.dirPath = ValidateUtils.checkNotNullAndNotEmpty(path, "No path");
- this.dirHandle = Objects.requireNonNull(dirHandle, "No directory handle");
- this.closeOnFinished = closeOnFinished;
- this.dirEntries = load(dirHandle);
- }
-
- /**
- * The client instance
- *
- * @return {@link SftpClient} instance used to access the remote folder
- */
- public final SftpClient getClient() {
- return client;
- }
-
- /**
- * The remotely accessed directory path
- *
- * @return Remote directory hint - may be the handle's value if accessed directly
- * via a {@link Handle} instead of via a path - used only for logging
- */
- public final String getPath() {
- return dirPath;
- }
-
- /**
- * @return The directory {@link Handle} used to access the remote directory
- */
- public final Handle getHandle() {
- return dirHandle;
- }
-
- @Override
- public boolean hasNext() {
- return (dirEntries != null) && (index < dirEntries.size());
- }
-
- @Override
- public DirEntry next() {
- DirEntry entry = dirEntries.get(index++);
- if (index >= dirEntries.size()) {
- index = 0;
-
- try {
- dirEntries = load(getHandle());
- } catch (RuntimeException e) {
- dirEntries = null;
- throw e;
- }
- }
-
- return entry;
- }
-
- @Override
- public boolean isOpen() {
- return open.get();
- }
-
- public boolean isCloseOnFinished() {
- return closeOnFinished;
- }
-
- @Override
- public void close() throws IOException {
- if (open.getAndSet(false)) {
- Handle handle = getHandle();
- if ((handle instanceof Closeable) && isCloseOnFinished()) {
- if (log.isDebugEnabled()) {
- log.debug("close(" + getPath() + ") handle=" + handle);
- }
- ((Closeable) handle).close();
- }
- }
- }
-
- protected List<DirEntry> load(Handle handle) {
- try {
- // check if previous call yielded an end-of-list indication
- Boolean eolReached = eolIndicator.getAndSet(null);
- if ((eolReached != null) && eolReached) {
- if (log.isTraceEnabled()) {
- log.trace("load({})[{}] exhausted all entries on previous call", getPath(), handle);
- }
- return null;
- }
-
- List<DirEntry> entries = client.readDir(handle, eolIndicator);
- eolReached = eolIndicator.get();
- if ((entries == null) || ((eolReached != null) && eolReached)) {
- if (log.isTraceEnabled()) {
- log.trace("load({})[{}] exhausted all entries - EOL={}", getPath(), handle, eolReached);
- }
- close();
- }
-
- return entries;
- } catch (IOException e) {
- try {
- close();
- } catch (IOException t) {
- if (log.isTraceEnabled()) {
- log.trace(t.getClass().getSimpleName() + " while close handle=" + handle
- + " due to " + e.getClass().getSimpleName() + " [" + e.getMessage() + "]"
- + ": " + t.getMessage());
- }
- }
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException("readDir(" + getPath() + ")[" + getHandle() + "] Iterator#remove() N/A");
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirectoryStream.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirectoryStream.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirectoryStream.java
deleted file mode 100644
index 5f48966..0000000
--- a/sshd-core/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:dev@mina.apache.org">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/251db9b9/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileStore.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileStore.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileStore.java
deleted file mode 100644
index 8a6f1f1..0000000
--- a/sshd-core/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:dev@mina.apache.org">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/251db9b9/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java
deleted file mode 100644
index bc790b3..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java
+++ /dev/null
@@ -1,596 +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.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 Set<String> UNIVERSAL_SUPPORTED_VIEWS =
- Collections.unmodifiableSet(
- GenericUtils.asSortedSet(String.CASE_INSENSITIVE_ORDER,
- "basic", "posix", "owner"));
-
- private final String id;
- private final ClientSession clientSession;
- 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, SftpVersionSelector selector) throws IOException {
- super(provider);
- this.id = id;
- this.clientSession = Objects.requireNonNull(session, "No client session");
- 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 = session.createSftpClient(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() + "[" + String.valueOf(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/251db9b9/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemChannel.java
deleted file mode 100644
index 40948bf..0000000
--- a/sshd-core/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:dev@mina.apache.org">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);
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/251db9b9/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
deleted file mode 100644
index 13686f7..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
+++ /dev/null
@@ -1,1249 +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.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.net.URI;
-import java.nio.channels.FileChannel;
-import java.nio.charset.Charset;
-import java.nio.file.AccessDeniedException;
-import java.nio.file.AccessMode;
-import java.nio.file.CopyOption;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileAlreadyExistsException;
-import java.nio.file.FileStore;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystemAlreadyExistsException;
-import java.nio.file.FileSystemException;
-import java.nio.file.FileSystemNotFoundException;
-import java.nio.file.LinkOption;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.OpenOption;
-import java.nio.file.Path;
-import java.nio.file.ProviderMismatchException;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.AclEntry;
-import java.nio.file.attribute.AclFileAttributeView;
-import java.nio.file.attribute.BasicFileAttributeView;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.nio.file.attribute.FileAttribute;
-import java.nio.file.attribute.FileAttributeView;
-import java.nio.file.attribute.FileOwnerAttributeView;
-import java.nio.file.attribute.FileTime;
-import java.nio.file.attribute.GroupPrincipal;
-import java.nio.file.attribute.PosixFileAttributeView;
-import java.nio.file.attribute.PosixFileAttributes;
-import java.nio.file.attribute.PosixFilePermission;
-import java.nio.file.attribute.UserPrincipal;
-import java.nio.file.spi.FileSystemProvider;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Map;
-import java.util.NavigableMap;
-import java.util.Objects;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.client.subsystem.sftp.SftpClient.Attributes;
-import org.apache.sshd.common.PropertyResolver;
-import org.apache.sshd.common.PropertyResolverUtils;
-import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.config.SshConfigFileReader;
-import org.apache.sshd.common.io.IoSession;
-import org.apache.sshd.common.subsystem.sftp.SftpConstants;
-import org.apache.sshd.common.subsystem.sftp.SftpException;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.NumberUtils;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.io.IoUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A registered {@link FileSystemProvider} that registers the "sftp://"
- * scheme so that URLs with this protocol are handled as remote SFTP {@link Path}-s
- * - e.g., "{@code sftp://user:password@host/remote/file/path}"
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class SftpFileSystemProvider extends FileSystemProvider {
- public static final String READ_BUFFER_PROP_NAME = "sftp-fs-read-buffer-size";
- public static final int DEFAULT_READ_BUFFER_SIZE = SftpClient.DEFAULT_READ_BUFFER_SIZE;
- public static final String WRITE_BUFFER_PROP_NAME = "sftp-fs-write-buffer-size";
- public static final int DEFAULT_WRITE_BUFFER_SIZE = SftpClient.DEFAULT_WRITE_BUFFER_SIZE;
- public static final String CONNECT_TIME_PROP_NAME = "sftp-fs-connect-time";
- public static final long DEFAULT_CONNECT_TIME = SftpClient.DEFAULT_WAIT_TIMEOUT;
- public static final String AUTH_TIME_PROP_NAME = "sftp-fs-auth-time";
- public static final long DEFAULT_AUTH_TIME = SftpClient.DEFAULT_WAIT_TIMEOUT;
- public static final String NAME_DECORDER_CHARSET_PROP_NAME = "sftp-fs-name-decoder-charset";
- public static final Charset DEFAULT_NAME_DECODER_CHARSET = SftpClient.DEFAULT_NAME_DECODING_CHARSET;
-
- /**
- * <P>
- * URI parameter that can be used to specify a special version selection. Options are:
- * </P>
- * <UL>
- * <LI>{@code max} - select maximum available version for the client</LI>
- * <LI>{@code min} - select minimum available version for the client</LI>
- * <LI>{@code current} - whatever version is reported by the server</LI>
- * <LI>{@code nnn} - select <U>only</U> the specified version</LI>
- * <LI>{@code a,b,c} - select one of the specified versions (if available) in preference order</LI>
- * </UL>
- */
- public static final String VERSION_PARAM = "version";
-
- public static final Set<Class<? extends FileAttributeView>> UNIVERSAL_SUPPORTED_VIEWS =
- Collections.unmodifiableSet(GenericUtils.asSet(
- PosixFileAttributeView.class,
- FileOwnerAttributeView.class,
- BasicFileAttributeView.class
- ));
-
- protected final Logger log;
-
- private final SshClient client;
- private final SftpVersionSelector selector;
- private final NavigableMap<String, SftpFileSystem> fileSystems = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-
- public SftpFileSystemProvider() {
- this((SshClient) null);
- }
-
- public SftpFileSystemProvider(SftpVersionSelector selector) {
- this(null, selector);
- }
-
- /**
- * @param client The {@link SshClient} to use - if {@code null} then a
- * default one will be setup and started. Otherwise, it is assumed that
- * the client has already been started
- * @see SshClient#setUpDefaultClient()
- */
- public SftpFileSystemProvider(SshClient client) {
- this(client, SftpVersionSelector.CURRENT);
- }
-
- public SftpFileSystemProvider(SshClient client, SftpVersionSelector selector) {
- this.log = LoggerFactory.getLogger(getClass());
- this.selector = selector;
- if (client == null) {
- // TODO: make this configurable using system properties
- client = SshClient.setUpDefaultClient();
- client.start();
- }
- this.client = client;
- }
-
- @Override
- public String getScheme() {
- return SftpConstants.SFTP_SUBSYSTEM_NAME;
- }
-
- public final SftpVersionSelector getSftpVersionSelector() {
- return selector;
- }
-
- @Override // NOTE: co-variant return
- public SftpFileSystem newFileSystem(URI uri, Map<String, ?> env) throws IOException {
- String host = ValidateUtils.checkNotNullAndNotEmpty(uri.getHost(), "Host not provided");
- int port = uri.getPort();
- if (port <= 0) {
- port = SshConfigFileReader.DEFAULT_PORT;
- }
-
- String userInfo = ValidateUtils.checkNotNullAndNotEmpty(uri.getUserInfo(), "UserInfo not provided");
- String[] ui = GenericUtils.split(userInfo, ':');
- ValidateUtils.checkTrue(GenericUtils.length(ui) == 2, "Invalid user info: %s", userInfo);
-
- String username = ui[0];
- String password = ui[1];
- String id = getFileSystemIdentifier(host, port, username);
- Map<String, Object> params = resolveFileSystemParameters(env, parseURIParameters(uri));
- PropertyResolver resolver = PropertyResolverUtils.toPropertyResolver(params);
- SftpVersionSelector selector = resolveSftpVersionSelector(uri, getSftpVersionSelector(), resolver);
- Charset decodingCharset =
- PropertyResolverUtils.getCharset(resolver, NAME_DECORDER_CHARSET_PROP_NAME, DEFAULT_NAME_DECODER_CHARSET);
- long maxConnectTime = resolver.getLongProperty(CONNECT_TIME_PROP_NAME, DEFAULT_CONNECT_TIME);
- long maxAuthTime = resolver.getLongProperty(AUTH_TIME_PROP_NAME, DEFAULT_AUTH_TIME);
-
- SftpFileSystem fileSystem;
- synchronized (fileSystems) {
- if (fileSystems.containsKey(id)) {
- throw new FileSystemAlreadyExistsException(id);
- }
-
- // TODO try and find a way to avoid doing this while locking the file systems cache
- ClientSession session = null;
- try {
- session = client.connect(username, host, port)
- .verify(maxConnectTime)
- .getSession();
- if (GenericUtils.size(params) > 0) {
- // Cannot use forEach because the session is not effectively final
- for (Map.Entry<String, ?> pe : params.entrySet()) {
- String key = pe.getKey();
- Object value = pe.getValue();
- if (VERSION_PARAM.equalsIgnoreCase(key)) {
- continue;
- }
-
- PropertyResolverUtils.updateProperty(session, key, value);
- }
-
- PropertyResolverUtils.updateProperty(session, SftpClient.NAME_DECODING_CHARSET, decodingCharset);
- }
-
- session.addPasswordIdentity(password);
- session.auth().verify(maxAuthTime);
-
- fileSystem = new SftpFileSystem(this, id, session, selector);
- fileSystems.put(id, fileSystem);
- } catch (Exception e) {
- if (session != null) {
- try {
- session.close();
- } catch (IOException t) {
- if (log.isDebugEnabled()) {
- log.debug("Failed (" + t.getClass().getSimpleName() + ")"
- + " to close session for new file system on " + host + ":" + port
- + " due to " + e.getClass().getSimpleName() + "[" + e.getMessage() + "]"
- + ": " + t.getMessage());
- }
- }
- }
-
- if (e instanceof IOException) {
- throw (IOException) e;
- } else if (e instanceof RuntimeException) {
- throw (RuntimeException) e;
- } else {
- throw new IOException(e);
- }
- }
- }
-
- fileSystem.setReadBufferSize(resolver.getIntProperty(READ_BUFFER_PROP_NAME, DEFAULT_READ_BUFFER_SIZE));
- fileSystem.setWriteBufferSize(resolver.getIntProperty(WRITE_BUFFER_PROP_NAME, DEFAULT_WRITE_BUFFER_SIZE));
- if (log.isDebugEnabled()) {
- log.debug("newFileSystem({}): {}", uri.toASCIIString(), fileSystem);
- }
- return fileSystem;
- }
-
- protected SftpVersionSelector resolveSftpVersionSelector(URI uri, SftpVersionSelector defaultSelector, PropertyResolver resolver) {
- String preference = resolver.getString(VERSION_PARAM);
- if (GenericUtils.isEmpty(preference)) {
- return defaultSelector;
- }
-
- if (log.isDebugEnabled()) {
- log.debug("resolveSftpVersionSelector({}) preference={}", uri, preference);
- }
-
- if ("max".equalsIgnoreCase(preference)) {
- return SftpVersionSelector.MAXIMUM;
- } else if ("min".equalsIgnoreCase(preference)) {
- return SftpVersionSelector.MINIMUM;
- } else if ("current".equalsIgnoreCase(preference)) {
- return SftpVersionSelector.CURRENT;
- }
-
- String[] values = GenericUtils.split(preference, ',');
- if (values.length == 1) {
- return SftpVersionSelector.fixedVersionSelector(Integer.parseInt(values[0]));
- }
-
- int[] preferred = new int[values.length];
- for (int index = 0; index < values.length; index++) {
- preferred[index] = Integer.parseInt(values[index]);
- }
-
- return SftpVersionSelector.preferredVersionSelector(preferred);
- }
-
- // NOTE: URI parameters override environment ones
- public static Map<String, Object> resolveFileSystemParameters(Map<String, ?> env, Map<String, Object> uriParams) {
- if (GenericUtils.isEmpty(env)) {
- return GenericUtils.isEmpty(uriParams) ? Collections.emptyMap() : uriParams;
- } else if (GenericUtils.isEmpty(uriParams)) {
- return Collections.unmodifiableMap(env);
- }
-
- Map<String, Object> resolved = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- resolved.putAll(env);
- resolved.putAll(uriParams);
- return resolved;
- }
-
- public static Map<String, Object> parseURIParameters(URI uri) {
- return parseURIParameters((uri == null) ? "" : uri.getQuery());
- }
-
- public static Map<String, Object> parseURIParameters(String params) {
- if (GenericUtils.isEmpty(params)) {
- return Collections.emptyMap();
- }
-
- if (params.charAt(0) == '?') {
- if (params.length() == 1) {
- return Collections.emptyMap();
- }
- params = params.substring(1);
- }
-
- String[] pairs = GenericUtils.split(params, '&');
- Map<String, Object> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- for (String p : pairs) {
- int pos = p.indexOf('=');
- if (pos < 0) {
- map.put(p, Boolean.TRUE);
- continue;
- }
-
- String key = p.substring(0, pos);
- String value = p.substring(pos + 1);
- if (NumberUtils.isIntegerNumber(value)) {
- map.put(key, Long.parseLong(value));
- } else {
- map.put(key, value);
- }
- }
-
- return map;
- }
-
- public SftpFileSystem newFileSystem(ClientSession session) throws IOException {
- String id = getFileSystemIdentifier(session);
- SftpFileSystem fileSystem;
- synchronized (fileSystems) {
- if (fileSystems.containsKey(id)) {
- throw new FileSystemAlreadyExistsException(id);
- }
- fileSystem = new SftpFileSystem(this, id, session, getSftpVersionSelector());
- fileSystems.put(id, fileSystem);
- }
-
- fileSystem.setReadBufferSize(session.getIntProperty(READ_BUFFER_PROP_NAME, DEFAULT_READ_BUFFER_SIZE));
- fileSystem.setWriteBufferSize(session.getIntProperty(WRITE_BUFFER_PROP_NAME, DEFAULT_WRITE_BUFFER_SIZE));
- if (log.isDebugEnabled()) {
- log.debug("newFileSystem: {}", fileSystem);
- }
-
- return fileSystem;
- }
-
- @Override
- public FileSystem getFileSystem(URI uri) {
- String id = getFileSystemIdentifier(uri);
- SftpFileSystem fs = getFileSystem(id);
- if (fs == null) {
- throw new FileSystemNotFoundException(id);
- }
- return fs;
- }
-
- /**
- * @param id File system identifier - ignored if {@code null}/empty
- * @return The removed {@link SftpFileSystem} - {@code null} if no match
- */
- public SftpFileSystem removeFileSystem(String id) {
- if (GenericUtils.isEmpty(id)) {
- return null;
- }
-
- SftpFileSystem removed;
- synchronized (fileSystems) {
- removed = fileSystems.remove(id);
- }
-
- if (log.isDebugEnabled()) {
- log.debug("removeFileSystem({}): {}", id, removed);
- }
- return removed;
- }
-
- /**
- * @param id File system identifier - ignored if {@code null}/empty
- * @return The cached {@link SftpFileSystem} - {@code null} if no match
- */
- public SftpFileSystem getFileSystem(String id) {
- if (GenericUtils.isEmpty(id)) {
- return null;
- }
-
- synchronized (fileSystems) {
- return fileSystems.get(id);
- }
- }
-
- @Override
- public Path getPath(URI uri) {
- FileSystem fs = getFileSystem(uri);
- return fs.getPath(uri.getPath());
- }
-
- @Override
- public FileChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
- return newFileChannel(path, options, attrs);
- }
-
- @Override
- public FileChannel newFileChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
- Collection<SftpClient.OpenMode> modes = SftpClient.OpenMode.fromOpenOptions(options);
- if (modes.isEmpty()) {
- modes = EnumSet.of(SftpClient.OpenMode.Read, SftpClient.OpenMode.Write);
- }
- // TODO: process file attributes
- return new SftpFileSystemChannel(toSftpPath(path), modes);
- }
-
- @Override
- public DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter) throws IOException {
- final SftpPath p = toSftpPath(dir);
- return new SftpDirectoryStream(p);
- }
-
- @Override
- public void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException {
- SftpPath p = toSftpPath(dir);
- SftpFileSystem fs = p.getFileSystem();
- if (log.isDebugEnabled()) {
- log.debug("createDirectory({}) {} ({})", fs, dir, Arrays.asList(attrs));
- }
- try (SftpClient sftp = fs.getClient()) {
- try {
- sftp.mkdir(dir.toString());
- } catch (SftpException e) {
- int sftpStatus = e.getStatus();
- if ((sftp.getVersion() == SftpConstants.SFTP_V3) && (sftpStatus == SftpConstants.SSH_FX_FAILURE)) {
- try {
- Attributes attributes = sftp.stat(dir.toString());
- if (attributes != null) {
- throw new FileAlreadyExistsException(p.toString());
- }
- } catch (SshException e2) {
- e.addSuppressed(e2);
- }
- }
- if (sftpStatus == SftpConstants.SSH_FX_FILE_ALREADY_EXISTS) {
- throw new FileAlreadyExistsException(p.toString());
- }
- throw e;
- }
- for (FileAttribute<?> attr : attrs) {
- setAttribute(p, attr.name(), attr.value());
- }
- }
- }
-
- @Override
- public void delete(Path path) throws IOException {
- SftpPath p = toSftpPath(path);
- checkAccess(p, AccessMode.WRITE);
-
- SftpFileSystem fs = p.getFileSystem();
- if (log.isDebugEnabled()) {
- log.debug("delete({}) {}", fs, path);
- }
-
- try (SftpClient sftp = fs.getClient()) {
- BasicFileAttributes attributes = readAttributes(path, BasicFileAttributes.class);
- if (attributes.isDirectory()) {
- sftp.rmdir(path.toString());
- } else {
- sftp.remove(path.toString());
- }
- }
- }
-
- @Override
- public void copy(Path source, Path target, CopyOption... options) throws IOException {
- SftpPath src = toSftpPath(source);
- SftpPath dst = toSftpPath(target);
- if (src.getFileSystem() != dst.getFileSystem()) {
- throw new ProviderMismatchException("Mismatched file system providers for " + src + " vs. " + dst);
- }
- checkAccess(src);
-
- boolean replaceExisting = false;
- boolean copyAttributes = false;
- boolean noFollowLinks = false;
- for (CopyOption opt : options) {
- replaceExisting |= opt == StandardCopyOption.REPLACE_EXISTING;
- copyAttributes |= opt == StandardCopyOption.COPY_ATTRIBUTES;
- noFollowLinks |= opt == LinkOption.NOFOLLOW_LINKS;
- }
- LinkOption[] linkOptions = IoUtils.getLinkOptions(!noFollowLinks);
-
- // attributes of source file
- BasicFileAttributes attrs = readAttributes(source, BasicFileAttributes.class, linkOptions);
- if (attrs.isSymbolicLink()) {
- throw new IOException("Copying of symbolic links not supported");
- }
-
- // delete target if it exists and REPLACE_EXISTING is specified
- Boolean status = IoUtils.checkFileExists(target, linkOptions);
- if (status == null) {
- throw new AccessDeniedException("Existence cannot be determined for copy target: " + target);
- }
-
- if (log.isDebugEnabled()) {
- log.debug("copy({})[{}] {} => {}", src.getFileSystem(), Arrays.asList(options), src, dst);
- }
-
- if (replaceExisting) {
- deleteIfExists(target);
- } else {
- if (status) {
- throw new FileAlreadyExistsException(target.toString());
- }
- }
-
- // create directory or copy file
- if (attrs.isDirectory()) {
- createDirectory(target);
- } else {
- try (InputStream in = newInputStream(source);
- OutputStream os = newOutputStream(target)) {
- IoUtils.copy(in, os);
- }
- }
-
- // copy basic attributes to target
- if (copyAttributes) {
- BasicFileAttributeView view = getFileAttributeView(target, BasicFileAttributeView.class, linkOptions);
- try {
- view.setTimes(attrs.lastModifiedTime(), attrs.lastAccessTime(), attrs.creationTime());
- } catch (Throwable x) {
- // rollback
- try {
- delete(target);
- } catch (Throwable suppressed) {
- x.addSuppressed(suppressed);
- }
- throw x;
- }
- }
- }
-
- @Override
- public void move(Path source, Path target, CopyOption... options) throws IOException {
- SftpPath src = toSftpPath(source);
- SftpFileSystem fsSrc = src.getFileSystem();
- SftpPath dst = toSftpPath(target);
-
- if (src.getFileSystem() != dst.getFileSystem()) {
- throw new ProviderMismatchException("Mismatched file system providers for " + src + " vs. " + dst);
- }
- checkAccess(src);
-
- boolean replaceExisting = false;
- boolean copyAttributes = false;
- boolean noFollowLinks = false;
- for (CopyOption opt : options) {
- replaceExisting |= opt == StandardCopyOption.REPLACE_EXISTING;
- copyAttributes |= opt == StandardCopyOption.COPY_ATTRIBUTES;
- noFollowLinks |= opt == LinkOption.NOFOLLOW_LINKS;
- }
- LinkOption[] linkOptions = IoUtils.getLinkOptions(noFollowLinks);
-
- // attributes of source file
- BasicFileAttributes attrs = readAttributes(source, BasicFileAttributes.class, linkOptions);
- if (attrs.isSymbolicLink()) {
- throw new IOException("Moving of source symbolic link (" + source + ") to " + target + " not supported");
- }
-
- // delete target if it exists and REPLACE_EXISTING is specified
- Boolean status = IoUtils.checkFileExists(target, linkOptions);
- if (status == null) {
- throw new AccessDeniedException("Existence cannot be determined for move target " + target);
- }
-
- if (log.isDebugEnabled()) {
- log.debug("move({})[{}] {} => {}", src.getFileSystem(), Arrays.asList(options), src, dst);
- }
-
- if (replaceExisting) {
- deleteIfExists(target);
- } else if (status) {
- throw new FileAlreadyExistsException(target.toString());
- }
-
- try (SftpClient sftp = fsSrc.getClient()) {
- sftp.rename(src.toString(), dst.toString());
- }
-
- // copy basic attributes to target
- if (copyAttributes) {
- BasicFileAttributeView view = getFileAttributeView(target, BasicFileAttributeView.class, linkOptions);
- try {
- view.setTimes(attrs.lastModifiedTime(), attrs.lastAccessTime(), attrs.creationTime());
- } catch (Throwable x) {
- // rollback
- try {
- delete(target);
- } catch (Throwable suppressed) {
- x.addSuppressed(suppressed);
- }
- throw x;
- }
- }
- }
-
- @Override
- public boolean isSameFile(Path path1, Path path2) throws IOException {
- SftpPath p1 = toSftpPath(path1);
- SftpPath p2 = toSftpPath(path2);
- if (p1.getFileSystem() != p2.getFileSystem()) {
- throw new ProviderMismatchException("Mismatched file system providers for " + p1 + " vs. " + p2);
- }
- checkAccess(p1);
- checkAccess(p2);
- return p1.equals(p2);
- }
-
- @Override
- public boolean isHidden(Path path) throws IOException {
- return false;
- }
-
- @Override
- public FileStore getFileStore(Path path) throws IOException {
- FileSystem fs = path.getFileSystem();
- if (!(fs instanceof SftpFileSystem)) {
- throw new FileSystemException(path.toString(), path.toString(), "getFileStore(" + path + ") path not attached to an SFTP file system");
- }
-
- SftpFileSystem sftpFs = (SftpFileSystem) fs;
- String id = sftpFs.getId();
- SftpFileSystem cached = getFileSystem(id);
- if (cached != sftpFs) {
- throw new FileSystemException(path.toString(), path.toString(), "Mismatched file system instance for id=" + id);
- }
-
- return sftpFs.getFileStores().get(0);
- }
-
- @Override
- public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs) throws IOException {
- SftpPath l = toSftpPath(link);
- SftpFileSystem fsLink = l.getFileSystem();
- SftpPath t = toSftpPath(target);
- if (fsLink != t.getFileSystem()) {
- throw new ProviderMismatchException("Mismatched file system providers for " + l + " vs. " + t);
- }
-
- if (log.isDebugEnabled()) {
- log.debug("createSymbolicLink({})[{}] {} => {}", fsLink, Arrays.asList(attrs), link, target);
- }
-
- try (SftpClient client = fsLink.getClient()) {
- client.symLink(l.toString(), t.toString());
- }
- }
-
- @Override
- public Path readSymbolicLink(Path link) throws IOException {
- SftpPath l = toSftpPath(link);
- SftpFileSystem fsLink = l.getFileSystem();
- try (SftpClient client = fsLink.getClient()) {
- String linkPath = client.readLink(l.toString());
- if (log.isDebugEnabled()) {
- log.debug("readSymbolicLink({})[{}] {} => {}", fsLink, link, linkPath);
- }
-
- return fsLink.getPath(linkPath);
- }
- }
-
- @Override
- public void checkAccess(Path path, AccessMode... modes) throws IOException {
- SftpPath p = toSftpPath(path);
- boolean w = false;
- boolean x = false;
- if (GenericUtils.length(modes) > 0) {
- for (AccessMode mode : modes) {
- switch (mode) {
- case READ:
- break;
- case WRITE:
- w = true;
- break;
- case EXECUTE:
- x = true;
- break;
- default:
- throw new UnsupportedOperationException("Unsupported mode: " + mode);
- }
- }
- }
-
- BasicFileAttributes attrs = getFileAttributeView(p, BasicFileAttributeView.class).readAttributes();
- if ((attrs == null) && !(p.isAbsolute() && p.getNameCount() == 0)) {
- throw new NoSuchFileException(path.toString());
- }
-
- SftpFileSystem fs = p.getFileSystem();
- if (x || (w && fs.isReadOnly())) {
- throw new AccessDeniedException("Filesystem is read-only: " + path.toString());
- }
- }
-
- @Override
- public <V extends FileAttributeView> V getFileAttributeView(Path path, Class<V> type, final LinkOption... options) {
- if (isSupportedFileAttributeView(path, type)) {
- if (AclFileAttributeView.class.isAssignableFrom(type)) {
- return type.cast(new SftpAclFileAttributeView(this, path, options));
- } else if (BasicFileAttributeView.class.isAssignableFrom(type)) {
- return type.cast(new SftpPosixFileAttributeView(this, path, options));
- }
- }
-
- throw new UnsupportedOperationException("getFileAttributeView(" + path + ") view not supported: " + type.getSimpleName());
- }
-
- public boolean isSupportedFileAttributeView(Path path, Class<? extends FileAttributeView> type) {
- return isSupportedFileAttributeView(toSftpPath(path).getFileSystem(), type);
- }
-
- public boolean isSupportedFileAttributeView(SftpFileSystem fs, Class<? extends FileAttributeView> type) {
- Collection<String> views = fs.supportedFileAttributeViews();
- if ((type == null) || GenericUtils.isEmpty(views)) {
- return false;
- } else if (PosixFileAttributeView.class.isAssignableFrom(type)) {
- return views.contains("posix");
- } else if (AclFileAttributeView.class.isAssignableFrom(type)) {
- return views.contains("acl"); // must come before owner view
- } else if (FileOwnerAttributeView.class.isAssignableFrom(type)) {
- return views.contains("owner");
- } else if (BasicFileAttributeView.class.isAssignableFrom(type)) {
- return views.contains("basic"); // must be last
- } else {
- return false;
- }
- }
-
- @Override
- public <A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type, LinkOption... options) throws IOException {
- if (type.isAssignableFrom(PosixFileAttributes.class)) {
- return type.cast(getFileAttributeView(path, PosixFileAttributeView.class, options).readAttributes());
- }
-
- throw new UnsupportedOperationException("readAttributes(" + path + ")[" + type.getSimpleName() + "] N/A");
- }
-
- @Override
- public Map<String, Object> readAttributes(Path path, String attributes, LinkOption... options) throws IOException {
- String view;
- String attrs;
- int i = attributes.indexOf(':');
- if (i == -1) {
- view = "basic";
- attrs = attributes;
- } else {
- view = attributes.substring(0, i++);
- attrs = attributes.substring(i);
- }
-
- return readAttributes(path, view, attrs, options);
- }
-
- public Map<String, Object> readAttributes(Path path, String view, String attrs, LinkOption... options) throws IOException {
- SftpPath p = toSftpPath(path);
- SftpFileSystem fs = p.getFileSystem();
- Collection<String> views = fs.supportedFileAttributeViews();
- if (GenericUtils.isEmpty(views) || (!views.contains(view))) {
- throw new UnsupportedOperationException("readAttributes(" + path + ")[" + view + ":" + attrs + "] view not supported: " + views);
- }
-
- if ("basic".equalsIgnoreCase(view) || "posix".equalsIgnoreCase(view) || "owner".equalsIgnoreCase(view)) {
- return readPosixViewAttributes(p, view, attrs, options);
- } else if ("acl".equalsIgnoreCase(view)) {
- return readAclViewAttributes(p, view, attrs, options);
- } else {
- return readCustomViewAttributes(p, view, attrs, options);
- }
- }
-
- protected Map<String, Object> readCustomViewAttributes(SftpPath path, String view, String attrs, LinkOption... options) throws IOException {
- throw new UnsupportedOperationException("readCustomViewAttributes(" + path + ")[" + view + ":" + attrs + "] view not supported");
- }
-
- protected NavigableMap<String, Object> readAclViewAttributes(SftpPath path, String view, String attrs, LinkOption... options) throws IOException {
- if ("*".equals(attrs)) {
- attrs = "acl,owner";
- }
-
- SftpFileSystem fs = path.getFileSystem();
- SftpClient.Attributes attributes;
- try (SftpClient client = fs.getClient()) {
- attributes = readRemoteAttributes(path, options);
- }
-
- NavigableMap<String, Object> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- String[] attrValues = GenericUtils.split(attrs, ',');
- boolean traceEnabled = log.isTraceEnabled();
- for (String attr : attrValues) {
- switch (attr) {
- case "acl":
- List<AclEntry> acl = attributes.getAcl();
- if (acl != null) {
- map.put(attr, acl);
- }
- break;
- case "owner":
- String owner = attributes.getOwner();
- if (GenericUtils.length(owner) > 0) {
- map.put(attr, new SftpFileSystem.DefaultUserPrincipal(owner));
- }
- break;
- default:
- if (traceEnabled) {
- log.trace("readAclViewAttributes({})[{}] unknown attribute: {}", fs, attrs, attr);
- }
- }
- }
-
- return map;
- }
-
- public SftpClient.Attributes readRemoteAttributes(SftpPath path, LinkOption... options) throws IOException {
- SftpFileSystem fs = path.getFileSystem();
- try (SftpClient client = fs.getClient()) {
- try {
- SftpClient.Attributes attrs;
- if (IoUtils.followLinks(options)) {
- attrs = client.stat(path.toString());
- } else {
- attrs = client.lstat(path.toString());
- }
- if (log.isTraceEnabled()) {
- log.trace("readRemoteAttributes({})[{}]: {}", fs, path, attrs);
- }
- return attrs;
- } catch (SftpException e) {
- if (e.getStatus() == SftpConstants.SSH_FX_NO_SUCH_FILE) {
- throw new NoSuchFileException(path.toString());
- }
- throw e;
- }
- }
- }
-
- protected NavigableMap<String, Object> readPosixViewAttributes(
- SftpPath path, String view, String attrs, LinkOption... options)
- throws IOException {
- PosixFileAttributes v = readAttributes(path, PosixFileAttributes.class, options);
- if ("*".equals(attrs)) {
- attrs = "lastModifiedTime,lastAccessTime,creationTime,size,isRegularFile,isDirectory,isSymbolicLink,isOther,fileKey,owner,permissions,group";
- }
-
- NavigableMap<String, Object> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- boolean traceEnabled = log.isTraceEnabled();
- String[] attrValues = GenericUtils.split(attrs, ',');
- for (String attr : attrValues) {
- switch (attr) {
- case "lastModifiedTime":
- map.put(attr, v.lastModifiedTime());
- break;
- case "lastAccessTime":
- map.put(attr, v.lastAccessTime());
- break;
- case "creationTime":
- map.put(attr, v.creationTime());
- break;
- case "size":
- map.put(attr, v.size());
- break;
- case "isRegularFile":
- map.put(attr, v.isRegularFile());
- break;
- case "isDirectory":
- map.put(attr, v.isDirectory());
- break;
- case "isSymbolicLink":
- map.put(attr, v.isSymbolicLink());
- break;
- case "isOther":
- map.put(attr, v.isOther());
- break;
- case "fileKey":
- map.put(attr, v.fileKey());
- break;
- case "owner":
- map.put(attr, v.owner());
- break;
- case "permissions":
- map.put(attr, v.permissions());
- break;
- case "group":
- map.put(attr, v.group());
- break;
- default:
- if (traceEnabled) {
- log.trace("readPosixViewAttributes({})[{}:{}] ignored for {}", path, view, attr, attrs);
- }
- }
- }
- return map;
- }
-
- @Override
- public void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException {
- String view;
- String attr;
- int i = attribute.indexOf(':');
- if (i == -1) {
- view = "basic";
- attr = attribute;
- } else {
- view = attribute.substring(0, i++);
- attr = attribute.substring(i);
- }
-
- setAttribute(path, view, attr, value, options);
- }
-
- public void setAttribute(Path path, String view, String attr, Object value, LinkOption... options) throws IOException {
- SftpPath p = toSftpPath(path);
- SftpFileSystem fs = p.getFileSystem();
- Collection<String> views = fs.supportedFileAttributeViews();
- if (GenericUtils.isEmpty(views) || (!views.contains(view))) {
- throw new UnsupportedOperationException("setAttribute(" + path + ")[" + view + ":" + attr + "=" + value + "] view " + view + " not supported: " + views);
- }
-
- SftpClient.Attributes attributes = new SftpClient.Attributes();
- switch (attr) {
- case "lastModifiedTime":
- attributes.modifyTime((int) ((FileTime) value).to(TimeUnit.SECONDS));
- break;
- case "lastAccessTime":
- attributes.accessTime((int) ((FileTime) value).to(TimeUnit.SECONDS));
- break;
- case "creationTime":
- attributes.createTime((int) ((FileTime) value).to(TimeUnit.SECONDS));
- break;
- case "size":
- attributes.size(((Number) value).longValue());
- break;
- case "permissions": {
- @SuppressWarnings("unchecked")
- Set<PosixFilePermission> attrSet = (Set<PosixFilePermission>) value;
- attributes.perms(attributesToPermissions(path, attrSet));
- break;
- }
- case "owner":
- attributes.owner(((UserPrincipal) value).getName());
- break;
- case "group":
- attributes.group(((GroupPrincipal) value).getName());
- break;
- case "acl": {
- ValidateUtils.checkTrue("acl".equalsIgnoreCase(view), "ACL cannot be set via view=%s", view);
- @SuppressWarnings("unchecked")
- List<AclEntry> acl = (List<AclEntry>) value;
- attributes.acl(acl);
- break;
- }
- case "isRegularFile":
- case "isDirectory":
- case "isSymbolicLink":
- case "isOther":
- case "fileKey":
- throw new UnsupportedOperationException("setAttribute(" + path + ")[" + view + ":" + attr + "=" + value + "] modification N/A");
- default:
- if (log.isTraceEnabled()) {
- log.trace("setAttribute({})[{}] ignore {}:{}={}", fs, path, view, attr, value);
- }
- }
-
- if (log.isDebugEnabled()) {
- log.debug("setAttribute({}) {}: {}", fs, path, attributes);
- }
-
- try (SftpClient client = fs.getClient()) {
- client.setStat(p.toString(), attributes);
- }
- }
-
- public SftpPath toSftpPath(Path path) {
- Objects.requireNonNull(path, "No path provided");
- if (!(path instanceof SftpPath)) {
- throw new ProviderMismatchException("Path is not SFTP: " + path);
- }
- return (SftpPath) path;
- }
-
- protected int attributesToPermissions(Path path, Collection<PosixFilePermission> perms) {
- if (GenericUtils.isEmpty(perms)) {
- return 0;
- }
-
- int pf = 0;
- boolean traceEnabled = log.isTraceEnabled();
- for (PosixFilePermission p : perms) {
- switch (p) {
- case OWNER_READ:
- pf |= SftpConstants.S_IRUSR;
- break;
- case OWNER_WRITE:
- pf |= SftpConstants.S_IWUSR;
- break;
- case OWNER_EXECUTE:
- pf |= SftpConstants.S_IXUSR;
- break;
- case GROUP_READ:
- pf |= SftpConstants.S_IRGRP;
- break;
- case GROUP_WRITE:
- pf |= SftpConstants.S_IWGRP;
- break;
- case GROUP_EXECUTE:
- pf |= SftpConstants.S_IXGRP;
- break;
- case OTHERS_READ:
- pf |= SftpConstants.S_IROTH;
- break;
- case OTHERS_WRITE:
- pf |= SftpConstants.S_IWOTH;
- break;
- case OTHERS_EXECUTE:
- pf |= SftpConstants.S_IXOTH;
- break;
- default:
- if (traceEnabled) {
- log.trace("attributesToPermissions(" + path + ") ignored " + p);
- }
- }
- }
-
- return pf;
- }
-
- public static String getRWXPermissions(int perms) {
- StringBuilder sb = new StringBuilder(10 /* 3 * rwx + (d)irectory */);
- if ((perms & SftpConstants.S_IFLNK) == SftpConstants.S_IFLNK) {
- sb.append('l');
- } else if ((perms & SftpConstants.S_IFDIR) == SftpConstants.S_IFDIR) {
- sb.append('d');
- } else {
- sb.append('-');
- }
-
- if ((perms & SftpConstants.S_IRUSR) == SftpConstants.S_IRUSR) {
- sb.append('r');
- } else {
- sb.append('-');
- }
- if ((perms & SftpConstants.S_IWUSR) == SftpConstants.S_IWUSR) {
- sb.append('w');
- } else {
- sb.append('-');
- }
- if ((perms & SftpConstants.S_IXUSR) == SftpConstants.S_IXUSR) {
- sb.append('x');
- } else {
- sb.append('-');
- }
-
- if ((perms & SftpConstants.S_IRGRP) == SftpConstants.S_IRGRP) {
- sb.append('r');
- } else {
- sb.append('-');
- }
- if ((perms & SftpConstants.S_IWGRP) == SftpConstants.S_IWGRP) {
- sb.append('w');
- } else {
- sb.append('-');
- }
- if ((perms & SftpConstants.S_IXGRP) == SftpConstants.S_IXGRP) {
- sb.append('x');
- } else {
- sb.append('-');
- }
-
- if ((perms & SftpConstants.S_IROTH) == SftpConstants.S_IROTH) {
- sb.append('r');
- } else {
- sb.append('-');
- }
- if ((perms & SftpConstants.S_IWOTH) == SftpConstants.S_IWOTH) {
- sb.append('w');
- } else {
- sb.append('-');
- }
- if ((perms & SftpConstants.S_IXOTH) == SftpConstants.S_IXOTH) {
- sb.append('x');
- } else {
- sb.append('-');
- }
-
- return sb.toString();
- }
-
- public static String getOctalPermissions(int perms) {
- Collection<PosixFilePermission> attrs = permissionsToAttributes(perms);
- return getOctalPermissions(attrs);
- }
-
- public static Set<PosixFilePermission> permissionsToAttributes(int perms) {
- Set<PosixFilePermission> p = EnumSet.noneOf(PosixFilePermission.class);
- if ((perms & SftpConstants.S_IRUSR) == SftpConstants.S_IRUSR) {
- p.add(PosixFilePermission.OWNER_READ);
- }
- if ((perms & SftpConstants.S_IWUSR) == SftpConstants.S_IWUSR) {
- p.add(PosixFilePermission.OWNER_WRITE);
- }
- if ((perms & SftpConstants.S_IXUSR) == SftpConstants.S_IXUSR) {
- p.add(PosixFilePermission.OWNER_EXECUTE);
- }
- if ((perms & SftpConstants.S_IRGRP) == SftpConstants.S_IRGRP) {
- p.add(PosixFilePermission.GROUP_READ);
- }
- if ((perms & SftpConstants.S_IWGRP) == SftpConstants.S_IWGRP) {
- p.add(PosixFilePermission.GROUP_WRITE);
- }
- if ((perms & SftpConstants.S_IXGRP) == SftpConstants.S_IXGRP) {
- p.add(PosixFilePermission.GROUP_EXECUTE);
- }
- if ((perms & SftpConstants.S_IROTH) == SftpConstants.S_IROTH) {
- p.add(PosixFilePermission.OTHERS_READ);
- }
- if ((perms & SftpConstants.S_IWOTH) == SftpConstants.S_IWOTH) {
- p.add(PosixFilePermission.OTHERS_WRITE);
- }
- if ((perms & SftpConstants.S_IXOTH) == SftpConstants.S_IXOTH) {
- p.add(PosixFilePermission.OTHERS_EXECUTE);
- }
- return p;
- }
-
- public static String getOctalPermissions(Collection<PosixFilePermission> perms) {
- int pf = 0;
-
- for (PosixFilePermission p : perms) {
- switch (p) {
- case OWNER_READ:
- pf |= SftpConstants.S_IRUSR;
- break;
- case OWNER_WRITE:
- pf |= SftpConstants.S_IWUSR;
- break;
- case OWNER_EXECUTE:
- pf |= SftpConstants.S_IXUSR;
- break;
- case GROUP_READ:
- pf |= SftpConstants.S_IRGRP;
- break;
- case GROUP_WRITE:
- pf |= SftpConstants.S_IWGRP;
- break;
- case GROUP_EXECUTE:
- pf |= SftpConstants.S_IXGRP;
- break;
- case OTHERS_READ:
- pf |= SftpConstants.S_IROTH;
- break;
- case OTHERS_WRITE:
- pf |= SftpConstants.S_IWOTH;
- break;
- case OTHERS_EXECUTE:
- pf |= SftpConstants.S_IXOTH;
- break;
- default: // ignored
- }
- }
-
- return String.format("%04o", pf);
- }
-
- /**
- * Uses the host, port and username to create a unique identifier
- *
- * @param uri The {@link URI} - <B>Note:</B> not checked to make sure
- * that the scheme is {@code sftp://}
- * @return The unique identifier
- * @see #getFileSystemIdentifier(String, int, String)
- */
- public static String getFileSystemIdentifier(URI uri) {
- String userInfo = ValidateUtils.checkNotNullAndNotEmpty(uri.getUserInfo(), "UserInfo not provided");
- String[] ui = GenericUtils.split(userInfo, ':');
- ValidateUtils.checkTrue(GenericUtils.length(ui) == 2, "Invalid user info: %s", userInfo);
- return getFileSystemIdentifier(uri.getHost(), uri.getPort(), ui[0]);
- }
-
- /**
- * Uses the remote host address, port and current username to create a unique identifier
- *
- * @param session The {@link ClientSession}
- * @return The unique identifier
- * @see #getFileSystemIdentifier(String, int, String)
- */
- public static String getFileSystemIdentifier(ClientSession session) {
- IoSession ioSession = session.getIoSession();
- SocketAddress addr = ioSession.getRemoteAddress();
- String username = session.getUsername();
- if (addr instanceof InetSocketAddress) {
- InetSocketAddress inetAddr = (InetSocketAddress) addr;
- return getFileSystemIdentifier(inetAddr.getHostString(), inetAddr.getPort(), username);
- } else {
- return getFileSystemIdentifier(addr.toString(), SshConfigFileReader.DEFAULT_PORT, username);
- }
- }
-
- public static String getFileSystemIdentifier(String host, int port, String username) {
- return GenericUtils.trimToEmpty(host) + ':'
- + ((port <= 0) ? SshConfigFileReader.DEFAULT_PORT : port) + ':'
- + GenericUtils.trimToEmpty(username);
- }
-
- public static URI createFileSystemURI(String host, int port, String username, String password) {
- return createFileSystemURI(host, port, username, password, Collections.emptyMap());
- }
-
- public static URI createFileSystemURI(String host, int port, String username, String password, Map<String, ?> params) {
- StringBuilder sb = new StringBuilder(Byte.MAX_VALUE);
- sb.append(SftpConstants.SFTP_SUBSYSTEM_NAME)
- .append("://").append(username).append(':').append(password)
- .append('@').append(host).append(':').append(port)
- .append('/');
- if (GenericUtils.size(params) > 0) {
- boolean firstParam = true;
- // Cannot use forEach because firstParam is not effectively final
- for (Map.Entry<String, ?> pe : params.entrySet()) {
- String key = pe.getKey();
- Object value = pe.getValue();
- sb.append(firstParam ? '?' : '&').append(key).append('=').append(Objects.toString(value, null));
- firstParam = false;
- }
- }
-
- return URI.create(sb.toString());
- }
-}