http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java deleted file mode 100644 index 0d4f826..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileChannel.java +++ /dev/null @@ -1,389 +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.sftp; - -import static org.apache.sshd.common.sftp.SftpConstants.SSH_FX_LOCK_CONFLICT; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.MappedByteBuffer; -import java.nio.channels.AsynchronousCloseException; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; -import java.nio.channels.OverlappingFileLockException; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.apache.sshd.client.SftpException; -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.ValidateUtils; - -public class SftpFileChannel extends FileChannel { - - private final SftpPath p; - private final Collection<SftpClient.OpenMode> modes; - private final SftpClient sftp; - private final SftpClient.CloseableHandle handle; - private final Object lock = new Object(); - private volatile long pos; - private volatile Thread blockingThread; - - public SftpFileChannel(SftpPath p, Collection<SftpClient.OpenMode> modes) throws IOException { - this.p = ValidateUtils.checkNotNull(p, "No target path", GenericUtils.EMPTY_OBJECT_ARRAY); - this.modes = ValidateUtils.checkNotNull(modes, "No channel modes specified", GenericUtils.EMPTY_OBJECT_ARRAY); - - SftpFileSystem fs=p.getFileSystem(); - sftp = fs.getClient(); - handle = sftp.open(p.toString(), modes); - } - - @Override - public int read(ByteBuffer dst) throws IOException { - return (int) doRead(Collections.singletonList(dst), -1); - } - - @Override - public int read(ByteBuffer dst, long position) throws IOException { - if (position < 0) { - throw new IllegalArgumentException("read(" + p + ") illegal position to read from: " + position); - } - return (int) doRead(Collections.singletonList(dst), position); - } - - @Override - public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { - List<ByteBuffer> buffers = Arrays.asList(dsts).subList(offset, offset + length); - return doRead(buffers, -1); - } - - public static final Set<SftpClient.OpenMode> READ_MODES= - Collections.unmodifiableSet(EnumSet.of(SftpClient.OpenMode.Read)); - - protected long doRead(List<ByteBuffer> buffers, long position) throws IOException { - ensureOpen(READ_MODES); - synchronized (lock) { - boolean completed = false; - boolean eof = false; - long curPos = position >= 0 ? position : pos; - try { - long totalRead = 0; - beginBlocking(); - loop: - for (ByteBuffer buffer : buffers) { - while (buffer.remaining() > 0) { - ByteBuffer wrap = buffer; - if (!buffer.hasArray()) { - wrap = ByteBuffer.allocate(Math.min(8192, buffer.remaining())); - } - int read = sftp.read(handle, curPos, wrap.array(), wrap.arrayOffset() + wrap.position(), wrap.remaining()); - if (read > 0) { - if (wrap == buffer) { - wrap.position(wrap.position() + read); - } else { - buffer.put(wrap.array(), wrap.arrayOffset(), read); - } - curPos += read; - totalRead += read; - } else { - eof = read == -1; - break loop; - } - } - } - completed = true; - return totalRead > 0 ? totalRead : eof ? -1 : 0; - } finally { - if (position < 0) { - pos = curPos; - } - endBlocking(completed); - } - } - } - - @Override - public int write(ByteBuffer src) throws IOException { - return (int) doWrite(Collections.singletonList(src), -1); - } - - @Override - public int write(ByteBuffer src, long position) throws IOException { - if (position < 0) { - throw new IllegalArgumentException("write(" + p + ") illegal position to write to: " + position); - } - return (int) doWrite(Collections.singletonList(src), position); - } - - @Override - public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { - List<ByteBuffer> buffers = Arrays.asList(srcs).subList(offset, offset + length); - return doWrite(buffers, -1); - } - - public static final Set<SftpClient.OpenMode> WRITE_MODES= - Collections.unmodifiableSet( - EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Append, SftpClient.OpenMode.Create, SftpClient.OpenMode.Truncate)); - - protected long doWrite(List<ByteBuffer> buffers, long position) throws IOException { - ensureOpen(WRITE_MODES); - synchronized (lock) { - boolean completed = false; - long curPos = position >= 0 ? position : pos; - try { - long totalWritten = 0; - beginBlocking(); - for (ByteBuffer buffer : buffers) { - while (buffer.remaining() > 0) { - ByteBuffer wrap = buffer; - if (!buffer.hasArray()) { - wrap = ByteBuffer.allocate(Math.min(8192, buffer.remaining())); - buffer.get(wrap.array(), wrap.arrayOffset(), wrap.remaining()); - } - int written = wrap.remaining(); - sftp.write(handle, curPos, wrap.array(), wrap.arrayOffset() + wrap.position(), written); - if (wrap == buffer) { - wrap.position(wrap.position() + written); - } - curPos += written; - totalWritten += written; - } - } - completed = true; - return totalWritten; - } finally { - if (position < 0) { - pos = curPos; - } - endBlocking(completed); - } - } - } - - @Override - public long position() throws IOException { - ensureOpen(Collections.<SftpClient.OpenMode>emptySet()); - return pos; - } - - @Override - public FileChannel position(long newPosition) throws IOException { - if (newPosition < 0) { - throw new IllegalArgumentException("position(" + p + ") illegal file channel position: " + newPosition); - } - - ensureOpen(Collections.<SftpClient.OpenMode>emptySet()); - synchronized (lock) { - pos = newPosition; - return this; - } - } - - @Override - public long size() throws IOException { - ensureOpen(Collections.<SftpClient.OpenMode>emptySet()); - return sftp.stat(handle).size; - } - - @Override - public FileChannel truncate(long size) throws IOException { - ensureOpen(Collections.<SftpClient.OpenMode>emptySet()); - sftp.setStat(handle, new SftpClient.Attributes().size(size)); - return this; - } - - @Override - public void force(boolean metaData) throws IOException { - ensureOpen(Collections.<SftpClient.OpenMode>emptySet()); - } - - @Override - public long transferTo(long position, long count, WritableByteChannel target) throws IOException { - if ((position < 0) || (count < 0)) { - throw new IllegalArgumentException("transferTo(" + p + ") illegal position (" + position + ") or count (" + count + ")"); - } - ensureOpen(READ_MODES); - synchronized (lock) { - boolean completed = false; - boolean eof = false; - long curPos = position; - try { - beginBlocking(); - - int bufSize = (int) Math.min(count, 32768); - byte[] buffer = new byte[bufSize]; - long totalRead = 0L; - while (totalRead < count) { - int read = sftp.read(handle, curPos, buffer, 0, buffer.length); - if (read > 0) { - ByteBuffer wrap = ByteBuffer.wrap(buffer); - while (wrap.remaining() > 0) { - target.write(wrap); - } - curPos += read; - totalRead += read; - } else { - eof = read == -1; - } - } - completed = true; - return totalRead > 0 ? totalRead : eof ? -1 : 0; - } finally { - endBlocking(completed); - } - } - } - - @Override - public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException { - if ((position < 0) || (count < 0)) { - throw new IllegalArgumentException("transferFrom(" + p + ") illegal position (" + position + ") or count (" + count + ")"); - } - ensureOpen(WRITE_MODES); - - synchronized(lock) { - boolean completed = false; - long curPos = position >= 0 ? position : pos; - try { - long totalRead = 0; - beginBlocking(); - - byte[] buffer = new byte[32768]; - while (totalRead < count) { - ByteBuffer wrap = ByteBuffer.wrap(buffer, 0, (int) Math.min(buffer.length, count - totalRead)); - int read = src.read(wrap); - if (read > 0) { - sftp.write(handle, curPos, buffer, 0, read); - curPos += read; - totalRead += read; - } else { - break; - } - } - completed = true; - return totalRead; - } finally { - endBlocking(completed); - } - } - } - - @Override - public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException { - throw new UnsupportedOperationException("map(" + p + ")[" + mode + "," + position + "," + size + "] N/A"); - } - - @Override - public FileLock lock(long position, long size, boolean shared) throws IOException { - return tryLock(position, size, shared); - } - - @Override - public FileLock tryLock(final long position, final long size, boolean shared) throws IOException { - ensureOpen(Collections.<SftpClient.OpenMode>emptySet()); - - try { - sftp.lock(handle, position, size, 0); - } catch (SftpException e) { - if (e.getStatus() == SSH_FX_LOCK_CONFLICT) { - throw new OverlappingFileLockException(); - } - throw e; - } - - return new FileLock(this, position, size, shared) { - private final AtomicBoolean valid = new AtomicBoolean(true); - - @Override - public boolean isValid() { - return acquiredBy().isOpen() && valid.get(); - } - - @SuppressWarnings("synthetic-access") - @Override - public void release() throws IOException { - if (valid.compareAndSet(true, false)) { - sftp.unlock(handle, position, size); - } - } - }; - } - - @Override - protected void implCloseChannel() throws IOException { - try { - final Thread thread = blockingThread; - if (thread != null) { - thread.interrupt(); - } - } finally { - try { - handle.close(); - } finally { - sftp.close(); - } - } - } - - private void beginBlocking() { - begin(); - blockingThread = Thread.currentThread(); - } - - private void endBlocking(boolean completed) throws AsynchronousCloseException { - blockingThread = null; - end(completed); - } - - /** - * Checks that the channel is open and that its current mode contains - * at least one of the required ones - * @param reqModes The required modes - ignored if {@code null}/empty - * @throws IOException If channel not open or the required modes are not - * satisfied - */ - private void ensureOpen(Collection<SftpClient.OpenMode> reqModes) throws IOException { - if (!isOpen()) { - throw new ClosedChannelException(); - } - - if (GenericUtils.size(reqModes) > 0) { - for (SftpClient.OpenMode m : reqModes) { - if (this.modes.contains(m)) { - return; - } - } - - throw new IOException("ensureOpen(" + p + ") current channel modes (" + this.modes + ") do contain any of the required: " + reqModes); - } - } - - @Override - public String toString() { - return Objects.toString(p); - } -}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java deleted file mode 100644 index 026d13c..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystem.java +++ /dev/null @@ -1,384 +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.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; - } - - @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 { - return delegate.open(path, options); - } - - @Override - public void close(Handle handle) throws IOException { - delegate.close(handle); - } - - @Override - public void remove(String path) throws IOException { - delegate.remove(path); - } - - @Override - public void rename(String oldPath, String newPath, Collection<CopyMode> options) throws IOException { - delegate.rename(oldPath, newPath, options); - } - - @Override - public int read(Handle handle, long fileOffset, byte[] dst, int dstoff, int len) throws IOException { - return delegate.read(handle, fileOffset, dst, dstoff, len); - } - - @Override - public void write(Handle handle, long fileOffset, byte[] src, int srcoff, int len) throws IOException { - delegate.write(handle, fileOffset, src, srcoff, len); - } - - @Override - public void mkdir(String path) throws IOException { - delegate.mkdir(path); - } - - @Override - public void rmdir(String path) throws IOException { - delegate.rmdir(path); - } - - @Override - public CloseableHandle openDir(String path) throws IOException { - return delegate.openDir(path); - } - - @Override - public DirEntry[] readDir(Handle handle) throws IOException { - return delegate.readDir(handle); - } - - @Override - public String canonicalPath(String canonical) throws IOException { - return delegate.canonicalPath(canonical); - } - - @Override - public Attributes stat(String path) throws IOException { - return delegate.stat(path); - } - - @Override - public Attributes lstat(String path) throws IOException { - return delegate.lstat(path); - } - - @Override - public Attributes stat(Handle handle) throws IOException { - return delegate.stat(handle); - } - - @Override - public void setStat(String path, Attributes attributes) throws IOException { - delegate.setStat(path, attributes); - } - - @Override - public void setStat(Handle handle, Attributes attributes) throws IOException { - delegate.setStat(handle, attributes); - } - - @Override - public String readLink(String path) throws IOException { - return delegate.readLink(path); - } - - @Override - public void symLink(String linkPath, String targetPath) throws IOException { - delegate.symLink(linkPath, targetPath); - } - - @Override - public Iterable<DirEntry> readDir(String path) throws IOException { - 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 { - 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 { - return delegate.write(path, bufferSize, mode); - } - - @Override - public void link(String linkPath, String targetPath, boolean symbolic) throws IOException { - delegate.link(linkPath, targetPath, symbolic); - } - - @Override - public void lock(Handle handle, long offset, long length, int mask) throws IOException { - delegate.lock(handle, offset, length, mask); - } - - @Override - public void unlock(Handle handle, long offset, long length) throws IOException { - 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/sftp/SftpFileSystemProvider.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java deleted file mode 100644 index 2ac72b1..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java +++ /dev/null @@ -1,892 +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.sftp; - -import static org.apache.sshd.common.sftp.SftpConstants.SFTP_V3; -import static org.apache.sshd.common.sftp.SftpConstants.S_IRGRP; -import static org.apache.sshd.common.sftp.SftpConstants.S_IROTH; -import static org.apache.sshd.common.sftp.SftpConstants.S_IRUSR; -import static org.apache.sshd.common.sftp.SftpConstants.S_IWGRP; -import static org.apache.sshd.common.sftp.SftpConstants.S_IWOTH; -import static org.apache.sshd.common.sftp.SftpConstants.S_IWUSR; -import static org.apache.sshd.common.sftp.SftpConstants.S_IXGRP; -import static org.apache.sshd.common.sftp.SftpConstants.S_IXOTH; -import static org.apache.sshd.common.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.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.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/sftp/SftpPath.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpPath.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpPath.java deleted file mode 100644 index d4e0b0b..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpPath.java +++ /dev/null @@ -1,46 +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.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/client/subsystem/SubsystemClient.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/SubsystemClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/SubsystemClient.java new file mode 100644 index 0000000..7f86bd7 --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/SubsystemClient.java @@ -0,0 +1,31 @@ +/* + * 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; + +import java.nio.channels.Channel; + +import org.apache.sshd.common.NamedResource; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public interface SubsystemClient extends NamedResource, Channel { + // marker interface for subsystems +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java new file mode 100644 index 0000000..fc7a02b --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java @@ -0,0 +1,130 @@ +/* + * 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.util.Collection; +import java.util.Collections; +import java.util.EnumSet; + +import org.apache.sshd.common.subsystem.sftp.SftpConstants; +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.common.util.logging.AbstractLoggingBean; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public abstract class AbstractSftpClient extends AbstractLoggingBean implements SftpClient { + protected AbstractSftpClient() { + super(); + } + + @Override + public String getName() { + return SftpConstants.SFTP_SUBSYSTEM_NAME; + } + + @Override + public CloseableHandle open(String path) throws IOException { + return open(path, Collections.<OpenMode>emptySet()); + } + + @Override + public CloseableHandle open(String path, OpenMode ... options) throws IOException { + return open(path, GenericUtils.of(options)); + } + + @Override + public void rename(String oldPath, String newPath) throws IOException { + rename(oldPath, newPath, Collections.<CopyMode>emptySet()); + } + + @Override + public void rename(String oldPath, String newPath, CopyMode ... options) throws IOException { + rename(oldPath, newPath, GenericUtils.of(options)); + } + + @Override + public InputStream read(String path) throws IOException { + return read(path, DEFAULT_READ_BUFFER_SIZE); + } + + @Override + public InputStream read(String path, int bufferSize) throws IOException { + return read(path, bufferSize, EnumSet.of(OpenMode.Read)); + } + + @Override + public InputStream read(String path, OpenMode ... mode) throws IOException { + return read(path, DEFAULT_READ_BUFFER_SIZE, mode); + } + + @Override + public InputStream read(String path, int bufferSize, OpenMode ... mode) throws IOException { + return read(path, bufferSize, GenericUtils.of(mode)); + } + + @Override + public InputStream read(String path, Collection<OpenMode> mode) throws IOException { + return read(path, DEFAULT_READ_BUFFER_SIZE, mode); + } + + @Override + public int read(Handle handle, long fileOffset, byte[] dst) throws IOException { + return read(handle, fileOffset, dst, 0, dst.length); + } + + @Override + public OutputStream write(String path) throws IOException { + return write(path, DEFAULT_WRITE_BUFFER_SIZE); + } + + @Override + public OutputStream write(String path, int bufferSize) throws IOException { + return write(path, bufferSize, EnumSet.of(OpenMode.Write, OpenMode.Create, OpenMode.Truncate)); + } + + @Override + public OutputStream write(String path, OpenMode ... mode) throws IOException { + return write(path, DEFAULT_WRITE_BUFFER_SIZE, mode); + } + + @Override + public OutputStream write(String path, Collection<OpenMode> mode) throws IOException { + return write(path, DEFAULT_WRITE_BUFFER_SIZE, mode); + } + + @Override + public OutputStream write(String path, int bufferSize, OpenMode ... mode) throws IOException { + return write(path, bufferSize, GenericUtils.of(mode)); + } + + @Override + public void write(Handle handle, long fileOffset, byte[] src) throws IOException { + write(handle, fileOffset, src, 0, src.length); + } + + @Override + public void symLink(String linkPath, String targetPath) throws IOException { + link(linkPath, targetPath, true); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a6e2bf9e/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultCloseableHandle.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultCloseableHandle.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultCloseableHandle.java new file mode 100644 index 0000000..868ff10 --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultCloseableHandle.java @@ -0,0 +1,55 @@ +/* + * 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.concurrent.atomic.AtomicBoolean; + +import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle; +import org.apache.sshd.common.util.ValidateUtils; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class DefaultCloseableHandle extends CloseableHandle { + private final AtomicBoolean open = new AtomicBoolean(true); + private final SftpClient client; + + public DefaultCloseableHandle(SftpClient client, String id) { + super(id); + this.client = ValidateUtils.checkNotNull(client, "No client for id=%s", id); + } + + public final SftpClient getSftpClient() { + return client; + } + + @Override + public boolean isOpen() { + return open.get(); + } + + @Override + public void close() throws IOException { + if (open.getAndSet(false)) { + client.close(this); + } + } +}
