You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/07/01 12:57:48 UTC
[07/10] mina-sshd git commit: [SSHD-509] Use targeted derived
NamedFactory(ies) for the various generic parameters
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/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
new file mode 100644
index 0000000..edbf82b
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java
@@ -0,0 +1,465 @@
+/*
+ * 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.nio.file.attribute.GroupPrincipal;
+import java.nio.file.attribute.UserPrincipal;
+import java.nio.file.attribute.UserPrincipalLookupService;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.file.util.BaseFileSystem;
+import org.apache.sshd.common.file.util.ImmutableList;
+
+public class SftpFileSystem extends BaseFileSystem<SftpPath> {
+
+ private final ClientSession session;
+ private final Queue<SftpClient> pool;
+ private final ThreadLocal<Wrapper> wrappers = new ThreadLocal<>();
+ private SftpPath defaultDir;
+ private int readBufferSize = SftpClient.DEFAULT_READ_BUFFER_SIZE;
+ private int writeBufferSize = SftpClient.DEFAULT_WRITE_BUFFER_SIZE;
+
+ public SftpFileSystem(SftpFileSystemProvider provider, ClientSession session) throws IOException {
+ super(provider);
+ this.session = session;
+ this.pool = new LinkedBlockingQueue<>(8);
+ try (SftpClient client = getClient()) {
+ defaultDir = getPath(client.canonicalPath("."));
+ }
+ }
+
+ 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, ImmutableList<String> names) {
+ return new SftpPath(this, root, names);
+ }
+
+ public ClientSession getSession() {
+ return session;
+ }
+
+ @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) {
+ client = session.createSftpClient();
+ }
+ 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()) {
+ session.close(true);
+ }
+ }
+
+ @Override
+ public boolean isOpen() {
+ return !session.isClosing();
+ }
+
+ @Override
+ public Set<String> supportedFileAttributeViews() {
+ Set<String> set = new HashSet<>();
+ set.addAll(Arrays.asList("basic", "posix", "owner"));
+ return Collections.unmodifiableSet(set);
+ }
+
+ @Override
+ public UserPrincipalLookupService getUserPrincipalLookupService() {
+ return new DefaultUserPrincipalLookupService();
+ }
+
+ @Override
+ public SftpPath getDefaultDir() {
+ return defaultDir;
+ }
+
+ private class Wrapper extends AbstractSftpClient {
+
+ private final SftpClient delegate;
+ private final AtomicInteger count = new AtomicInteger(1);
+ private final int readSize, 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 boolean isClosing() {
+ return false;
+ }
+
+ @Override
+ public boolean isOpen() {
+ if (count.get() > 0) {
+ return true;
+ } else {
+ return false; // debug breakpoint
+ }
+ }
+
+ @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 DirEntry[] readDir(Handle handle) throws IOException {
+ if (!isOpen()) {
+ throw new IOException("readDir(" + handle + ") client is closed");
+ }
+ return delegate.readDir(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);
+ }
+ }
+
+ protected static class DefaultUserPrincipalLookupService extends UserPrincipalLookupService {
+
+ @Override
+ public UserPrincipal lookupPrincipalByName(String name) throws IOException {
+ return new DefaultUserPrincipal(name);
+ }
+
+ @Override
+ public GroupPrincipal lookupPrincipalByGroupName(String group) throws IOException {
+ return new DefaultGroupPrincipal(group);
+ }
+ }
+
+ protected static class DefaultUserPrincipal implements UserPrincipal {
+
+ private final String name;
+
+ public DefaultUserPrincipal(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("name is null");
+ }
+ this.name = name;
+ }
+
+ @Override
+ public 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 name.equals(that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+
+ protected static class DefaultGroupPrincipal extends DefaultUserPrincipal implements GroupPrincipal {
+
+ public DefaultGroupPrincipal(String name) {
+ super(name);
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/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
new file mode 100644
index 0000000..0e5169c
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
@@ -0,0 +1,892 @@
+/*
+ * 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 static org.apache.sshd.common.subsystem.sftp.SftpConstants.SFTP_V3;
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IRGRP;
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IROTH;
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IRUSR;
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IWGRP;
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IWOTH;
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IWUSR;
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IXGRP;
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IXOTH;
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.S_IXUSR;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SeekableByteChannel;
+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.StandardOpenOption;
+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.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.Collection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.sshd.client.ClientBuilder;
+import org.apache.sshd.client.SftpException;
+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.FactoryManagerUtils;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.config.SshConfigFileReader;
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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;
+
+ private final SshClient client;
+ private final Map<String, SftpFileSystem> fileSystems = new HashMap<String, SftpFileSystem>();
+ protected final Logger log;
+
+ public SftpFileSystemProvider() {
+ this(null);
+ }
+
+ public SftpFileSystemProvider(SshClient client) {
+ this.log = LoggerFactory.getLogger(getClass());
+ if (client == null) {
+ // TODO: make this configurable using system properties
+ client = ClientBuilder.builder().build();
+ }
+ this.client = client;
+ this.client.start();
+ }
+
+ @Override
+ public String getScheme() {
+ return SftpConstants.SFTP_SUBSYSTEM_NAME;
+ }
+
+ @Override
+ public FileSystem newFileSystem(URI uri, Map<String, ?> env) throws IOException {
+ synchronized (fileSystems) {
+ String authority = uri.getAuthority();
+ SftpFileSystem fileSystem = fileSystems.get(authority);
+ if (fileSystem != null) {
+ throw new FileSystemAlreadyExistsException(authority);
+ }
+ String host = ValidateUtils.checkNotNullAndNotEmpty(uri.getHost(), "Host not provided", GenericUtils.EMPTY_OBJECT_ARRAY);
+ String userInfo = ValidateUtils.checkNotNullAndNotEmpty(uri.getUserInfo(), "UserInfo not provided", GenericUtils.EMPTY_OBJECT_ARRAY);
+ String[] ui = GenericUtils.split(userInfo, ':');
+ int port = uri.getPort();
+ if (port <= 0) {
+ port = SshConfigFileReader.DEFAULT_PORT;
+ }
+
+ ClientSession session=null;
+ try {
+ session = client.connect(ui[0], host, port)
+ .verify(FactoryManagerUtils.getLongProperty(env, CONNECT_TIME_PROP_NAME, DEFAULT_CONNECT_TIME))
+ .getSession()
+ ;
+ session.addPasswordIdentity(ui[1]);
+ session.auth().verify();
+ fileSystem = new SftpFileSystem(this, session);
+ fileSystem.setReadBufferSize(FactoryManagerUtils.getIntProperty(env, READ_BUFFER_PROP_NAME, DEFAULT_READ_BUFFER_SIZE));
+ fileSystem.setWriteBufferSize(FactoryManagerUtils.getIntProperty(env, WRITE_BUFFER_PROP_NAME, DEFAULT_WRITE_BUFFER_SIZE));
+ fileSystems.put(authority, fileSystem);
+ return 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);
+ }
+ }
+ }
+ }
+
+ @Override
+ public FileSystem getFileSystem(URI uri) {
+ synchronized (fileSystems) {
+ String authority = uri.getAuthority();
+ SftpFileSystem fileSystem = fileSystems.get(authority);
+ if (fileSystem == null) {
+ throw new FileSystemNotFoundException(authority);
+ }
+ return fileSystem;
+ }
+ }
+
+ @Override
+ public Path getPath(URI uri) {
+ FileSystem fs = getFileSystem(uri);
+ return fs.getPath(uri.getPath());
+ }
+
+ @Override
+ public SeekableByteChannel 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 = EnumSet.noneOf(SftpClient.OpenMode.class);
+ for (OpenOption option : options) {
+ if (option == StandardOpenOption.READ) {
+ modes.add(SftpClient.OpenMode.Read);
+ } else if (option == StandardOpenOption.APPEND) {
+ modes.add(SftpClient.OpenMode.Append);
+ } else if (option == StandardOpenOption.CREATE) {
+ modes.add(SftpClient.OpenMode.Create);
+ } else if (option == StandardOpenOption.TRUNCATE_EXISTING) {
+ modes.add(SftpClient.OpenMode.Truncate);
+ } else if (option == StandardOpenOption.WRITE) {
+ modes.add(SftpClient.OpenMode.Write);
+ } else if (option == StandardOpenOption.CREATE_NEW) {
+ modes.add(SftpClient.OpenMode.Create);
+ modes.add(SftpClient.OpenMode.Exclusive);
+ } else if (option == StandardOpenOption.SPARSE) {
+ /*
+ * As per the Javadoc:
+ *
+ * The option is ignored when the file system does not
+ * support the creation of sparse files
+ */
+ continue;
+ } else {
+ throw new IllegalArgumentException("newFileChannel(" + path + ") unsupported open option: " + option);
+ }
+ }
+ if (modes.isEmpty()) {
+ modes.add(SftpClient.OpenMode.Read);
+ modes.add(SftpClient.OpenMode.Write);
+ }
+ // TODO: attrs
+ return new SftpFileChannel(toSftpPath(path), modes);
+ }
+
+ @Override
+ public DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter) throws IOException {
+ final SftpPath p = toSftpPath(dir);
+ return new DirectoryStream<Path>() {
+ private final SftpFileSystem fs = p.getFileSystem();
+ private final SftpClient sftp = fs.getClient();
+ private final Iterable<SftpClient.DirEntry> iter = sftp.readDir(p.toString());
+
+ @Override
+ public Iterator<Path> iterator() {
+ return new Iterator<Path>() {
+ @SuppressWarnings("synthetic-access")
+ private final Iterator<SftpClient.DirEntry> it = iter.iterator();
+
+ @Override
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ @Override
+ public Path next() {
+ SftpClient.DirEntry entry = it.next();
+ return p.resolve(entry.filename);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("newDirectoryStream(" + p + ") Iterator#remove() N/A");
+ }
+ };
+ }
+
+ @Override
+ public void close() throws IOException {
+ sftp.close();
+ }
+ };
+ }
+
+ @Override
+ public void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException {
+ SftpPath p = toSftpPath(dir);
+ SftpFileSystem fs = p.getFileSystem();
+ try (SftpClient sftp = fs.getClient()) {
+ try {
+ sftp.mkdir(dir.toString());
+ } catch (SftpException e) {
+ int sftpStatus=e.getStatus();
+ if ((sftp.getVersion() == 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();
+ 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 (replaceExisting) {
+ deleteIfExists(target);
+ } else {
+ if (status.booleanValue()) {
+ 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("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 move target " + target);
+ }
+
+ if (replaceExisting) {
+ deleteIfExists(target);
+ } else if (status.booleanValue()) {
+ 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 {
+ throw new FileSystemException(path.toString(), path.toString(), "getFileStore(" + path + ") N/A");
+ }
+
+ @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);
+ }
+ 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()) {
+ return fsLink.getPath(client.readLink(l.toString()));
+ }
+ }
+
+ @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(path.toString());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <V extends FileAttributeView> V getFileAttributeView(final Path path, Class<V> type, final LinkOption... options) {
+ if (type.isAssignableFrom(PosixFileAttributeView.class)) {
+ return (V) new PosixFileAttributeView() {
+ @Override
+ public String name() {
+ return "view";
+ }
+
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public PosixFileAttributes readAttributes() throws IOException {
+ SftpPath p = toSftpPath(path);
+ SftpFileSystem fs = p.getFileSystem();
+ final SftpClient.Attributes attributes;
+ try (SftpClient client =fs.getClient()) {
+ try {
+ if (followLinks(options)) {
+ attributes = client.stat(p.toString());
+ } else {
+ attributes = client.lstat(p.toString());
+ }
+ } catch (SftpException e) {
+ if (e.getStatus() == SftpConstants.SSH_FX_NO_SUCH_FILE) {
+ throw new NoSuchFileException(p.toString());
+ }
+ throw e;
+ }
+ }
+ return new PosixFileAttributes() {
+ @Override
+ public UserPrincipal owner() {
+ return attributes.owner != null ? new SftpFileSystem.DefaultGroupPrincipal(attributes.owner) : null;
+ }
+
+ @Override
+ public GroupPrincipal group() {
+ return attributes.group != null ? new SftpFileSystem.DefaultGroupPrincipal(attributes.group) : null;
+ }
+
+ @Override
+ public Set<PosixFilePermission> permissions() {
+ return permissionsToAttributes(attributes.perms);
+ }
+
+ @Override
+ public FileTime lastModifiedTime() {
+ return FileTime.from(attributes.mtime, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public FileTime lastAccessTime() {
+ return FileTime.from(attributes.atime, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public FileTime creationTime() {
+ return FileTime.from(attributes.ctime, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public boolean isRegularFile() {
+ return attributes.isRegularFile();
+ }
+
+ @Override
+ public boolean isDirectory() {
+ return attributes.isDirectory();
+ }
+
+ @Override
+ public boolean isSymbolicLink() {
+ return attributes.isSymbolicLink();
+ }
+
+ @Override
+ public boolean isOther() {
+ return attributes.isOther();
+ }
+
+ @Override
+ public long size() {
+ return attributes.size;
+ }
+
+ @Override
+ public Object fileKey() {
+ // TODO
+ return null;
+ }
+ };
+ }
+
+ @Override
+ public void setTimes(FileTime lastModifiedTime, FileTime lastAccessTime, FileTime createTime) throws IOException {
+ if (lastModifiedTime != null) {
+ setAttribute(path, "lastModifiedTime", lastModifiedTime, options);
+ }
+ if (lastAccessTime != null) {
+ setAttribute(path, "lastAccessTime", lastAccessTime, options);
+ }
+ if (createTime != null) {
+ setAttribute(path, "createTime", createTime, options);
+ }
+ }
+
+ @Override
+ public void setPermissions(Set<PosixFilePermission> perms) throws IOException {
+ setAttribute(path, "permissions", perms, options);
+ }
+
+ @Override
+ public void setGroup(GroupPrincipal group) throws IOException {
+ setAttribute(path, "group", group, options);
+ }
+
+ @Override
+ public UserPrincipal getOwner() throws IOException {
+ return readAttributes().owner();
+ }
+
+ @Override
+ public void setOwner(UserPrincipal owner) throws IOException {
+ setAttribute(path, "owner", owner, options);
+ }
+ };
+ } else {
+ throw new UnsupportedOperationException("getFileAttributeView(" + path + ") view not supported: " + type.getSimpleName());
+ }
+ }
+
+ @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);
+ }
+ 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 + ")[" + attributes + "] view " + view + " not supported: " + views);
+ }
+
+ PosixFileAttributes v = readAttributes(path, PosixFileAttributes.class, options);
+ if ("*".equals(attrs)) {
+ attrs = "lastModifiedTime,lastAccessTime,creationTime,size,isRegularFile,isDirectory,isSymbolicLink,isOther,fileKey,owner,permissions,group";
+ }
+ Map<String, Object> map = new HashMap<>();
+ for (String attr : attrs.split(",")) {
+ 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, Long.valueOf(v.size()));
+ break;
+ case "isRegularFile":
+ map.put(attr, Boolean.valueOf(v.isRegularFile()));
+ break;
+ case "isDirectory":
+ map.put(attr, Boolean.valueOf(v.isDirectory()));
+ break;
+ case "isSymbolicLink":
+ map.put(attr, Boolean.valueOf(v.isSymbolicLink()));
+ break;
+ case "isOther":
+ map.put(attr, Boolean.valueOf(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 (log.isTraceEnabled()) {
+ log.trace("readAttributes({})[{}] ignored {}={}", path, attributes, attr, v);
+ }
+ }
+ }
+ 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);
+ }
+ SftpPath p = toSftpPath(path);
+ SftpFileSystem fs = p.getFileSystem();
+ Collection<String> views = fs.supportedFileAttributeViews();
+ if (GenericUtils.isEmpty(views) || (!view.contains(view))) {
+ throw new UnsupportedOperationException("setAttribute(" + path + ")[" + attribute + "=" + value + "] view " + view + " not supported: " + views);
+ }
+
+ SftpClient.Attributes attributes = new SftpClient.Attributes();
+ switch (attr) {
+ case "lastModifiedTime":
+ attributes.mtime((int) ((FileTime) value).to(TimeUnit.SECONDS));
+ break;
+ case "lastAccessTime":
+ attributes.atime((int) ((FileTime) value).to(TimeUnit.SECONDS));
+ break;
+ case "creationTime":
+ attributes.ctime((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 "isRegularFile":
+ case "isDirectory":
+ case "isSymbolicLink":
+ case "isOther":
+ case "fileKey":
+ throw new UnsupportedOperationException("setAttribute(" + path + ")[" + attribute + "=" + value + "]"
+ + " unknown view=" + view + " attribute: " + attr);
+ default:
+ if (log.isTraceEnabled()) {
+ log.trace("setAttribute({})[{}] ignore {}={}", path, attribute, attr, value);
+ }
+ }
+
+ try (SftpClient client = fs.getClient()) {
+ client.setStat(p.toString(), attributes);
+ }
+ }
+
+ private SftpPath toSftpPath(Path path) {
+ ValidateUtils.checkNotNull(path, "No path provided", GenericUtils.EMPTY_OBJECT_ARRAY);
+ if (!(path instanceof SftpPath)) {
+ throw new ProviderMismatchException("Path is not SFTP: " + path);
+ }
+ return (SftpPath) path;
+ }
+
+ static boolean followLinks(LinkOption... paramVarArgs) {
+ boolean bool = true;
+ for (LinkOption localLinkOption : paramVarArgs) {
+ if (localLinkOption == LinkOption.NOFOLLOW_LINKS) {
+ bool = false;
+ }
+ }
+ return bool;
+ }
+
+ private Set<PosixFilePermission> permissionsToAttributes(int perms) {
+ Set<PosixFilePermission> p = new HashSet<>();
+ if ((perms & S_IRUSR) != 0) {
+ p.add(PosixFilePermission.OWNER_READ);
+ }
+ if ((perms & S_IWUSR) != 0) {
+ p.add(PosixFilePermission.OWNER_WRITE);
+ }
+ if ((perms & S_IXUSR) != 0) {
+ p.add(PosixFilePermission.OWNER_EXECUTE);
+ }
+ if ((perms & S_IRGRP) != 0) {
+ p.add(PosixFilePermission.GROUP_READ);
+ }
+ if ((perms & S_IWGRP) != 0) {
+ p.add(PosixFilePermission.GROUP_WRITE);
+ }
+ if ((perms & S_IXGRP) != 0) {
+ p.add(PosixFilePermission.GROUP_EXECUTE);
+ }
+ if ((perms & S_IROTH) != 0) {
+ p.add(PosixFilePermission.OTHERS_READ);
+ }
+ if ((perms & S_IWOTH) != 0) {
+ p.add(PosixFilePermission.OTHERS_WRITE);
+ }
+ if ((perms & S_IXOTH) != 0) {
+ p.add(PosixFilePermission.OTHERS_EXECUTE);
+ }
+ return p;
+ }
+
+ protected int attributesToPermissions(Path path, Collection<PosixFilePermission> perms) {
+ if (GenericUtils.isEmpty(perms)) {
+ return 0;
+ }
+
+ int pf = 0;
+ for (PosixFilePermission p : perms) {
+ switch (p) {
+ case OWNER_READ:
+ pf |= S_IRUSR;
+ break;
+ case OWNER_WRITE:
+ pf |= S_IWUSR;
+ break;
+ case OWNER_EXECUTE:
+ pf |= S_IXUSR;
+ break;
+ case GROUP_READ:
+ pf |= S_IRGRP;
+ break;
+ case GROUP_WRITE:
+ pf |= S_IWGRP;
+ break;
+ case GROUP_EXECUTE:
+ pf |= S_IXGRP;
+ break;
+ case OTHERS_READ:
+ pf |= S_IROTH;
+ break;
+ case OTHERS_WRITE:
+ pf |= S_IWOTH;
+ break;
+ case OTHERS_EXECUTE:
+ pf |= S_IXOTH;
+ break;
+ default:
+ if (log.isTraceEnabled()) {
+ log.trace("attributesToPermissions(" + path + ") ignored " + p);
+ }
+ }
+ }
+
+ return pf;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpPath.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpPath.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpPath.java
new file mode 100644
index 0000000..f130d1a
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpPath.java
@@ -0,0 +1,46 @@
+/*
+ * 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.FileSystem;
+import java.nio.file.LinkOption;
+import java.nio.file.spi.FileSystemProvider;
+
+import org.apache.sshd.common.file.util.BasePath;
+import org.apache.sshd.common.file.util.ImmutableList;
+
+public class SftpPath extends BasePath<SftpPath, SftpFileSystem> {
+ public SftpPath(SftpFileSystem fileSystem, String root, ImmutableList<String> names) {
+ super(fileSystem, root, names);
+ }
+
+ @Override
+ public SftpPath toRealPath(LinkOption... options) throws IOException {
+// try (SftpClient client = fileSystem.getClient()) {
+// client.realP
+// }
+ // TODO: handle links
+ SftpPath absolute = toAbsolutePath();
+ FileSystem fs = getFileSystem();
+ FileSystemProvider provider = fs.provider();
+ provider.checkAccess(absolute);
+ return absolute;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
index bad235f..ef67e34 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/file/root/RootedFileSystemProvider.java
@@ -33,7 +33,6 @@ import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.FileSystemAlreadyExistsException;
import java.nio.file.FileSystemNotFoundException;
-import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption;
import java.nio.file.Path;
@@ -73,42 +72,52 @@ public class RootedFileSystemProvider extends FileSystemProvider {
@Override
public FileSystem newFileSystem(URI uri, Map<String, ?> env) throws IOException {
Path path = uriToPath(uri);
- synchronized (fileSystems)
- {
- Path localPath2 = null;
- if (ensureDirectory(path))
- {
- localPath2 = path.toRealPath();
- if (this.fileSystems.containsKey(localPath2)) {
- throw new FileSystemAlreadyExistsException();
- }
+ Path localPath2 = ensureDirectory(path).toRealPath();
+
+ RootedFileSystem rootedFs=null;
+ synchronized (fileSystems) {
+ if (!this.fileSystems.containsKey(localPath2)) {
+ rootedFs = new RootedFileSystem(this, path, env);
+ this.fileSystems.put(localPath2, rootedFs);
}
- RootedFileSystem rootedFs = new RootedFileSystem(this, path, env);
- this.fileSystems.put(localPath2, rootedFs);
- return rootedFs;
}
+
+ // do all the throwing outside the synchronized block to minimize its lock time
+ if (rootedFs == null) {
+ throw new FileSystemAlreadyExistsException("newFileSystem(" + uri + ") already mapped " + localPath2);
+ }
+
+ return rootedFs;
}
@Override
public FileSystem getFileSystem(URI uri) {
+ Path path = uriToPath(uri);
+ Path real;
+ try {
+ real = path.toRealPath();
+ } catch (IOException e) {
+ FileSystemNotFoundException err = new FileSystemNotFoundException(uri.toString());
+ err.initCause(e);
+ throw err;
+ }
+
+ RootedFileSystem fileSystem = null;
synchronized (fileSystems) {
- RootedFileSystem fileSystem = null;
- try {
- fileSystem = fileSystems.get(uriToPath(uri).toRealPath());
- } catch (IOException ignore) {
- // ignored
- }
- if (fileSystem == null) {
- throw new FileSystemNotFoundException(uri.toString());
- }
- return fileSystem;
+ fileSystem = fileSystems.get(real);
}
+
+ // do all the throwing outside the synchronized block to minimize its lock time
+ if (fileSystem == null) {
+ throw new FileSystemNotFoundException(uri.toString());
+ }
+
+ return fileSystem;
}
@Override
public FileSystem newFileSystem(Path path, Map<String, ?> env) throws IOException {
- ensureDirectory(path);
- return new RootedFileSystem(this, path, env);
+ return new RootedFileSystem(this, ensureDirectory(path), env);
}
protected Path uriToPath(URI uri) {
@@ -130,11 +139,8 @@ public class RootedFileSystemProvider extends FileSystemProvider {
}
}
- private boolean ensureDirectory(Path path) {
- if (!Files.isDirectory(path, IoUtils.getLinkOptions(false))) {
- throw new UnsupportedOperationException("Not a directory: " + path);
- }
- return true;
+ private static Path ensureDirectory(Path path) {
+ return IoUtils.ensureDirectory(path, IoUtils.getLinkOptions(false));
}
@Override
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/common/sftp/SftpConstants.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/sftp/SftpConstants.java b/sshd-core/src/main/java/org/apache/sshd/common/sftp/SftpConstants.java
deleted file mode 100644
index dd54bf3..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/sftp/SftpConstants.java
+++ /dev/null
@@ -1,223 +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.common.sftp;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class SftpConstants {
- public static String SFTP_SUBSYSTEM_NAME = "sftp";
-
- public static final int SSH_FXP_INIT = 1;
- public static final int SSH_FXP_VERSION = 2;
- public static final int SSH_FXP_OPEN = 3;
- public static final int SSH_FXP_CLOSE = 4;
- public static final int SSH_FXP_READ = 5;
- public static final int SSH_FXP_WRITE = 6;
- public static final int SSH_FXP_LSTAT = 7;
- public static final int SSH_FXP_FSTAT = 8;
- public static final int SSH_FXP_SETSTAT = 9;
- public static final int SSH_FXP_FSETSTAT = 10;
- public static final int SSH_FXP_OPENDIR = 11;
- public static final int SSH_FXP_READDIR = 12;
- public static final int SSH_FXP_REMOVE = 13;
- public static final int SSH_FXP_MKDIR = 14;
- public static final int SSH_FXP_RMDIR = 15;
- public static final int SSH_FXP_REALPATH = 16;
- public static final int SSH_FXP_STAT = 17;
- public static final int SSH_FXP_RENAME = 18;
- public static final int SSH_FXP_READLINK = 19;
- public static final int SSH_FXP_SYMLINK = 20; // v3 -> v5
- public static final int SSH_FXP_LINK = 21; // v6
- public static final int SSH_FXP_BLOCK = 22; // v6
- public static final int SSH_FXP_UNBLOCK = 23; // v6
- public static final int SSH_FXP_STATUS = 101;
- public static final int SSH_FXP_HANDLE = 102;
- public static final int SSH_FXP_DATA = 103;
- public static final int SSH_FXP_NAME = 104;
- public static final int SSH_FXP_ATTRS = 105;
- public static final int SSH_FXP_EXTENDED = 200;
- public static final int SSH_FXP_EXTENDED_REPLY = 201;
-
- public static final int SSH_FX_OK = 0;
- public static final int SSH_FX_EOF = 1;
- public static final int SSH_FX_NO_SUCH_FILE = 2;
- public static final int SSH_FX_PERMISSION_DENIED = 3;
- public static final int SSH_FX_FAILURE = 4;
- public static final int SSH_FX_BAD_MESSAGE = 5;
- public static final int SSH_FX_NO_CONNECTION = 6;
- public static final int SSH_FX_CONNECTION_LOST = 7;
- public static final int SSH_FX_OP_UNSUPPORTED = 8;
- public static final int SSH_FX_INVALID_HANDLE = 9;
- public static final int SSH_FX_NO_SUCH_PATH = 10;
- public static final int SSH_FX_FILE_ALREADY_EXISTS = 11;
- public static final int SSH_FX_WRITE_PROTECT = 12;
- public static final int SSH_FX_NO_MEDIA = 13;
- public static final int SSH_FX_NO_SPACE_ON_FILESYSTEM = 14;
- public static final int SSH_FX_QUOTA_EXCEEDED = 15;
- public static final int SSH_FX_UNKNOWN_PRINCIPLE = 16;
- public static final int SSH_FX_LOCK_CONFLICT = 17;
- public static final int SSH_FX_DIR_NOT_EMPTY = 18;
- public static final int SSH_FX_NOT_A_DIRECTORY = 19;
- public static final int SSH_FX_INVALID_FILENAME = 20;
- public static final int SSH_FX_LINK_LOOP = 21;
- public static final int SSH_FX_CANNOT_DELETE = 22;
- public static final int SSH_FX_INVALID_PARAMETER = 23;
- public static final int SSH_FX_FILE_IS_A_DIRECTORY = 24;
- public static final int SSH_FX_BYTE_RANGE_LOCK_CONFLICT = 25;
- public static final int SSH_FX_BYTE_RANGE_LOCK_REFUSED = 26;
- public static final int SSH_FX_DELETE_PENDING = 27;
- public static final int SSH_FX_FILE_CORRUPT = 28;
- public static final int SSH_FX_OWNER_INVALID = 29;
- public static final int SSH_FX_GROUP_INVALID = 30;
- public static final int SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK = 31;
-
- public static final int SSH_FILEXFER_ATTR_SIZE = 0x00000001;
- public static final int SSH_FILEXFER_ATTR_UIDGID = 0x00000002;
- public static final int SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004;
- public static final int SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008; // v3 naming convention
- public static final int SSH_FILEXFER_ATTR_ACCESSTIME = 0x00000008; // v4
- public static final int SSH_FILEXFER_ATTR_CREATETIME = 0x00000010; // v4
- public static final int SSH_FILEXFER_ATTR_MODIFYTIME = 0x00000020; // v4
- public static final int SSH_FILEXFER_ATTR_ACL = 0x00000040; // v4
- public static final int SSH_FILEXFER_ATTR_OWNERGROUP = 0x00000080; // v4
- public static final int SSH_FILEXFER_ATTR_SUBSECOND_TIMES = 0x00000100; // v5
- public static final int SSH_FILEXFER_ATTR_BITS = 0x00000200; // v5
- public static final int SSH_FILEXFER_ATTR_ALLOCATION_SIZE = 0x00000400; // v6
- public static final int SSH_FILEXFER_ATTR_TEXT_HINT = 0x00000800; // v6
- public static final int SSH_FILEXFER_ATTR_MIME_TYPE = 0x00001000; // v6
- public static final int SSH_FILEXFER_ATTR_LINK_COUNT = 0x00002000; // v6
- public static final int SSH_FILEXFER_ATTR_UNTRANSLATED_NAME = 0x00004000; // v6
- public static final int SSH_FILEXFER_ATTR_CTIME = 0x00008000; // v6
- public static final int SSH_FILEXFER_ATTR_EXTENDED = 0x80000000;
-
- public static final int SSH_FILEXFER_ATTR_ALL = 0x0000FFFF; // All attributes
-
- public static final int SSH_FILEXFER_ATTR_FLAGS_READONLY = 0x00000001;
- public static final int SSH_FILEXFER_ATTR_FLAGS_SYSTEM = 0x00000002;
- public static final int SSH_FILEXFER_ATTR_FLAGS_HIDDEN = 0x00000004;
- public static final int SSH_FILEXFER_ATTR_FLAGS_CASE_INSENSITIVE = 0x00000008;
- public static final int SSH_FILEXFER_ATTR_FLAGS_ARCHIVE = 0x00000010;
- public static final int SSH_FILEXFER_ATTR_FLAGS_ENCRYPTED = 0x00000020;
- public static final int SSH_FILEXFER_ATTR_FLAGS_COMPRESSED = 0x00000040;
- public static final int SSH_FILEXFER_ATTR_FLAGS_SPARSE = 0x00000080;
- public static final int SSH_FILEXFER_ATTR_FLAGS_APPEND_ONLY = 0x00000100;
- public static final int SSH_FILEXFER_ATTR_FLAGS_IMMUTABLE = 0x00000200;
- public static final int SSH_FILEXFER_ATTR_FLAGS_SYNC = 0x00000400;
-
- public static final int SSH_FILEXFER_TYPE_REGULAR = 1;
- public static final int SSH_FILEXFER_TYPE_DIRECTORY = 2;
- public static final int SSH_FILEXFER_TYPE_SYMLINK = 3;
- public static final int SSH_FILEXFER_TYPE_SPECIAL = 4;
- public static final int SSH_FILEXFER_TYPE_UNKNOWN = 5;
- public static final int SSH_FILEXFER_TYPE_SOCKET = 6; // v5
- public static final int SSH_FILEXFER_TYPE_CHAR_DEVICE = 7; // v5
- public static final int SSH_FILEXFER_TYPE_BLOCK_DEVICE = 8; // v5
- public static final int SSH_FILEXFER_TYPE_FIFO = 9; // v5
-
- public static final int SSH_FXF_READ = 0x00000001;
- public static final int SSH_FXF_WRITE = 0x00000002;
- public static final int SSH_FXF_APPEND = 0x00000004;
- public static final int SSH_FXF_CREAT = 0x00000008;
- public static final int SSH_FXF_TRUNC = 0x00000010;
- public static final int SSH_FXF_EXCL = 0x00000020;
- public static final int SSH_FXF_TEXT = 0x00000040;
-
- public static final int SSH_FXF_ACCESS_DISPOSITION = 0x00000007;
- public static final int SSH_FXF_CREATE_NEW = 0x00000000;
- public static final int SSH_FXF_CREATE_TRUNCATE = 0x00000001;
- public static final int SSH_FXF_OPEN_EXISTING = 0x00000002;
- public static final int SSH_FXF_OPEN_OR_CREATE = 0x00000003;
- public static final int SSH_FXF_TRUNCATE_EXISTING = 0x00000004;
- public static final int SSH_FXF_APPEND_DATA = 0x00000008;
- public static final int SSH_FXF_APPEND_DATA_ATOMIC = 0x00000010;
- public static final int SSH_FXF_TEXT_MODE = 0x00000020;
- public static final int SSH_FXF_READ_LOCK = 0x00000040;
- public static final int SSH_FXF_WRITE_LOCK = 0x00000080;
- public static final int SSH_FXF_DELETE_LOCK = 0x00000100;
-
- public static final int SSH_FXP_RENAME_OVERWRITE = 0x00000001;
- public static final int SSH_FXP_RENAME_ATOMIC = 0x00000002;
- public static final int SSH_FXP_RENAME_NATIVE = 0x00000004;
-
- public static final int SSH_FXP_REALPATH_NO_CHECK = 0x00000001;
- public static final int SSH_FXP_REALPATH_STAT_IF = 0x00000002;
- public static final int SSH_FXP_REALPATH_STAT_ALWAYS = 0x00000003;
-
- public static final int SSH_FXF_RENAME_OVERWRITE = 0x00000001;
- public static final int SSH_FXF_RENAME_ATOMIC = 0x00000002;
- public static final int SSH_FXF_RENAME_NATIVE = 0x00000004;
-
- public static final int ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000;
- public static final int ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001;
- public static final int ACE4_SYSTEM_AUDIT_ACE_TYPE = 0x00000002;
- public static final int ACE4_SYSTEM_ALARM_ACE_TYPE = 0x00000003;
-
- public static final int ACE4_FILE_INHERIT_ACE = 0x00000001;
- public static final int ACE4_DIRECTORY_INHERIT_ACE = 0x00000002;
- public static final int ACE4_NO_PROPAGATE_INHERIT_ACE = 0x00000004;
- public static final int ACE4_INHERIT_ONLY_ACE = 0x00000008;
- public static final int ACE4_SUCCESSFUL_ACCESS_ACE_FLAG = 0x00000010;
- public static final int ACE4_FAILED_ACCESS_ACE_FLAG = 0x00000020;
- public static final int ACE4_IDENTIFIER_GROUP = 0x00000040;
-
- public static final int ACE4_READ_DATA = 0x00000001;
- public static final int ACE4_LIST_DIRECTORY = 0x00000001;
- public static final int ACE4_WRITE_DATA = 0x00000002;
- public static final int ACE4_ADD_FILE = 0x00000002;
- public static final int ACE4_APPEND_DATA = 0x00000004;
- public static final int ACE4_ADD_SUBDIRECTORY = 0x00000004;
- public static final int ACE4_READ_NAMED_ATTRS = 0x00000008;
- public static final int ACE4_WRITE_NAMED_ATTRS = 0x00000010;
- public static final int ACE4_EXECUTE = 0x00000020;
- public static final int ACE4_DELETE_CHILD = 0x00000040;
- public static final int ACE4_READ_ATTRIBUTES = 0x00000080;
- public static final int ACE4_WRITE_ATTRIBUTES = 0x00000100;
- public static final int ACE4_DELETE = 0x00010000;
- public static final int ACE4_READ_ACL = 0x00020000;
- public static final int ACE4_WRITE_ACL = 0x00040000;
- public static final int ACE4_WRITE_OWNER = 0x00080000;
- public static final int ACE4_SYNCHRONIZE = 0x00100000;
-
- public static final int S_IFMT = 0170000; // bitmask for the file type bitfields
- public static final int S_IFSOCK = 0140000; // socket
- public static final int S_IFLNK = 0120000; // symbolic link
- public static final int S_IFREG = 0100000; // regular file
- public static final int S_IFBLK = 0060000; // block device
- public static final int S_IFDIR = 0040000; // directory
- public static final int S_IFCHR = 0020000; // character device
- public static final int S_IFIFO = 0010000; // fifo
- public static final int S_ISUID = 0004000; // set UID bit
- public static final int S_ISGID = 0002000; // set GID bit
- public static final int S_ISVTX = 0001000; // sticky bit
- public static final int S_IRUSR = 0000400;
- public static final int S_IWUSR = 0000200;
- public static final int S_IXUSR = 0000100;
- public static final int S_IRGRP = 0000040;
- public static final int S_IWGRP = 0000020;
- public static final int S_IXGRP = 0000010;
- public static final int S_IROTH = 0000004;
- public static final int S_IWOTH = 0000002;
- public static final int S_IXOTH = 0000001;
-
- public static int SFTP_V3 = 3;
- public static int SFTP_V4 = 4;
- public static int SFTP_V5 = 5;
- public static int SFTP_V6 = 6;
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
new file mode 100644
index 0000000..f2f005d
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
@@ -0,0 +1,223 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.subsystem.sftp;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SftpConstants {
+ public static String SFTP_SUBSYSTEM_NAME = "sftp";
+
+ public static final int SSH_FXP_INIT = 1;
+ public static final int SSH_FXP_VERSION = 2;
+ public static final int SSH_FXP_OPEN = 3;
+ public static final int SSH_FXP_CLOSE = 4;
+ public static final int SSH_FXP_READ = 5;
+ public static final int SSH_FXP_WRITE = 6;
+ public static final int SSH_FXP_LSTAT = 7;
+ public static final int SSH_FXP_FSTAT = 8;
+ public static final int SSH_FXP_SETSTAT = 9;
+ public static final int SSH_FXP_FSETSTAT = 10;
+ public static final int SSH_FXP_OPENDIR = 11;
+ public static final int SSH_FXP_READDIR = 12;
+ public static final int SSH_FXP_REMOVE = 13;
+ public static final int SSH_FXP_MKDIR = 14;
+ public static final int SSH_FXP_RMDIR = 15;
+ public static final int SSH_FXP_REALPATH = 16;
+ public static final int SSH_FXP_STAT = 17;
+ public static final int SSH_FXP_RENAME = 18;
+ public static final int SSH_FXP_READLINK = 19;
+ public static final int SSH_FXP_SYMLINK = 20; // v3 -> v5
+ public static final int SSH_FXP_LINK = 21; // v6
+ public static final int SSH_FXP_BLOCK = 22; // v6
+ public static final int SSH_FXP_UNBLOCK = 23; // v6
+ public static final int SSH_FXP_STATUS = 101;
+ public static final int SSH_FXP_HANDLE = 102;
+ public static final int SSH_FXP_DATA = 103;
+ public static final int SSH_FXP_NAME = 104;
+ public static final int SSH_FXP_ATTRS = 105;
+ public static final int SSH_FXP_EXTENDED = 200;
+ public static final int SSH_FXP_EXTENDED_REPLY = 201;
+
+ public static final int SSH_FX_OK = 0;
+ public static final int SSH_FX_EOF = 1;
+ public static final int SSH_FX_NO_SUCH_FILE = 2;
+ public static final int SSH_FX_PERMISSION_DENIED = 3;
+ public static final int SSH_FX_FAILURE = 4;
+ public static final int SSH_FX_BAD_MESSAGE = 5;
+ public static final int SSH_FX_NO_CONNECTION = 6;
+ public static final int SSH_FX_CONNECTION_LOST = 7;
+ public static final int SSH_FX_OP_UNSUPPORTED = 8;
+ public static final int SSH_FX_INVALID_HANDLE = 9;
+ public static final int SSH_FX_NO_SUCH_PATH = 10;
+ public static final int SSH_FX_FILE_ALREADY_EXISTS = 11;
+ public static final int SSH_FX_WRITE_PROTECT = 12;
+ public static final int SSH_FX_NO_MEDIA = 13;
+ public static final int SSH_FX_NO_SPACE_ON_FILESYSTEM = 14;
+ public static final int SSH_FX_QUOTA_EXCEEDED = 15;
+ public static final int SSH_FX_UNKNOWN_PRINCIPLE = 16;
+ public static final int SSH_FX_LOCK_CONFLICT = 17;
+ public static final int SSH_FX_DIR_NOT_EMPTY = 18;
+ public static final int SSH_FX_NOT_A_DIRECTORY = 19;
+ public static final int SSH_FX_INVALID_FILENAME = 20;
+ public static final int SSH_FX_LINK_LOOP = 21;
+ public static final int SSH_FX_CANNOT_DELETE = 22;
+ public static final int SSH_FX_INVALID_PARAMETER = 23;
+ public static final int SSH_FX_FILE_IS_A_DIRECTORY = 24;
+ public static final int SSH_FX_BYTE_RANGE_LOCK_CONFLICT = 25;
+ public static final int SSH_FX_BYTE_RANGE_LOCK_REFUSED = 26;
+ public static final int SSH_FX_DELETE_PENDING = 27;
+ public static final int SSH_FX_FILE_CORRUPT = 28;
+ public static final int SSH_FX_OWNER_INVALID = 29;
+ public static final int SSH_FX_GROUP_INVALID = 30;
+ public static final int SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK = 31;
+
+ public static final int SSH_FILEXFER_ATTR_SIZE = 0x00000001;
+ public static final int SSH_FILEXFER_ATTR_UIDGID = 0x00000002;
+ public static final int SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004;
+ public static final int SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008; // v3 naming convention
+ public static final int SSH_FILEXFER_ATTR_ACCESSTIME = 0x00000008; // v4
+ public static final int SSH_FILEXFER_ATTR_CREATETIME = 0x00000010; // v4
+ public static final int SSH_FILEXFER_ATTR_MODIFYTIME = 0x00000020; // v4
+ public static final int SSH_FILEXFER_ATTR_ACL = 0x00000040; // v4
+ public static final int SSH_FILEXFER_ATTR_OWNERGROUP = 0x00000080; // v4
+ public static final int SSH_FILEXFER_ATTR_SUBSECOND_TIMES = 0x00000100; // v5
+ public static final int SSH_FILEXFER_ATTR_BITS = 0x00000200; // v5
+ public static final int SSH_FILEXFER_ATTR_ALLOCATION_SIZE = 0x00000400; // v6
+ public static final int SSH_FILEXFER_ATTR_TEXT_HINT = 0x00000800; // v6
+ public static final int SSH_FILEXFER_ATTR_MIME_TYPE = 0x00001000; // v6
+ public static final int SSH_FILEXFER_ATTR_LINK_COUNT = 0x00002000; // v6
+ public static final int SSH_FILEXFER_ATTR_UNTRANSLATED_NAME = 0x00004000; // v6
+ public static final int SSH_FILEXFER_ATTR_CTIME = 0x00008000; // v6
+ public static final int SSH_FILEXFER_ATTR_EXTENDED = 0x80000000;
+
+ public static final int SSH_FILEXFER_ATTR_ALL = 0x0000FFFF; // All attributes
+
+ public static final int SSH_FILEXFER_ATTR_FLAGS_READONLY = 0x00000001;
+ public static final int SSH_FILEXFER_ATTR_FLAGS_SYSTEM = 0x00000002;
+ public static final int SSH_FILEXFER_ATTR_FLAGS_HIDDEN = 0x00000004;
+ public static final int SSH_FILEXFER_ATTR_FLAGS_CASE_INSENSITIVE = 0x00000008;
+ public static final int SSH_FILEXFER_ATTR_FLAGS_ARCHIVE = 0x00000010;
+ public static final int SSH_FILEXFER_ATTR_FLAGS_ENCRYPTED = 0x00000020;
+ public static final int SSH_FILEXFER_ATTR_FLAGS_COMPRESSED = 0x00000040;
+ public static final int SSH_FILEXFER_ATTR_FLAGS_SPARSE = 0x00000080;
+ public static final int SSH_FILEXFER_ATTR_FLAGS_APPEND_ONLY = 0x00000100;
+ public static final int SSH_FILEXFER_ATTR_FLAGS_IMMUTABLE = 0x00000200;
+ public static final int SSH_FILEXFER_ATTR_FLAGS_SYNC = 0x00000400;
+
+ public static final int SSH_FILEXFER_TYPE_REGULAR = 1;
+ public static final int SSH_FILEXFER_TYPE_DIRECTORY = 2;
+ public static final int SSH_FILEXFER_TYPE_SYMLINK = 3;
+ public static final int SSH_FILEXFER_TYPE_SPECIAL = 4;
+ public static final int SSH_FILEXFER_TYPE_UNKNOWN = 5;
+ public static final int SSH_FILEXFER_TYPE_SOCKET = 6; // v5
+ public static final int SSH_FILEXFER_TYPE_CHAR_DEVICE = 7; // v5
+ public static final int SSH_FILEXFER_TYPE_BLOCK_DEVICE = 8; // v5
+ public static final int SSH_FILEXFER_TYPE_FIFO = 9; // v5
+
+ public static final int SSH_FXF_READ = 0x00000001;
+ public static final int SSH_FXF_WRITE = 0x00000002;
+ public static final int SSH_FXF_APPEND = 0x00000004;
+ public static final int SSH_FXF_CREAT = 0x00000008;
+ public static final int SSH_FXF_TRUNC = 0x00000010;
+ public static final int SSH_FXF_EXCL = 0x00000020;
+ public static final int SSH_FXF_TEXT = 0x00000040;
+
+ public static final int SSH_FXF_ACCESS_DISPOSITION = 0x00000007;
+ public static final int SSH_FXF_CREATE_NEW = 0x00000000;
+ public static final int SSH_FXF_CREATE_TRUNCATE = 0x00000001;
+ public static final int SSH_FXF_OPEN_EXISTING = 0x00000002;
+ public static final int SSH_FXF_OPEN_OR_CREATE = 0x00000003;
+ public static final int SSH_FXF_TRUNCATE_EXISTING = 0x00000004;
+ public static final int SSH_FXF_APPEND_DATA = 0x00000008;
+ public static final int SSH_FXF_APPEND_DATA_ATOMIC = 0x00000010;
+ public static final int SSH_FXF_TEXT_MODE = 0x00000020;
+ public static final int SSH_FXF_READ_LOCK = 0x00000040;
+ public static final int SSH_FXF_WRITE_LOCK = 0x00000080;
+ public static final int SSH_FXF_DELETE_LOCK = 0x00000100;
+
+ public static final int SSH_FXP_RENAME_OVERWRITE = 0x00000001;
+ public static final int SSH_FXP_RENAME_ATOMIC = 0x00000002;
+ public static final int SSH_FXP_RENAME_NATIVE = 0x00000004;
+
+ public static final int SSH_FXP_REALPATH_NO_CHECK = 0x00000001;
+ public static final int SSH_FXP_REALPATH_STAT_IF = 0x00000002;
+ public static final int SSH_FXP_REALPATH_STAT_ALWAYS = 0x00000003;
+
+ public static final int SSH_FXF_RENAME_OVERWRITE = 0x00000001;
+ public static final int SSH_FXF_RENAME_ATOMIC = 0x00000002;
+ public static final int SSH_FXF_RENAME_NATIVE = 0x00000004;
+
+ public static final int ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000;
+ public static final int ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001;
+ public static final int ACE4_SYSTEM_AUDIT_ACE_TYPE = 0x00000002;
+ public static final int ACE4_SYSTEM_ALARM_ACE_TYPE = 0x00000003;
+
+ public static final int ACE4_FILE_INHERIT_ACE = 0x00000001;
+ public static final int ACE4_DIRECTORY_INHERIT_ACE = 0x00000002;
+ public static final int ACE4_NO_PROPAGATE_INHERIT_ACE = 0x00000004;
+ public static final int ACE4_INHERIT_ONLY_ACE = 0x00000008;
+ public static final int ACE4_SUCCESSFUL_ACCESS_ACE_FLAG = 0x00000010;
+ public static final int ACE4_FAILED_ACCESS_ACE_FLAG = 0x00000020;
+ public static final int ACE4_IDENTIFIER_GROUP = 0x00000040;
+
+ public static final int ACE4_READ_DATA = 0x00000001;
+ public static final int ACE4_LIST_DIRECTORY = 0x00000001;
+ public static final int ACE4_WRITE_DATA = 0x00000002;
+ public static final int ACE4_ADD_FILE = 0x00000002;
+ public static final int ACE4_APPEND_DATA = 0x00000004;
+ public static final int ACE4_ADD_SUBDIRECTORY = 0x00000004;
+ public static final int ACE4_READ_NAMED_ATTRS = 0x00000008;
+ public static final int ACE4_WRITE_NAMED_ATTRS = 0x00000010;
+ public static final int ACE4_EXECUTE = 0x00000020;
+ public static final int ACE4_DELETE_CHILD = 0x00000040;
+ public static final int ACE4_READ_ATTRIBUTES = 0x00000080;
+ public static final int ACE4_WRITE_ATTRIBUTES = 0x00000100;
+ public static final int ACE4_DELETE = 0x00010000;
+ public static final int ACE4_READ_ACL = 0x00020000;
+ public static final int ACE4_WRITE_ACL = 0x00040000;
+ public static final int ACE4_WRITE_OWNER = 0x00080000;
+ public static final int ACE4_SYNCHRONIZE = 0x00100000;
+
+ public static final int S_IFMT = 0170000; // bitmask for the file type bitfields
+ public static final int S_IFSOCK = 0140000; // socket
+ public static final int S_IFLNK = 0120000; // symbolic link
+ public static final int S_IFREG = 0100000; // regular file
+ public static final int S_IFBLK = 0060000; // block device
+ public static final int S_IFDIR = 0040000; // directory
+ public static final int S_IFCHR = 0020000; // character device
+ public static final int S_IFIFO = 0010000; // fifo
+ public static final int S_ISUID = 0004000; // set UID bit
+ public static final int S_ISGID = 0002000; // set GID bit
+ public static final int S_ISVTX = 0001000; // sticky bit
+ public static final int S_IRUSR = 0000400;
+ public static final int S_IWUSR = 0000200;
+ public static final int S_IXUSR = 0000100;
+ public static final int S_IRGRP = 0000040;
+ public static final int S_IWGRP = 0000020;
+ public static final int S_IXGRP = 0000010;
+ public static final int S_IROTH = 0000004;
+ public static final int S_IWOTH = 0000002;
+ public static final int S_IXOTH = 0000001;
+
+ public static int SFTP_V3 = 3;
+ public static int SFTP_V4 = 4;
+ public static int SFTP_V5 = 5;
+ public static int SFTP_V6 = 6;
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
index 7afc506..74dd77f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java
@@ -312,4 +312,17 @@ public class IoUtils {
return null;
}
+
+ /**
+ * @param path The {@link Path} to check
+ * @param options The {@link LinkOption}s to use when checking if path is a directory
+ * @return The same input path if it is a directory
+ * @throws UnsupportedOperationException if input path not a directory
+ */
+ public static Path ensureDirectory(Path path, LinkOption ... options) {
+ if (!Files.isDirectory(path, options)) {
+ throw new UnsupportedOperationException("Not a directory: " + path);
+ }
+ return path;
+ }
}